From 000290c4c923cc1473e21b4bdbdc0c42765ef7dd Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot Date: Sun, 8 Oct 2023 08:06:18 +0000 Subject: [PATCH 01/24] docs: Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7aa4019ed87a..4aeefc08cd2e 100644 --- a/README.md +++ b/README.md @@ -288,7 +288,7 @@ The following companies, organizations, and individuals support ESLint's ongoing

Platinum Sponsors

Chrome Frameworks Fund Automattic

Gold Sponsors

Salesforce Airbnb

Silver Sponsors

-

Liftoff Siemens American Express

Bronze Sponsors

+

Liftoff American Express

Bronze Sponsors

ThemeIsle Anagram Solver Icons8 Discord Transloadit Ignition HeroCoders QuickBooks Tool hub

From 1000187e00949332babcee4d37d46c96a6a554a8 Mon Sep 17 00:00:00 2001 From: Francesco Trotta Date: Sun, 8 Oct 2023 15:39:25 +0200 Subject: [PATCH 02/24] docs: Fix examples in `unicode-bom` (#17631) Fix examples in `unicode-bom` docs --- docs/src/rules/unicode-bom.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/src/rules/unicode-bom.md b/docs/src/rules/unicode-bom.md index 1bae51ce64e1..6fcde6c3304e 100644 --- a/docs/src/rules/unicode-bom.md +++ b/docs/src/rules/unicode-bom.md @@ -31,9 +31,10 @@ Example of **correct** code for this rule with the `"always"` option: ::: correct ```js +// U+FEFF at the beginning + /*eslint unicode-bom: ["error", "always"]*/ -U+FEFF var abc; ``` @@ -70,9 +71,10 @@ Example of **incorrect** code for this rule with the `"never"` option: ::: incorrect ```js +// U+FEFF at the beginning + /*eslint unicode-bom: ["error", "never"]*/ -U+FEFF var abc; ``` From 6b8acfb770589f3941df41c3910d3b8ffc3e1e45 Mon Sep 17 00:00:00 2001 From: Francesco Trotta Date: Mon, 9 Oct 2023 09:15:58 +0200 Subject: [PATCH 03/24] docs: Add real whitespace to `no-trailing-spaces` examples (#17630) * Add real whitespace to `no-trailing-spaces` examples * Fix space-only line --- docs/src/rules/no-trailing-spaces.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/docs/src/rules/no-trailing-spaces.md b/docs/src/rules/no-trailing-spaces.md index fba4f7df9a21..61aec1fcf4aa 100644 --- a/docs/src/rules/no-trailing-spaces.md +++ b/docs/src/rules/no-trailing-spaces.md @@ -18,9 +18,9 @@ Examples of **incorrect** code for this rule: ```js /*eslint no-trailing-spaces: "error"*/ -var foo = 0;//••••• -var baz = 5;//•• -//••••• +var foo = 0;/* trailing whitespace */ +var baz = 5;/* trailing whitespace */ +/* trailing whitespace */ ``` ::: @@ -58,7 +58,8 @@ Examples of **correct** code for this rule with the `{ "skipBlankLines": true }` var foo = 0; var baz = 5; -//••••• +// ↓ a line with whitespace only ↓ + ``` ::: @@ -72,12 +73,12 @@ Examples of **correct** code for this rule with the `{ "ignoreComments": true }` ```js /*eslint no-trailing-spaces: ["error", { "ignoreComments": true }]*/ -//foo• -//••••• +// ↓ these comments have trailing whitespace → +// /** - *•baz - *•• - *•bar + * baz + * + * bar */ ``` From 392305bf4797e3ebc696dfca48bd874741fca845 Mon Sep 17 00:00:00 2001 From: Francesco Trotta Date: Mon, 9 Oct 2023 10:55:39 +0200 Subject: [PATCH 04/24] docs: Update `no-irregular-whitespace` and fix examples (#17626) Update `no-irregular-whitespace` docs --- docs/src/_data/further_reading_links.json | 7 +++++++ docs/src/rules/no-irregular-whitespace.md | 19 +++++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/docs/src/_data/further_reading_links.json b/docs/src/_data/further_reading_links.json index 045bd4faf628..a33ce6c0b3bb 100644 --- a/docs/src/_data/further_reading_links.json +++ b/docs/src/_data/further_reading_links.json @@ -740,5 +740,12 @@ "logo": "https://v8.dev/favicon.ico", "title": "RegExp v flag with set notation and properties of strings · V8", "description": "The new RegExp `v` flag enables `unicodeSets` mode, unlocking support for extended character classes, including Unicode properties of strings, set notation, and improved case-insensitive matching." + }, + "https://codepoints.net/U+1680": { + "domain": "codepoints.net", + "url": "https://codepoints.net/U+1680", + "logo": "https://codepoints.net/favicon.ico", + "title": "U+1680 OGHAM SPACE MARK:   – Unicode – Codepoints", + "description": " , codepoint U+1680 OGHAM SPACE MARK in Unicode, is located in the block “Ogham”. It belongs to the Ogham script and is a Space Separator." } } \ No newline at end of file diff --git a/docs/src/rules/no-irregular-whitespace.md b/docs/src/rules/no-irregular-whitespace.md index c0683645628e..4118defe6311 100644 --- a/docs/src/rules/no-irregular-whitespace.md +++ b/docs/src/rules/no-irregular-whitespace.md @@ -4,6 +4,7 @@ rule_type: problem further_reading: - https://es5.github.io/#x7.2 - https://web.archive.org/web/20200414142829/http://timelessrepo.com/json-isnt-a-javascript-subset +- https://codepoints.net/U+1680 --- @@ -16,11 +17,17 @@ A simple fix for this problem could be to rewrite the offending line from scratc Known issues these spaces cause: +* Ogham Space Mark + * Is a valid token separator, but is rendered as a visible glyph in most typefaces, which may be misleading in source code. +* Mongolian Vowel Separator + * Is no longer considered a space separator since Unicode 6.3. It will result in a syntax error in current parsers when used in place of a regular token separator. +* Line Separator and Paragraph Separator + * These have always been valid whitespace characters and line terminators, but were considered illegal in string literals prior to ECMAScript 2019. * Zero Width Space - * Is NOT considered a separator for tokens and is often parsed as an `Unexpected token ILLEGAL` - * Is NOT shown in modern browsers making code repository software expected to resolve the visualization -* Line Separator - * Is NOT a valid character within JSON which would cause parse errors + * Is NOT considered a separator for tokens and is often parsed as an `Unexpected token ILLEGAL`. + * Is NOT shown in modern browsers making code repository software expected to resolve the visualization. + +In JSON, none of the characters listed as irregular whitespace by this rule may appear outside of a string. ## Rule Details @@ -86,7 +93,7 @@ var thing = function /**/(){ return 'test'; } -var thing = function᠎/**/(){ +var thing = function /**/(){ return 'test'; } @@ -204,7 +211,7 @@ Examples of additional **correct** code for this rule with the `{ "skipJSXText": /*eslint-env es6*/ function Thing() { - return
text in JSX
; + return
text in JSX
; // before `JSX` } ``` From fab249ae6addac2ee18cd81cee80916010bb469e Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot Date: Tue, 10 Oct 2023 08:07:17 +0000 Subject: [PATCH 05/24] docs: Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4aeefc08cd2e..dc500d03d6ae 100644 --- a/README.md +++ b/README.md @@ -289,7 +289,7 @@ The following companies, organizations, and individuals support ESLint's ongoing

Chrome Frameworks Fund Automattic

Gold Sponsors

Salesforce Airbnb

Silver Sponsors

Liftoff American Express

Bronze Sponsors

-

ThemeIsle Anagram Solver Icons8 Discord Transloadit Ignition HeroCoders QuickBooks Tool hub

+

bulkfollow ThemeIsle Anagram Solver Icons8 Discord Transloadit Ignition HeroCoders QuickBooks Tool hub

## Technology Sponsors From ff8e4bf327b5c92b0623b0fc5f8f101954f785db Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot Date: Wed, 11 Oct 2023 08:07:17 +0000 Subject: [PATCH 06/24] docs: Update README --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index dc500d03d6ae..97f165daaa6a 100644 --- a/README.md +++ b/README.md @@ -254,6 +254,11 @@ Francesco Trotta
Yosuke Ota + + +
+Tanuj Kanti +
### Website Team From 9fafe450c31ed9b6bdd9dcd6c115255943b8c1c2 Mon Sep 17 00:00:00 2001 From: Percy Ma Date: Wed, 11 Oct 2023 07:04:32 -0500 Subject: [PATCH 07/24] docs: upgrade to 11ty 2.0 (#17632) * docs: upgrade to 11ty 2.0 * docs: fix broken links * chore: clean * Update Makefile.js Co-authored-by: Milos Djermanovic * chore: change filename --------- Co-authored-by: Milos Djermanovic --- Makefile.js | 16 +- conf/rule-type-list.json | 58 +- docs/.eleventy.js | 22 +- docs/package.json | 8 +- docs/src/_data/rules.json | 4057 ++++++++++++++-------------- docs/src/_data/rules_categories.js | 26 + docs/src/pages/rules.md | 25 +- 7 files changed, 2093 insertions(+), 2119 deletions(-) create mode 100644 docs/src/_data/rules_categories.js diff --git a/Makefile.js b/Makefile.js index 7978369c0b05..8a963388ebea 100644 --- a/Makefile.js +++ b/Makefile.js @@ -214,7 +214,7 @@ function generateRuleIndexPage() { }; if (rule.meta.deprecated) { - ruleTypesData.deprecated.rules.push({ + ruleTypesData.deprecated.push({ name: basename, replacedBy: rule.meta.replacedBy || [] }); @@ -226,22 +226,18 @@ function generateRuleIndexPage() { fixable: !!rule.meta.fixable, hasSuggestions: !!rule.meta.hasSuggestions }, - ruleType = ruleTypesData.types.find(c => c.name === rule.meta.type); + ruleType = ruleTypesData.types[rule.meta.type]; - if (!ruleType.rules) { - ruleType.rules = []; - } - - ruleType.rules.push(output); + ruleType.push(output); } }); - // `.rules` will be `undefined` if all rules in category are deprecated. - ruleTypesData.types = ruleTypesData.types.filter(ruleType => !!ruleType.rules); + ruleTypesData.types = Object.fromEntries( + Object.entries(ruleTypesData.types).filter(([, value]) => value && value.length > 0) + ); JSON.stringify(ruleTypesData, null, 4).to(docsSiteOutputFile); JSON.stringify(meta, null, 4).to(docsSiteMetaOutputFile); - } /** diff --git a/conf/rule-type-list.json b/conf/rule-type-list.json index d5823acc898e..6ca730f34f02 100644 --- a/conf/rule-type-list.json +++ b/conf/rule-type-list.json @@ -1,36 +1,28 @@ { - "types": [ - { "name": "problem", "displayName": "Possible Problems", "description": "These rules relate to possible logic errors in code:" }, - { "name": "suggestion", "displayName": "Suggestions", "description": "These rules suggest alternate ways of doing things:" }, - { "name": "layout", "displayName": "Layout & Formatting", "description": "These rules care about how the code looks rather than how it executes:" } - ], - "deprecated": { - "name": "Deprecated", - "description": "These rules have been deprecated in accordance with the deprecation policy, and replaced by newer rules:", - "rules": [] + "types": { + "problem": [], + "suggestion": [], + "layout": [] }, - "removed": { - "name": "Removed", - "description": "These rules from older versions of ESLint (before the deprecation policy existed) have been replaced by newer rules:", - "rules": [ - { "removed": "generator-star", "replacedBy": ["generator-star-spacing"] }, - { "removed": "global-strict", "replacedBy": ["strict"] }, - { "removed": "no-arrow-condition", "replacedBy": ["no-confusing-arrow", "no-constant-condition"] }, - { "removed": "no-comma-dangle", "replacedBy": ["comma-dangle"] }, - { "removed": "no-empty-class", "replacedBy": ["no-empty-character-class"] }, - { "removed": "no-empty-label", "replacedBy": ["no-labels"] }, - { "removed": "no-extra-strict", "replacedBy": ["strict"] }, - { "removed": "no-reserved-keys", "replacedBy": ["quote-props"] }, - { "removed": "no-space-before-semi", "replacedBy": ["semi-spacing"] }, - { "removed": "no-wrap-func", "replacedBy": ["no-extra-parens"] }, - { "removed": "space-after-function-name", "replacedBy": ["space-before-function-paren"] }, - { "removed": "space-after-keywords", "replacedBy": ["keyword-spacing"] }, - { "removed": "space-before-function-parentheses", "replacedBy": ["space-before-function-paren"] }, - { "removed": "space-before-keywords", "replacedBy": ["keyword-spacing"] }, - { "removed": "space-in-brackets", "replacedBy": ["object-curly-spacing", "array-bracket-spacing"] }, - { "removed": "space-return-throw-case", "replacedBy": ["keyword-spacing"] }, - { "removed": "space-unary-word-ops", "replacedBy": ["space-unary-ops"] }, - { "removed": "spaced-line-comment", "replacedBy": ["spaced-comment"] } - ] - } + "deprecated": [], + "removed": [ + { "removed": "generator-star", "replacedBy": ["generator-star-spacing"] }, + { "removed": "global-strict", "replacedBy": ["strict"] }, + { "removed": "no-arrow-condition", "replacedBy": ["no-confusing-arrow", "no-constant-condition"] }, + { "removed": "no-comma-dangle", "replacedBy": ["comma-dangle"] }, + { "removed": "no-empty-class", "replacedBy": ["no-empty-character-class"] }, + { "removed": "no-empty-label", "replacedBy": ["no-labels"] }, + { "removed": "no-extra-strict", "replacedBy": ["strict"] }, + { "removed": "no-reserved-keys", "replacedBy": ["quote-props"] }, + { "removed": "no-space-before-semi", "replacedBy": ["semi-spacing"] }, + { "removed": "no-wrap-func", "replacedBy": ["no-extra-parens"] }, + { "removed": "space-after-function-name", "replacedBy": ["space-before-function-paren"] }, + { "removed": "space-after-keywords", "replacedBy": ["keyword-spacing"] }, + { "removed": "space-before-function-parentheses", "replacedBy": ["space-before-function-paren"] }, + { "removed": "space-before-keywords", "replacedBy": ["keyword-spacing"] }, + { "removed": "space-in-brackets", "replacedBy": ["object-curly-spacing", "array-bracket-spacing"] }, + { "removed": "space-return-throw-case", "replacedBy": ["keyword-spacing"] }, + { "removed": "space-unary-word-ops", "replacedBy": ["space-unary-ops"] }, + { "removed": "spaced-line-comment", "replacedBy": ["spaced-comment"] } + ] } diff --git a/docs/.eleventy.js b/docs/.eleventy.js index 68c6604cf8d0..a2a0b71c17bc 100644 --- a/docs/.eleventy.js +++ b/docs/.eleventy.js @@ -54,6 +54,7 @@ module.exports = function(eleventyConfig) { eleventyConfig.addGlobalData("GIT_BRANCH", process.env.BRANCH); eleventyConfig.addGlobalData("HEAD", process.env.BRANCH === "main"); eleventyConfig.addGlobalData("NOINDEX", process.env.BRANCH !== "latest"); + eleventyConfig.addGlobalData("PATH_PREFIX", pathPrefix); eleventyConfig.addDataExtension("yml", contents => yaml.load(contents)); //------------------------------------------------------------------------------ @@ -487,25 +488,6 @@ module.exports = function(eleventyConfig) { // Settings //------------------------------------------------------------------------------ - /* - * When we run `eleventy --serve`, Eleventy 1.x uses browser-sync to serve the content. - * By default, browser-sync (more precisely, underlying serve-static) will not serve - * `foo/bar.html` when we request `foo/bar`. Thus, we need to rewrite URLs to append `.html` - * so that pretty links without `.html` can work in a local development environment. - * - * There's no need to rewrite URLs that end with `/`, because that already works well - * (server will return the content of `index.html` in the directory). - * URLs with a file extension, like main.css, main.js, sitemap.xml, etc. should not be rewritten - */ - eleventyConfig.setBrowserSyncConfig({ - middleware(req, res, next) { - if (!/(?:\.[a-zA-Z][^/]*|\/)$/u.test(req.url)) { - req.url += ".html"; - } - return next(); - } - }); - /* * Generate the sitemap only in certain contexts to prevent unwanted discovery of sitemaps that * contain URLs we'd prefer not to appear in search results (URLs in sitemaps are considered important). @@ -525,14 +507,12 @@ module.exports = function(eleventyConfig) { eleventyConfig.ignores.add("src/static/sitemap.njk"); // ... then don't generate the sitemap. } - return { passthroughFileCopy: true, pathPrefix, markdownTemplateEngine: "njk", - dataTemplateEngine: "njk", htmlTemplateEngine: "njk", dir: { diff --git a/docs/package.json b/docs/package.json index 1b2019bb4cb6..d24e203338c3 100644 --- a/docs/package.json +++ b/docs/package.json @@ -23,11 +23,11 @@ "start": "npm-run-all build:sass build:postcss --parallel *:*:watch" }, "devDependencies": { - "@11ty/eleventy": "^1.0.1", - "@11ty/eleventy-img": "^1.0.0", - "@11ty/eleventy-navigation": "^0.3.2", + "@11ty/eleventy": "^2.0.1", + "@11ty/eleventy-img": "^3.1.1", + "@11ty/eleventy-navigation": "^0.3.5", "@11ty/eleventy-plugin-rss": "^1.1.1", - "@11ty/eleventy-plugin-syntaxhighlight": "^3.1.2", + "@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0", "@munter/tap-render": "^0.2.0", "@types/markdown-it": "^12.2.3", "algoliasearch": "^4.12.1", diff --git a/docs/src/_data/rules.json b/docs/src/_data/rules.json index 2ac3df8c535c..3565b9ca65e7 100644 --- a/docs/src/_data/rules.json +++ b/docs/src/_data/rules.json @@ -1,2129 +1,2106 @@ { - "types": [ - { - "name": "problem", - "displayName": "Possible Problems", - "description": "These rules relate to possible logic errors in code:", - "rules": [ - { - "name": "array-callback-return", - "description": "Enforce `return` statements in callbacks of array methods", - "recommended": false, - "fixable": false, - "hasSuggestions": true - }, - { - "name": "constructor-super", - "description": "Require `super()` calls in constructors", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "for-direction", - "description": "Enforce \"for\" loop update clause moving the counter in the right direction", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "getter-return", - "description": "Enforce `return` statements in getters", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-async-promise-executor", - "description": "Disallow using an async function as a Promise executor", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-await-in-loop", - "description": "Disallow `await` inside of loops", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-class-assign", - "description": "Disallow reassigning class members", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-compare-neg-zero", - "description": "Disallow comparing against -0", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-cond-assign", - "description": "Disallow assignment operators in conditional expressions", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-const-assign", - "description": "Disallow reassigning `const` variables", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-constant-binary-expression", - "description": "Disallow expressions where the operation doesn't affect the value", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-constant-condition", - "description": "Disallow constant expressions in conditions", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-constructor-return", - "description": "Disallow returning value from constructor", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-control-regex", - "description": "Disallow control characters in regular expressions", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-debugger", - "description": "Disallow the use of `debugger`", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-dupe-args", - "description": "Disallow duplicate arguments in `function` definitions", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-dupe-class-members", - "description": "Disallow duplicate class members", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-dupe-else-if", - "description": "Disallow duplicate conditions in if-else-if chains", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-dupe-keys", - "description": "Disallow duplicate keys in object literals", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-duplicate-case", - "description": "Disallow duplicate case labels", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-duplicate-imports", - "description": "Disallow duplicate module imports", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-empty-character-class", - "description": "Disallow empty character classes in regular expressions", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-empty-pattern", - "description": "Disallow empty destructuring patterns", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-ex-assign", - "description": "Disallow reassigning exceptions in `catch` clauses", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-fallthrough", - "description": "Disallow fallthrough of `case` statements", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-func-assign", - "description": "Disallow reassigning `function` declarations", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-import-assign", - "description": "Disallow assigning to imported bindings", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-inner-declarations", - "description": "Disallow variable or `function` declarations in nested blocks", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-invalid-regexp", - "description": "Disallow invalid regular expression strings in `RegExp` constructors", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-irregular-whitespace", - "description": "Disallow irregular whitespace", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-loss-of-precision", - "description": "Disallow literal numbers that lose precision", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-misleading-character-class", - "description": "Disallow characters which are made with multiple code points in character class syntax", - "recommended": true, - "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", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-obj-calls", - "description": "Disallow calling global object properties as functions", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-promise-executor-return", - "description": "Disallow returning values from Promise executor functions", - "recommended": false, - "fixable": false, - "hasSuggestions": true - }, - { - "name": "no-prototype-builtins", - "description": "Disallow calling some `Object.prototype` methods directly on objects", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-self-assign", - "description": "Disallow assignments where both sides are exactly the same", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-self-compare", - "description": "Disallow comparisons where both sides are exactly the same", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-setter-return", - "description": "Disallow returning values from setters", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-sparse-arrays", - "description": "Disallow sparse arrays", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-template-curly-in-string", - "description": "Disallow template literal placeholder syntax in regular strings", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-this-before-super", - "description": "Disallow `this`/`super` before calling `super()` in constructors", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-undef", - "description": "Disallow the use of undeclared variables unless mentioned in `/*global */` comments", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-unexpected-multiline", - "description": "Disallow confusing multiline expressions", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-unmodified-loop-condition", - "description": "Disallow unmodified loop conditions", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-unreachable", - "description": "Disallow unreachable code after `return`, `throw`, `continue`, and `break` statements", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-unreachable-loop", - "description": "Disallow loops with a body that allows only one iteration", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-unsafe-finally", - "description": "Disallow control flow statements in `finally` blocks", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-unsafe-negation", - "description": "Disallow negating the left operand of relational operators", - "recommended": true, - "fixable": false, - "hasSuggestions": true - }, - { - "name": "no-unsafe-optional-chaining", - "description": "Disallow use of optional chaining in contexts where the `undefined` value is not allowed", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-unused-private-class-members", - "description": "Disallow unused private class members", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-unused-vars", - "description": "Disallow unused variables", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-use-before-define", - "description": "Disallow the use of variables before they are defined", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-useless-backreference", - "description": "Disallow useless backreferences in regular expressions", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "require-atomic-updates", - "description": "Disallow assignments that can lead to race conditions due to usage of `await` or `yield`", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "use-isnan", - "description": "Require calls to `isNaN()` when checking for `NaN`", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "valid-typeof", - "description": "Enforce comparing `typeof` expressions against valid strings", - "recommended": true, - "fixable": false, - "hasSuggestions": true - } - ] - }, - { - "name": "suggestion", - "displayName": "Suggestions", - "description": "These rules suggest alternate ways of doing things:", - "rules": [ - { - "name": "accessor-pairs", - "description": "Enforce getter and setter pairs in objects and classes", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "arrow-body-style", - "description": "Require braces around arrow function bodies", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "block-scoped-var", - "description": "Enforce the use of variables within the scope they are defined", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "camelcase", - "description": "Enforce camelcase naming convention", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "capitalized-comments", - "description": "Enforce or disallow capitalization of the first letter of a comment", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "class-methods-use-this", - "description": "Enforce that class methods utilize `this`", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "complexity", - "description": "Enforce a maximum cyclomatic complexity allowed in a program", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "consistent-return", - "description": "Require `return` statements to either always or never specify values", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "consistent-this", - "description": "Enforce consistent naming when capturing the current execution context", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "curly", - "description": "Enforce consistent brace style for all control statements", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "default-case", - "description": "Require `default` cases in `switch` statements", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "default-case-last", - "description": "Enforce default clauses in switch statements to be last", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "default-param-last", - "description": "Enforce default parameters to be last", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "dot-notation", - "description": "Enforce dot notation whenever possible", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "eqeqeq", - "description": "Require the use of `===` and `!==`", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "func-name-matching", - "description": "Require function names to match the name of the variable or property to which they are assigned", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "func-names", - "description": "Require or disallow named `function` expressions", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "func-style", - "description": "Enforce the consistent use of either `function` declarations or expressions", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "grouped-accessor-pairs", - "description": "Require grouped accessor pairs in object literals and classes", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "guard-for-in", - "description": "Require `for-in` loops to include an `if` statement", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "id-denylist", - "description": "Disallow specified identifiers", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "id-length", - "description": "Enforce minimum and maximum identifier lengths", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "id-match", - "description": "Require identifiers to match a specified regular expression", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "init-declarations", - "description": "Require or disallow initialization in variable declarations", - "recommended": false, - "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", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "max-depth", - "description": "Enforce a maximum depth that blocks can be nested", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "max-lines", - "description": "Enforce a maximum number of lines per file", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "max-lines-per-function", - "description": "Enforce a maximum number of lines of code in a function", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "max-nested-callbacks", - "description": "Enforce a maximum depth that callbacks can be nested", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "max-params", - "description": "Enforce a maximum number of parameters in function definitions", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "max-statements", - "description": "Enforce a maximum number of statements allowed in function blocks", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "multiline-comment-style", - "description": "Enforce a particular style for multiline comments", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "new-cap", - "description": "Require constructor names to begin with a capital letter", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-alert", - "description": "Disallow the use of `alert`, `confirm`, and `prompt`", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-array-constructor", - "description": "Disallow `Array` constructors", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-bitwise", - "description": "Disallow bitwise operators", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-caller", - "description": "Disallow the use of `arguments.caller` or `arguments.callee`", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-case-declarations", - "description": "Disallow lexical declarations in case clauses", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-confusing-arrow", - "description": "Disallow arrow functions where they could be confused with comparisons", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-console", - "description": "Disallow the use of `console`", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-continue", - "description": "Disallow `continue` statements", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-delete-var", - "description": "Disallow deleting variables", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-div-regex", - "description": "Disallow equal signs explicitly at the beginning of regular expressions", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-else-return", - "description": "Disallow `else` blocks after `return` statements in `if` statements", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-empty", - "description": "Disallow empty block statements", - "recommended": true, - "fixable": false, - "hasSuggestions": true - }, - { - "name": "no-empty-function", - "description": "Disallow empty functions", - "recommended": false, - "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", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-eval", - "description": "Disallow the use of `eval()`", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-extend-native", - "description": "Disallow extending native types", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-extra-bind", - "description": "Disallow unnecessary calls to `.bind()`", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-extra-boolean-cast", - "description": "Disallow unnecessary boolean casts", - "recommended": true, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-extra-label", - "description": "Disallow unnecessary labels", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-extra-semi", - "description": "Disallow unnecessary semicolons", - "recommended": true, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-floating-decimal", - "description": "Disallow leading or trailing decimal points in numeric literals", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-global-assign", - "description": "Disallow assignments to native objects or read-only global variables", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-implicit-coercion", - "description": "Disallow shorthand type conversions", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-implicit-globals", - "description": "Disallow declarations in the global scope", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-implied-eval", - "description": "Disallow the use of `eval()`-like methods", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-inline-comments", - "description": "Disallow inline comments after code", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-invalid-this", - "description": "Disallow use of `this` in contexts where the value of `this` is `undefined`", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-iterator", - "description": "Disallow the use of the `__iterator__` property", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-label-var", - "description": "Disallow labels that share a name with a variable", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-labels", - "description": "Disallow labeled statements", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-lone-blocks", - "description": "Disallow unnecessary nested blocks", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-lonely-if", - "description": "Disallow `if` statements as the only statement in `else` blocks", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-loop-func", - "description": "Disallow function declarations that contain unsafe references inside loop statements", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-magic-numbers", - "description": "Disallow magic numbers", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-mixed-operators", - "description": "Disallow mixed binary operators", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-multi-assign", - "description": "Disallow use of chained assignment expressions", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-multi-str", - "description": "Disallow multiline strings", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-negated-condition", - "description": "Disallow negated conditions", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-nested-ternary", - "description": "Disallow nested ternary expressions", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-new", - "description": "Disallow `new` operators outside of assignments or comparisons", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-new-func", - "description": "Disallow `new` operators with the `Function` object", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-new-wrappers", - "description": "Disallow `new` operators with the `String`, `Number`, and `Boolean` objects", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-nonoctal-decimal-escape", - "description": "Disallow `\\8` and `\\9` escape sequences in string literals", - "recommended": true, - "fixable": false, - "hasSuggestions": true - }, - { - "name": "no-object-constructor", - "description": "Disallow calls to the `Object` constructor without an argument", - "recommended": false, - "fixable": false, - "hasSuggestions": true - }, - { - "name": "no-octal", - "description": "Disallow octal literals", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-octal-escape", - "description": "Disallow octal escape sequences in string literals", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-param-reassign", - "description": "Disallow reassigning `function` parameters", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-plusplus", - "description": "Disallow the unary operators `++` and `--`", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-proto", - "description": "Disallow the use of the `__proto__` property", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-redeclare", - "description": "Disallow variable redeclaration", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-regex-spaces", - "description": "Disallow multiple spaces in regular expressions", - "recommended": true, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-restricted-exports", - "description": "Disallow specified names in exports", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-restricted-globals", - "description": "Disallow specified global variables", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-restricted-imports", - "description": "Disallow specified modules when loaded by `import`", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-restricted-properties", - "description": "Disallow certain properties on certain objects", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-restricted-syntax", - "description": "Disallow specified syntax", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-return-assign", - "description": "Disallow assignment operators in `return` statements", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-script-url", - "description": "Disallow `javascript:` urls", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-sequences", - "description": "Disallow comma operators", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-shadow", - "description": "Disallow variable declarations from shadowing variables declared in the outer scope", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-shadow-restricted-names", - "description": "Disallow identifiers from shadowing restricted names", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-ternary", - "description": "Disallow ternary operators", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-throw-literal", - "description": "Disallow throwing literals as exceptions", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-undef-init", - "description": "Disallow initializing variables to `undefined`", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-undefined", - "description": "Disallow the use of `undefined` as an identifier", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-underscore-dangle", - "description": "Disallow dangling underscores in identifiers", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-unneeded-ternary", - "description": "Disallow ternary operators when simpler alternatives exist", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-unused-expressions", - "description": "Disallow unused expressions", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-unused-labels", - "description": "Disallow unused labels", - "recommended": true, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-useless-call", - "description": "Disallow unnecessary calls to `.call()` and `.apply()`", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-useless-catch", - "description": "Disallow unnecessary `catch` clauses", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-useless-computed-key", - "description": "Disallow unnecessary computed property keys in objects and classes", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-useless-concat", - "description": "Disallow unnecessary concatenation of literals or template literals", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-useless-constructor", - "description": "Disallow unnecessary constructors", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-useless-escape", - "description": "Disallow unnecessary escape characters", - "recommended": true, - "fixable": false, - "hasSuggestions": true - }, - { - "name": "no-useless-rename", - "description": "Disallow renaming import, export, and destructured assignments to the same name", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-useless-return", - "description": "Disallow redundant return statements", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-var", - "description": "Require `let` or `const` instead of `var`", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-void", - "description": "Disallow `void` operators", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-warning-comments", - "description": "Disallow specified warning terms in comments", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-with", - "description": "Disallow `with` statements", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "object-shorthand", - "description": "Require or disallow method and property shorthand syntax for object literals", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "one-var", - "description": "Enforce variables to be declared either together or separately in functions", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "one-var-declaration-per-line", - "description": "Require or disallow newlines around variable declarations", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "operator-assignment", - "description": "Require or disallow assignment operator shorthand where possible", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "prefer-arrow-callback", - "description": "Require using arrow functions for callbacks", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "prefer-const", - "description": "Require `const` declarations for variables that are never reassigned after declared", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "prefer-destructuring", - "description": "Require destructuring from arrays and/or objects", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "prefer-exponentiation-operator", - "description": "Disallow the use of `Math.pow` in favor of the `**` operator", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "prefer-named-capture-group", - "description": "Enforce using named capture group in regular expression", - "recommended": false, - "fixable": false, - "hasSuggestions": true - }, - { - "name": "prefer-numeric-literals", - "description": "Disallow `parseInt()` and `Number.parseInt()` in favor of binary, octal, and hexadecimal literals", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "prefer-object-has-own", - "description": "Disallow use of `Object.prototype.hasOwnProperty.call()` and prefer use of `Object.hasOwn()`", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "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", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "prefer-promise-reject-errors", - "description": "Require using Error objects as Promise rejection reasons", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "prefer-regex-literals", - "description": "Disallow use of the `RegExp` constructor in favor of regular expression literals", - "recommended": false, - "fixable": false, - "hasSuggestions": true - }, - { - "name": "prefer-rest-params", - "description": "Require rest parameters instead of `arguments`", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "prefer-spread", - "description": "Require spread operators instead of `.apply()`", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "prefer-template", - "description": "Require template literals instead of string concatenation", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "quote-props", - "description": "Require quotes around object literal property names", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "radix", - "description": "Enforce the consistent use of the radix argument when using `parseInt()`", - "recommended": false, - "fixable": false, - "hasSuggestions": true - }, - { - "name": "require-await", - "description": "Disallow async functions which have no `await` expression", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "require-unicode-regexp", - "description": "Enforce the use of `u` or `v` flag on RegExp", - "recommended": false, - "fixable": false, - "hasSuggestions": true - }, - { - "name": "require-yield", - "description": "Require generator functions to contain `yield`", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "sort-imports", - "description": "Enforce sorted import declarations within modules", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "sort-keys", - "description": "Require object keys to be sorted", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "sort-vars", - "description": "Require variables within the same declaration block to be sorted", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "spaced-comment", - "description": "Enforce consistent spacing after the `//` or `/*` in a comment", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "strict", - "description": "Require or disallow strict mode directives", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "symbol-description", - "description": "Require symbol descriptions", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "vars-on-top", - "description": "Require `var` declarations be placed at the top of their containing scope", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "yoda", - "description": "Require or disallow \"Yoda\" conditions", - "recommended": false, - "fixable": true, - "hasSuggestions": false - } - ] - }, - { - "name": "layout", - "displayName": "Layout & Formatting", - "description": "These rules care about how the code looks rather than how it executes:", - "rules": [ - { - "name": "array-bracket-newline", - "description": "Enforce linebreaks after opening and before closing array brackets", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "array-bracket-spacing", - "description": "Enforce consistent spacing inside array brackets", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "array-element-newline", - "description": "Enforce line breaks after each array element", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "arrow-parens", - "description": "Require parentheses around arrow function arguments", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "arrow-spacing", - "description": "Enforce consistent spacing before and after the arrow in arrow functions", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "block-spacing", - "description": "Disallow or enforce spaces inside of blocks after opening block and before closing block", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "brace-style", - "description": "Enforce consistent brace style for blocks", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "comma-dangle", - "description": "Require or disallow trailing commas", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "comma-spacing", - "description": "Enforce consistent spacing before and after commas", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "comma-style", - "description": "Enforce consistent comma style", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "computed-property-spacing", - "description": "Enforce consistent spacing inside computed property brackets", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "dot-location", - "description": "Enforce consistent newlines before and after dots", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "eol-last", - "description": "Require or disallow newline at the end of files", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "func-call-spacing", - "description": "Require or disallow spacing between function identifiers and their invocations", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "function-call-argument-newline", - "description": "Enforce line breaks between arguments of a function call", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "function-paren-newline", - "description": "Enforce consistent line breaks inside function parentheses", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "generator-star-spacing", - "description": "Enforce consistent spacing around `*` operators in generator functions", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "implicit-arrow-linebreak", - "description": "Enforce the location of arrow function bodies", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "indent", - "description": "Enforce consistent indentation", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "jsx-quotes", - "description": "Enforce the consistent use of either double or single quotes in JSX attributes", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "key-spacing", - "description": "Enforce consistent spacing between keys and values in object literal properties", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "keyword-spacing", - "description": "Enforce consistent spacing before and after keywords", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "line-comment-position", - "description": "Enforce position of line comments", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "linebreak-style", - "description": "Enforce consistent linebreak style", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "lines-around-comment", - "description": "Require empty lines around comments", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "lines-between-class-members", - "description": "Require or disallow an empty line between class members", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "max-len", - "description": "Enforce a maximum line length", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "max-statements-per-line", - "description": "Enforce a maximum number of statements allowed per line", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "multiline-ternary", - "description": "Enforce newlines between operands of ternary expressions", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "new-parens", - "description": "Enforce or disallow parentheses when invoking a constructor with no arguments", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "newline-per-chained-call", - "description": "Require a newline after each call in a method chain", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-extra-parens", - "description": "Disallow unnecessary parentheses", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-mixed-spaces-and-tabs", - "description": "Disallow mixed spaces and tabs for indentation", - "recommended": true, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-multi-spaces", - "description": "Disallow multiple spaces", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-multiple-empty-lines", - "description": "Disallow multiple empty lines", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-tabs", - "description": "Disallow all tabs", - "recommended": false, - "fixable": false, - "hasSuggestions": false - }, - { - "name": "no-trailing-spaces", - "description": "Disallow trailing whitespace at the end of lines", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "no-whitespace-before-property", - "description": "Disallow whitespace before properties", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "nonblock-statement-body-position", - "description": "Enforce the location of single-line statements", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "object-curly-newline", - "description": "Enforce consistent line breaks after opening and before closing braces", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "object-curly-spacing", - "description": "Enforce consistent spacing inside braces", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "object-property-newline", - "description": "Enforce placing object properties on separate lines", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "operator-linebreak", - "description": "Enforce consistent linebreak style for operators", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "padded-blocks", - "description": "Require or disallow padding within blocks", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "padding-line-between-statements", - "description": "Require or disallow padding lines between statements", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "quotes", - "description": "Enforce the consistent use of either backticks, double, or single quotes", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "rest-spread-spacing", - "description": "Enforce spacing between rest and spread operators and their expressions", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "semi", - "description": "Require or disallow semicolons instead of ASI", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "semi-spacing", - "description": "Enforce consistent spacing before and after semicolons", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "semi-style", - "description": "Enforce location of semicolons", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "space-before-blocks", - "description": "Enforce consistent spacing before blocks", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "space-before-function-paren", - "description": "Enforce consistent spacing before `function` definition opening parenthesis", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "space-in-parens", - "description": "Enforce consistent spacing inside parentheses", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "space-infix-ops", - "description": "Require spacing around infix operators", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "space-unary-ops", - "description": "Enforce consistent spacing before or after unary operators", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "switch-colon-spacing", - "description": "Enforce spacing around colons of switch statements", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "template-curly-spacing", - "description": "Require or disallow spacing around embedded expressions of template strings", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "template-tag-spacing", - "description": "Require or disallow spacing between template tags and their literals", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "unicode-bom", - "description": "Require or disallow Unicode byte order mark (BOM)", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "wrap-iife", - "description": "Require parentheses around immediate `function` invocations", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "wrap-regex", - "description": "Require parenthesis around regex literals", - "recommended": false, - "fixable": true, - "hasSuggestions": false - }, - { - "name": "yield-star-spacing", - "description": "Require or disallow spacing around the `*` in `yield*` expressions", - "recommended": false, - "fixable": true, - "hasSuggestions": false - } - ] - } - ], - "deprecated": { - "name": "Deprecated", - "description": "These rules have been deprecated in accordance with the deprecation policy, and replaced by newer rules:", - "rules": [ + "types": { + "problem": [ + { + "name": "array-callback-return", + "description": "Enforce `return` statements in callbacks of array methods", + "recommended": false, + "fixable": false, + "hasSuggestions": true + }, + { + "name": "constructor-super", + "description": "Require `super()` calls in constructors", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "for-direction", + "description": "Enforce \"for\" loop update clause moving the counter in the right direction", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "getter-return", + "description": "Enforce `return` statements in getters", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-async-promise-executor", + "description": "Disallow using an async function as a Promise executor", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-await-in-loop", + "description": "Disallow `await` inside of loops", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-class-assign", + "description": "Disallow reassigning class members", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-compare-neg-zero", + "description": "Disallow comparing against -0", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-cond-assign", + "description": "Disallow assignment operators in conditional expressions", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-const-assign", + "description": "Disallow reassigning `const` variables", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-constant-binary-expression", + "description": "Disallow expressions where the operation doesn't affect the value", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-constant-condition", + "description": "Disallow constant expressions in conditions", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-constructor-return", + "description": "Disallow returning value from constructor", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-control-regex", + "description": "Disallow control characters in regular expressions", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-debugger", + "description": "Disallow the use of `debugger`", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-dupe-args", + "description": "Disallow duplicate arguments in `function` definitions", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-dupe-class-members", + "description": "Disallow duplicate class members", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-dupe-else-if", + "description": "Disallow duplicate conditions in if-else-if chains", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-dupe-keys", + "description": "Disallow duplicate keys in object literals", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-duplicate-case", + "description": "Disallow duplicate case labels", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-duplicate-imports", + "description": "Disallow duplicate module imports", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-empty-character-class", + "description": "Disallow empty character classes in regular expressions", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-empty-pattern", + "description": "Disallow empty destructuring patterns", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-ex-assign", + "description": "Disallow reassigning exceptions in `catch` clauses", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-fallthrough", + "description": "Disallow fallthrough of `case` statements", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-func-assign", + "description": "Disallow reassigning `function` declarations", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-import-assign", + "description": "Disallow assigning to imported bindings", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-inner-declarations", + "description": "Disallow variable or `function` declarations in nested blocks", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-invalid-regexp", + "description": "Disallow invalid regular expression strings in `RegExp` constructors", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-irregular-whitespace", + "description": "Disallow irregular whitespace", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-loss-of-precision", + "description": "Disallow literal numbers that lose precision", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-misleading-character-class", + "description": "Disallow characters which are made with multiple code points in character class syntax", + "recommended": true, + "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", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-obj-calls", + "description": "Disallow calling global object properties as functions", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-promise-executor-return", + "description": "Disallow returning values from Promise executor functions", + "recommended": false, + "fixable": false, + "hasSuggestions": true + }, + { + "name": "no-prototype-builtins", + "description": "Disallow calling some `Object.prototype` methods directly on objects", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-self-assign", + "description": "Disallow assignments where both sides are exactly the same", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-self-compare", + "description": "Disallow comparisons where both sides are exactly the same", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-setter-return", + "description": "Disallow returning values from setters", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-sparse-arrays", + "description": "Disallow sparse arrays", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-template-curly-in-string", + "description": "Disallow template literal placeholder syntax in regular strings", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-this-before-super", + "description": "Disallow `this`/`super` before calling `super()` in constructors", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-undef", + "description": "Disallow the use of undeclared variables unless mentioned in `/*global */` comments", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-unexpected-multiline", + "description": "Disallow confusing multiline expressions", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-unmodified-loop-condition", + "description": "Disallow unmodified loop conditions", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-unreachable", + "description": "Disallow unreachable code after `return`, `throw`, `continue`, and `break` statements", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-unreachable-loop", + "description": "Disallow loops with a body that allows only one iteration", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-unsafe-finally", + "description": "Disallow control flow statements in `finally` blocks", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-unsafe-negation", + "description": "Disallow negating the left operand of relational operators", + "recommended": true, + "fixable": false, + "hasSuggestions": true + }, + { + "name": "no-unsafe-optional-chaining", + "description": "Disallow use of optional chaining in contexts where the `undefined` value is not allowed", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-unused-private-class-members", + "description": "Disallow unused private class members", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-unused-vars", + "description": "Disallow unused variables", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-use-before-define", + "description": "Disallow the use of variables before they are defined", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-useless-backreference", + "description": "Disallow useless backreferences in regular expressions", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "require-atomic-updates", + "description": "Disallow assignments that can lead to race conditions due to usage of `await` or `yield`", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "use-isnan", + "description": "Require calls to `isNaN()` when checking for `NaN`", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "valid-typeof", + "description": "Enforce comparing `typeof` expressions against valid strings", + "recommended": true, + "fixable": false, + "hasSuggestions": true + } + ], + "suggestion": [ + { + "name": "accessor-pairs", + "description": "Enforce getter and setter pairs in objects and classes", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "arrow-body-style", + "description": "Require braces around arrow function bodies", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "block-scoped-var", + "description": "Enforce the use of variables within the scope they are defined", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "camelcase", + "description": "Enforce camelcase naming convention", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "capitalized-comments", + "description": "Enforce or disallow capitalization of the first letter of a comment", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "class-methods-use-this", + "description": "Enforce that class methods utilize `this`", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "complexity", + "description": "Enforce a maximum cyclomatic complexity allowed in a program", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "consistent-return", + "description": "Require `return` statements to either always or never specify values", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "consistent-this", + "description": "Enforce consistent naming when capturing the current execution context", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "curly", + "description": "Enforce consistent brace style for all control statements", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "default-case", + "description": "Require `default` cases in `switch` statements", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "default-case-last", + "description": "Enforce default clauses in switch statements to be last", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "default-param-last", + "description": "Enforce default parameters to be last", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "dot-notation", + "description": "Enforce dot notation whenever possible", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "eqeqeq", + "description": "Require the use of `===` and `!==`", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "func-name-matching", + "description": "Require function names to match the name of the variable or property to which they are assigned", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "func-names", + "description": "Require or disallow named `function` expressions", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "func-style", + "description": "Enforce the consistent use of either `function` declarations or expressions", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "grouped-accessor-pairs", + "description": "Require grouped accessor pairs in object literals and classes", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "guard-for-in", + "description": "Require `for-in` loops to include an `if` statement", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "id-denylist", + "description": "Disallow specified identifiers", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "id-length", + "description": "Enforce minimum and maximum identifier lengths", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "id-match", + "description": "Require identifiers to match a specified regular expression", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "init-declarations", + "description": "Require or disallow initialization in variable declarations", + "recommended": false, + "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", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "max-depth", + "description": "Enforce a maximum depth that blocks can be nested", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "max-lines", + "description": "Enforce a maximum number of lines per file", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "max-lines-per-function", + "description": "Enforce a maximum number of lines of code in a function", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "max-nested-callbacks", + "description": "Enforce a maximum depth that callbacks can be nested", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "max-params", + "description": "Enforce a maximum number of parameters in function definitions", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "max-statements", + "description": "Enforce a maximum number of statements allowed in function blocks", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "multiline-comment-style", + "description": "Enforce a particular style for multiline comments", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "new-cap", + "description": "Require constructor names to begin with a capital letter", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-alert", + "description": "Disallow the use of `alert`, `confirm`, and `prompt`", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-array-constructor", + "description": "Disallow `Array` constructors", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-bitwise", + "description": "Disallow bitwise operators", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-caller", + "description": "Disallow the use of `arguments.caller` or `arguments.callee`", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-case-declarations", + "description": "Disallow lexical declarations in case clauses", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-confusing-arrow", + "description": "Disallow arrow functions where they could be confused with comparisons", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "no-console", + "description": "Disallow the use of `console`", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-continue", + "description": "Disallow `continue` statements", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-delete-var", + "description": "Disallow deleting variables", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-div-regex", + "description": "Disallow equal signs explicitly at the beginning of regular expressions", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "no-else-return", + "description": "Disallow `else` blocks after `return` statements in `if` statements", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "no-empty", + "description": "Disallow empty block statements", + "recommended": true, + "fixable": false, + "hasSuggestions": true + }, + { + "name": "no-empty-function", + "description": "Disallow empty functions", + "recommended": false, + "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", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-eval", + "description": "Disallow the use of `eval()`", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-extend-native", + "description": "Disallow extending native types", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-extra-bind", + "description": "Disallow unnecessary calls to `.bind()`", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "no-extra-boolean-cast", + "description": "Disallow unnecessary boolean casts", + "recommended": true, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "no-extra-label", + "description": "Disallow unnecessary labels", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "no-extra-semi", + "description": "Disallow unnecessary semicolons", + "recommended": true, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "no-floating-decimal", + "description": "Disallow leading or trailing decimal points in numeric literals", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "no-global-assign", + "description": "Disallow assignments to native objects or read-only global variables", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-implicit-coercion", + "description": "Disallow shorthand type conversions", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "no-implicit-globals", + "description": "Disallow declarations in the global scope", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-implied-eval", + "description": "Disallow the use of `eval()`-like methods", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-inline-comments", + "description": "Disallow inline comments after code", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-invalid-this", + "description": "Disallow use of `this` in contexts where the value of `this` is `undefined`", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-iterator", + "description": "Disallow the use of the `__iterator__` property", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-label-var", + "description": "Disallow labels that share a name with a variable", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-labels", + "description": "Disallow labeled statements", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-lone-blocks", + "description": "Disallow unnecessary nested blocks", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-lonely-if", + "description": "Disallow `if` statements as the only statement in `else` blocks", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "no-loop-func", + "description": "Disallow function declarations that contain unsafe references inside loop statements", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-magic-numbers", + "description": "Disallow magic numbers", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-mixed-operators", + "description": "Disallow mixed binary operators", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-multi-assign", + "description": "Disallow use of chained assignment expressions", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-multi-str", + "description": "Disallow multiline strings", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-negated-condition", + "description": "Disallow negated conditions", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-nested-ternary", + "description": "Disallow nested ternary expressions", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-new", + "description": "Disallow `new` operators outside of assignments or comparisons", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-new-func", + "description": "Disallow `new` operators with the `Function` object", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-new-wrappers", + "description": "Disallow `new` operators with the `String`, `Number`, and `Boolean` objects", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-nonoctal-decimal-escape", + "description": "Disallow `\\8` and `\\9` escape sequences in string literals", + "recommended": true, + "fixable": false, + "hasSuggestions": true + }, + { + "name": "no-object-constructor", + "description": "Disallow calls to the `Object` constructor without an argument", + "recommended": false, + "fixable": false, + "hasSuggestions": true + }, + { + "name": "no-octal", + "description": "Disallow octal literals", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-octal-escape", + "description": "Disallow octal escape sequences in string literals", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-param-reassign", + "description": "Disallow reassigning `function` parameters", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-plusplus", + "description": "Disallow the unary operators `++` and `--`", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-proto", + "description": "Disallow the use of the `__proto__` property", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-redeclare", + "description": "Disallow variable redeclaration", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-regex-spaces", + "description": "Disallow multiple spaces in regular expressions", + "recommended": true, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "no-restricted-exports", + "description": "Disallow specified names in exports", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-restricted-globals", + "description": "Disallow specified global variables", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-restricted-imports", + "description": "Disallow specified modules when loaded by `import`", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-restricted-properties", + "description": "Disallow certain properties on certain objects", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-restricted-syntax", + "description": "Disallow specified syntax", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-return-assign", + "description": "Disallow assignment operators in `return` statements", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-script-url", + "description": "Disallow `javascript:` urls", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-sequences", + "description": "Disallow comma operators", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-shadow", + "description": "Disallow variable declarations from shadowing variables declared in the outer scope", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-shadow-restricted-names", + "description": "Disallow identifiers from shadowing restricted names", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, { - "name": "callback-return", - "replacedBy": [] + "name": "no-ternary", + "description": "Disallow ternary operators", + "recommended": false, + "fixable": false, + "hasSuggestions": false }, { - "name": "global-require", - "replacedBy": [] + "name": "no-throw-literal", + "description": "Disallow throwing literals as exceptions", + "recommended": false, + "fixable": false, + "hasSuggestions": false }, { - "name": "handle-callback-err", - "replacedBy": [] + "name": "no-undef-init", + "description": "Disallow initializing variables to `undefined`", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "name": "id-blacklist", - "replacedBy": [ - "id-denylist" - ] + "name": "no-undefined", + "description": "Disallow the use of `undefined` as an identifier", + "recommended": false, + "fixable": false, + "hasSuggestions": false }, { - "name": "indent-legacy", - "replacedBy": [ - "indent" - ] + "name": "no-underscore-dangle", + "description": "Disallow dangling underscores in identifiers", + "recommended": false, + "fixable": false, + "hasSuggestions": false }, { - "name": "lines-around-directive", - "replacedBy": [ - "padding-line-between-statements" - ] + "name": "no-unneeded-ternary", + "description": "Disallow ternary operators when simpler alternatives exist", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "name": "newline-after-var", - "replacedBy": [ - "padding-line-between-statements" - ] + "name": "no-unused-expressions", + "description": "Disallow unused expressions", + "recommended": false, + "fixable": false, + "hasSuggestions": false }, { - "name": "newline-before-return", - "replacedBy": [ - "padding-line-between-statements" - ] + "name": "no-unused-labels", + "description": "Disallow unused labels", + "recommended": true, + "fixable": true, + "hasSuggestions": false }, { - "name": "no-buffer-constructor", - "replacedBy": [] + "name": "no-useless-call", + "description": "Disallow unnecessary calls to `.call()` and `.apply()`", + "recommended": false, + "fixable": false, + "hasSuggestions": false }, { - "name": "no-catch-shadow", - "replacedBy": [ - "no-shadow" - ] + "name": "no-useless-catch", + "description": "Disallow unnecessary `catch` clauses", + "recommended": true, + "fixable": false, + "hasSuggestions": false }, { - "name": "no-mixed-requires", - "replacedBy": [] + "name": "no-useless-computed-key", + "description": "Disallow unnecessary computed property keys in objects and classes", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "name": "no-native-reassign", - "replacedBy": [ - "no-global-assign" - ] + "name": "no-useless-concat", + "description": "Disallow unnecessary concatenation of literals or template literals", + "recommended": false, + "fixable": false, + "hasSuggestions": false }, { - "name": "no-negated-in-lhs", - "replacedBy": [ - "no-unsafe-negation" - ] + "name": "no-useless-constructor", + "description": "Disallow unnecessary constructors", + "recommended": false, + "fixable": false, + "hasSuggestions": false }, { - "name": "no-new-object", - "replacedBy": [ - "no-object-constructor" - ] + "name": "no-useless-escape", + "description": "Disallow unnecessary escape characters", + "recommended": true, + "fixable": false, + "hasSuggestions": true }, { - "name": "no-new-require", - "replacedBy": [] + "name": "no-useless-rename", + "description": "Disallow renaming import, export, and destructured assignments to the same name", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "name": "no-path-concat", - "replacedBy": [] + "name": "no-useless-return", + "description": "Disallow redundant return statements", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "name": "no-process-env", - "replacedBy": [] + "name": "no-var", + "description": "Require `let` or `const` instead of `var`", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "name": "no-process-exit", - "replacedBy": [] + "name": "no-void", + "description": "Disallow `void` operators", + "recommended": false, + "fixable": false, + "hasSuggestions": false }, { - "name": "no-restricted-modules", - "replacedBy": [] + "name": "no-warning-comments", + "description": "Disallow specified warning terms in comments", + "recommended": false, + "fixable": false, + "hasSuggestions": false }, { - "name": "no-return-await", - "replacedBy": [] + "name": "no-with", + "description": "Disallow `with` statements", + "recommended": true, + "fixable": false, + "hasSuggestions": false }, { - "name": "no-spaced-func", - "replacedBy": [ - "func-call-spacing" - ] + "name": "object-shorthand", + "description": "Require or disallow method and property shorthand syntax for object literals", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "name": "no-sync", - "replacedBy": [] + "name": "one-var", + "description": "Enforce variables to be declared either together or separately in functions", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "name": "prefer-reflect", - "replacedBy": [] + "name": "one-var-declaration-per-line", + "description": "Require or disallow newlines around variable declarations", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "name": "require-jsdoc", - "replacedBy": [] + "name": "operator-assignment", + "description": "Require or disallow assignment operator shorthand where possible", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "name": "valid-jsdoc", - "replacedBy": [] + "name": "prefer-arrow-callback", + "description": "Require using arrow functions for callbacks", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "prefer-const", + "description": "Require `const` declarations for variables that are never reassigned after declared", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "prefer-destructuring", + "description": "Require destructuring from arrays and/or objects", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "prefer-exponentiation-operator", + "description": "Disallow the use of `Math.pow` in favor of the `**` operator", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "prefer-named-capture-group", + "description": "Enforce using named capture group in regular expression", + "recommended": false, + "fixable": false, + "hasSuggestions": true + }, + { + "name": "prefer-numeric-literals", + "description": "Disallow `parseInt()` and `Number.parseInt()` in favor of binary, octal, and hexadecimal literals", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "prefer-object-has-own", + "description": "Disallow use of `Object.prototype.hasOwnProperty.call()` and prefer use of `Object.hasOwn()`", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "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", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "prefer-promise-reject-errors", + "description": "Require using Error objects as Promise rejection reasons", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "prefer-regex-literals", + "description": "Disallow use of the `RegExp` constructor in favor of regular expression literals", + "recommended": false, + "fixable": false, + "hasSuggestions": true + }, + { + "name": "prefer-rest-params", + "description": "Require rest parameters instead of `arguments`", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "prefer-spread", + "description": "Require spread operators instead of `.apply()`", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "prefer-template", + "description": "Require template literals instead of string concatenation", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "quote-props", + "description": "Require quotes around object literal property names", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "radix", + "description": "Enforce the consistent use of the radix argument when using `parseInt()`", + "recommended": false, + "fixable": false, + "hasSuggestions": true + }, + { + "name": "require-await", + "description": "Disallow async functions which have no `await` expression", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "require-unicode-regexp", + "description": "Enforce the use of `u` or `v` flag on RegExp", + "recommended": false, + "fixable": false, + "hasSuggestions": true + }, + { + "name": "require-yield", + "description": "Require generator functions to contain `yield`", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "sort-imports", + "description": "Enforce sorted import declarations within modules", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "sort-keys", + "description": "Require object keys to be sorted", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "sort-vars", + "description": "Require variables within the same declaration block to be sorted", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "spaced-comment", + "description": "Enforce consistent spacing after the `//` or `/*` in a comment", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "strict", + "description": "Require or disallow strict mode directives", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "symbol-description", + "description": "Require symbol descriptions", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "vars-on-top", + "description": "Require `var` declarations be placed at the top of their containing scope", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "yoda", + "description": "Require or disallow \"Yoda\" conditions", + "recommended": false, + "fixable": true, + "hasSuggestions": false } - ] - }, - "removed": { - "name": "Removed", - "description": "These rules from older versions of ESLint (before the deprecation policy existed) have been replaced by newer rules:", - "rules": [ + ], + "layout": [ + { + "name": "array-bracket-newline", + "description": "Enforce linebreaks after opening and before closing array brackets", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "array-bracket-spacing", + "description": "Enforce consistent spacing inside array brackets", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "array-element-newline", + "description": "Enforce line breaks after each array element", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "arrow-parens", + "description": "Require parentheses around arrow function arguments", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "arrow-spacing", + "description": "Enforce consistent spacing before and after the arrow in arrow functions", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "block-spacing", + "description": "Disallow or enforce spaces inside of blocks after opening block and before closing block", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "brace-style", + "description": "Enforce consistent brace style for blocks", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "comma-dangle", + "description": "Require or disallow trailing commas", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "comma-spacing", + "description": "Enforce consistent spacing before and after commas", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "comma-style", + "description": "Enforce consistent comma style", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "computed-property-spacing", + "description": "Enforce consistent spacing inside computed property brackets", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "dot-location", + "description": "Enforce consistent newlines before and after dots", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "eol-last", + "description": "Require or disallow newline at the end of files", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "func-call-spacing", + "description": "Require or disallow spacing between function identifiers and their invocations", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "function-call-argument-newline", + "description": "Enforce line breaks between arguments of a function call", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "function-paren-newline", + "description": "Enforce consistent line breaks inside function parentheses", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "generator-star-spacing", + "description": "Enforce consistent spacing around `*` operators in generator functions", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "implicit-arrow-linebreak", + "description": "Enforce the location of arrow function bodies", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "indent", + "description": "Enforce consistent indentation", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "jsx-quotes", + "description": "Enforce the consistent use of either double or single quotes in JSX attributes", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "key-spacing", + "description": "Enforce consistent spacing between keys and values in object literal properties", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "keyword-spacing", + "description": "Enforce consistent spacing before and after keywords", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "line-comment-position", + "description": "Enforce position of line comments", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "linebreak-style", + "description": "Enforce consistent linebreak style", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "lines-around-comment", + "description": "Require empty lines around comments", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "lines-between-class-members", + "description": "Require or disallow an empty line between class members", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "max-len", + "description": "Enforce a maximum line length", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "max-statements-per-line", + "description": "Enforce a maximum number of statements allowed per line", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "multiline-ternary", + "description": "Enforce newlines between operands of ternary expressions", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "new-parens", + "description": "Enforce or disallow parentheses when invoking a constructor with no arguments", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "newline-per-chained-call", + "description": "Require a newline after each call in a method chain", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "no-extra-parens", + "description": "Disallow unnecessary parentheses", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "no-mixed-spaces-and-tabs", + "description": "Disallow mixed spaces and tabs for indentation", + "recommended": true, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-multi-spaces", + "description": "Disallow multiple spaces", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "no-multiple-empty-lines", + "description": "Disallow multiple empty lines", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "no-tabs", + "description": "Disallow all tabs", + "recommended": false, + "fixable": false, + "hasSuggestions": false + }, + { + "name": "no-trailing-spaces", + "description": "Disallow trailing whitespace at the end of lines", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "no-whitespace-before-property", + "description": "Disallow whitespace before properties", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, { - "removed": "generator-star", - "replacedBy": [ - "generator-star-spacing" - ] + "name": "nonblock-statement-body-position", + "description": "Enforce the location of single-line statements", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "removed": "global-strict", - "replacedBy": [ - "strict" - ] + "name": "object-curly-newline", + "description": "Enforce consistent line breaks after opening and before closing braces", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "removed": "no-arrow-condition", - "replacedBy": [ - "no-confusing-arrow", - "no-constant-condition" - ] + "name": "object-curly-spacing", + "description": "Enforce consistent spacing inside braces", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "removed": "no-comma-dangle", - "replacedBy": [ - "comma-dangle" - ] + "name": "object-property-newline", + "description": "Enforce placing object properties on separate lines", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "removed": "no-empty-class", - "replacedBy": [ - "no-empty-character-class" - ] + "name": "operator-linebreak", + "description": "Enforce consistent linebreak style for operators", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "removed": "no-empty-label", - "replacedBy": [ - "no-labels" - ] + "name": "padded-blocks", + "description": "Require or disallow padding within blocks", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "removed": "no-extra-strict", - "replacedBy": [ - "strict" - ] + "name": "padding-line-between-statements", + "description": "Require or disallow padding lines between statements", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "removed": "no-reserved-keys", - "replacedBy": [ - "quote-props" - ] + "name": "quotes", + "description": "Enforce the consistent use of either backticks, double, or single quotes", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "removed": "no-space-before-semi", - "replacedBy": [ - "semi-spacing" - ] + "name": "rest-spread-spacing", + "description": "Enforce spacing between rest and spread operators and their expressions", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "removed": "no-wrap-func", - "replacedBy": [ - "no-extra-parens" - ] + "name": "semi", + "description": "Require or disallow semicolons instead of ASI", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "removed": "space-after-function-name", - "replacedBy": [ - "space-before-function-paren" - ] + "name": "semi-spacing", + "description": "Enforce consistent spacing before and after semicolons", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "removed": "space-after-keywords", - "replacedBy": [ - "keyword-spacing" - ] + "name": "semi-style", + "description": "Enforce location of semicolons", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "removed": "space-before-function-parentheses", - "replacedBy": [ - "space-before-function-paren" - ] + "name": "space-before-blocks", + "description": "Enforce consistent spacing before blocks", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "removed": "space-before-keywords", - "replacedBy": [ - "keyword-spacing" - ] + "name": "space-before-function-paren", + "description": "Enforce consistent spacing before `function` definition opening parenthesis", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "removed": "space-in-brackets", - "replacedBy": [ - "object-curly-spacing", - "array-bracket-spacing" - ] + "name": "space-in-parens", + "description": "Enforce consistent spacing inside parentheses", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "removed": "space-return-throw-case", - "replacedBy": [ - "keyword-spacing" - ] + "name": "space-infix-ops", + "description": "Require spacing around infix operators", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "removed": "space-unary-word-ops", - "replacedBy": [ - "space-unary-ops" - ] + "name": "space-unary-ops", + "description": "Enforce consistent spacing before or after unary operators", + "recommended": false, + "fixable": true, + "hasSuggestions": false }, { - "removed": "spaced-line-comment", - "replacedBy": [ - "spaced-comment" - ] + "name": "switch-colon-spacing", + "description": "Enforce spacing around colons of switch statements", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "template-curly-spacing", + "description": "Require or disallow spacing around embedded expressions of template strings", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "template-tag-spacing", + "description": "Require or disallow spacing between template tags and their literals", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "unicode-bom", + "description": "Require or disallow Unicode byte order mark (BOM)", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "wrap-iife", + "description": "Require parentheses around immediate `function` invocations", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "wrap-regex", + "description": "Require parenthesis around regex literals", + "recommended": false, + "fixable": true, + "hasSuggestions": false + }, + { + "name": "yield-star-spacing", + "description": "Require or disallow spacing around the `*` in `yield*` expressions", + "recommended": false, + "fixable": true, + "hasSuggestions": false } ] - } + }, + "deprecated": [ + { + "name": "callback-return", + "replacedBy": [] + }, + { + "name": "global-require", + "replacedBy": [] + }, + { + "name": "handle-callback-err", + "replacedBy": [] + }, + { + "name": "id-blacklist", + "replacedBy": [ + "id-denylist" + ] + }, + { + "name": "indent-legacy", + "replacedBy": [ + "indent" + ] + }, + { + "name": "lines-around-directive", + "replacedBy": [ + "padding-line-between-statements" + ] + }, + { + "name": "newline-after-var", + "replacedBy": [ + "padding-line-between-statements" + ] + }, + { + "name": "newline-before-return", + "replacedBy": [ + "padding-line-between-statements" + ] + }, + { + "name": "no-buffer-constructor", + "replacedBy": [] + }, + { + "name": "no-catch-shadow", + "replacedBy": [ + "no-shadow" + ] + }, + { + "name": "no-mixed-requires", + "replacedBy": [] + }, + { + "name": "no-native-reassign", + "replacedBy": [ + "no-global-assign" + ] + }, + { + "name": "no-negated-in-lhs", + "replacedBy": [ + "no-unsafe-negation" + ] + }, + { + "name": "no-new-object", + "replacedBy": [ + "no-object-constructor" + ] + }, + { + "name": "no-new-require", + "replacedBy": [] + }, + { + "name": "no-path-concat", + "replacedBy": [] + }, + { + "name": "no-process-env", + "replacedBy": [] + }, + { + "name": "no-process-exit", + "replacedBy": [] + }, + { + "name": "no-restricted-modules", + "replacedBy": [] + }, + { + "name": "no-return-await", + "replacedBy": [] + }, + { + "name": "no-spaced-func", + "replacedBy": [ + "func-call-spacing" + ] + }, + { + "name": "no-sync", + "replacedBy": [] + }, + { + "name": "prefer-reflect", + "replacedBy": [] + }, + { + "name": "require-jsdoc", + "replacedBy": [] + }, + { + "name": "valid-jsdoc", + "replacedBy": [] + } + ], + "removed": [ + { + "removed": "generator-star", + "replacedBy": [ + "generator-star-spacing" + ] + }, + { + "removed": "global-strict", + "replacedBy": [ + "strict" + ] + }, + { + "removed": "no-arrow-condition", + "replacedBy": [ + "no-confusing-arrow", + "no-constant-condition" + ] + }, + { + "removed": "no-comma-dangle", + "replacedBy": [ + "comma-dangle" + ] + }, + { + "removed": "no-empty-class", + "replacedBy": [ + "no-empty-character-class" + ] + }, + { + "removed": "no-empty-label", + "replacedBy": [ + "no-labels" + ] + }, + { + "removed": "no-extra-strict", + "replacedBy": [ + "strict" + ] + }, + { + "removed": "no-reserved-keys", + "replacedBy": [ + "quote-props" + ] + }, + { + "removed": "no-space-before-semi", + "replacedBy": [ + "semi-spacing" + ] + }, + { + "removed": "no-wrap-func", + "replacedBy": [ + "no-extra-parens" + ] + }, + { + "removed": "space-after-function-name", + "replacedBy": [ + "space-before-function-paren" + ] + }, + { + "removed": "space-after-keywords", + "replacedBy": [ + "keyword-spacing" + ] + }, + { + "removed": "space-before-function-parentheses", + "replacedBy": [ + "space-before-function-paren" + ] + }, + { + "removed": "space-before-keywords", + "replacedBy": [ + "keyword-spacing" + ] + }, + { + "removed": "space-in-brackets", + "replacedBy": [ + "object-curly-spacing", + "array-bracket-spacing" + ] + }, + { + "removed": "space-return-throw-case", + "replacedBy": [ + "keyword-spacing" + ] + }, + { + "removed": "space-unary-word-ops", + "replacedBy": [ + "space-unary-ops" + ] + }, + { + "removed": "spaced-line-comment", + "replacedBy": [ + "spaced-comment" + ] + } + ] } \ No newline at end of file diff --git a/docs/src/_data/rules_categories.js b/docs/src/_data/rules_categories.js new file mode 100644 index 000000000000..46856958f228 --- /dev/null +++ b/docs/src/_data/rules_categories.js @@ -0,0 +1,26 @@ +module.exports = eleventy => { + const PATH_PREFIX = eleventy.PATH_PREFIX; + + return { + problem: { + displayName: "Possible Problems", + description: "These rules relate to possible logic errors in code:" + }, + suggestion: { + displayName: "Suggestions", + description: "These rules suggest alternate ways of doing things:" + }, + layout: { + displayName: "Layout & Formatting", + description: "These rules care about how the code looks rather than how it executes:" + }, + deprecated: { + displayName: "Deprecated", + description: `These rules have been deprecated in accordance with the deprecation policy, and replaced by newer rules:` + }, + removed: { + displayName: "Removed", + description: `These rules from older versions of ESLint (before the deprecation policy existed) have been replaced by newer rules:` + } + } +}; diff --git a/docs/src/pages/rules.md b/docs/src/pages/rules.md index 996860e2c865..9d801cf5126b 100644 --- a/docs/src/pages/rules.md +++ b/docs/src/pages/rules.md @@ -20,14 +20,17 @@ Rules in ESLint are grouped by type to help you understand their purpose. Each r hasSuggestions: true }) }} -{%- for type in rules.types -%} +{%- for type, content in rules.types -%} -

{{ type.displayName }}

+

{{ rules_categories[type].displayName }}

-{{ type.description | safe }} +{{ rules_categories[type].description | safe }} - {%- for the_rule in type.rules -%} - {%- if type.displayName == 'deprecated' -%}{%- set deprecated_value = true -%}{%- endif -%} + {%- for the_rule in content -%} + + {%- if rules_categories[type].displayName == 'deprecated' -%} + {%- set deprecated_value = true -%} + {%- endif -%} {%- set name_value = the_rule.name -%} {%- set description_value = the_rule.description -%} @@ -50,11 +53,11 @@ Rules in ESLint are grouped by type to help you understand their purpose. Each r {%- if rules.deprecated -%} -

{{ rules.deprecated.name }}

+

{{ rules_categories.deprecated.displayName }}

-{{ rules.deprecated.description | safe }} +{{ rules_categories.deprecated.description | safe }} -{%- for the_rule in rules.deprecated.rules -%} +{%- for the_rule in rules.deprecated -%} {%- set name_value = the_rule.name -%} {%- set isReplacedBy = the_rule.replacedBy -%} @@ -68,11 +71,11 @@ Rules in ESLint are grouped by type to help you understand their purpose. Each r {%- if rules.removed -%} -

{{ rules.removed.name }}

+

{{ rules_categories.removed.displayName }}

-{{ rules.removed.description | safe }} +{{ rules_categories.removed.description | safe }} -{%- for the_rule in rules.removed.rules -%} +{%- for the_rule in rules.removed -%} {%- set name_value = the_rule.removed -%} {%- set isReplacedBy = the_rule.replacedBy -%} From 61b90839633ef300ac7707a651f65f532e65f42d Mon Sep 17 00:00:00 2001 From: Zhongyuan Zhou Date: Wed, 11 Oct 2023 23:40:58 +0800 Subject: [PATCH 08/24] docs: Make no-continue example code work (#17643) Update no-continue.md make code works without errors --- docs/src/rules/no-continue.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/src/rules/no-continue.md b/docs/src/rules/no-continue.md index af5cd8f98f16..fd0df533dec2 100644 --- a/docs/src/rules/no-continue.md +++ b/docs/src/rules/no-continue.md @@ -15,7 +15,7 @@ for(i = 0; i < 10; i++) { continue; } - a += i; + sum += i; } ``` @@ -38,7 +38,7 @@ for(i = 0; i < 10; i++) { continue; } - a += i; + sum += i; } ``` @@ -57,7 +57,7 @@ labeledLoop: for(i = 0; i < 10; i++) { continue labeledLoop; } - a += i; + sum += i; } ``` @@ -75,7 +75,7 @@ var sum = 0, for(i = 0; i < 10; i++) { if(i < 5) { - a += i; + sum += i; } } ``` From 0bcb9a8db608a3d0bd2645f99e0707b9a9bbaaf0 Mon Sep 17 00:00:00 2001 From: Francesco Trotta Date: Wed, 11 Oct 2023 22:39:57 +0200 Subject: [PATCH 09/24] docs: Fix syntax errors in rule examples (#17633) * Fix code examples in rule docs * Update `id-length` * Restore example in `id-match` under option `properties` * Update docs/src/rules/constructor-super.md Co-authored-by: Nicholas C. Zakas * Update docs/src/rules/no-useless-rename.md Co-authored-by: Milos Djermanovic --------- Co-authored-by: Nicholas C. Zakas Co-authored-by: Milos Djermanovic --- docs/src/rules/arrow-body-style.md | 28 ++-- docs/src/rules/camelcase.md | 18 +-- docs/src/rules/class-methods-use-this.md | 4 +- docs/src/rules/constructor-super.md | 22 ++-- docs/src/rules/id-denylist.md | 28 ++-- docs/src/rules/id-length.md | 48 +++---- docs/src/rules/id-match.md | 18 +-- docs/src/rules/indent-legacy.md | 120 +++++++++--------- docs/src/rules/indent.md | 80 ++++++------ docs/src/rules/jsx-quotes.md | 24 ++-- docs/src/rules/keyword-spacing.md | 34 ++--- docs/src/rules/lines-around-comment.md | 2 +- docs/src/rules/lines-between-class-members.md | 16 ++- docs/src/rules/max-params.md | 8 +- docs/src/rules/max-statements.md | 4 +- docs/src/rules/newline-after-var.md | 24 ++-- docs/src/rules/no-dupe-class-members.md | 20 +-- docs/src/rules/no-empty-static-block.md | 2 +- docs/src/rules/no-extra-parens.md | 22 ++-- docs/src/rules/no-invalid-this.md | 4 +- docs/src/rules/no-loss-of-precision.md | 26 ++-- .../rules/no-misleading-character-class.md | 34 ++--- docs/src/rules/no-multi-assign.md | 10 +- docs/src/rules/no-restricted-exports.md | 27 ++++ docs/src/rules/no-restricted-imports.md | 2 +- docs/src/rules/no-sequences.md | 8 +- docs/src/rules/no-this-before-super.md | 14 +- docs/src/rules/no-underscore-dangle.md | 52 ++++---- docs/src/rules/no-unexpected-multiline.md | 6 +- .../rules/no-unused-private-class-members.md | 16 +-- docs/src/rules/no-useless-constructor.md | 6 +- docs/src/rules/no-useless-rename.md | 43 ++++--- docs/src/rules/object-curly-newline.md | 14 +- .../src/rules/one-var-declaration-per-line.md | 20 +-- docs/src/rules/one-var.md | 14 +- docs/src/rules/prefer-const.md | 52 ++++---- docs/src/rules/prefer-destructuring.md | 11 +- docs/src/rules/require-unicode-regexp.md | 2 +- docs/src/rules/rest-spread-spacing.md | 16 +-- docs/src/rules/sort-imports.md | 56 +++++++- docs/src/rules/sort-keys.md | 80 ++++++------ docs/src/rules/space-before-keywords.md | 6 +- docs/src/rules/space-infix-ops.md | 4 +- 43 files changed, 580 insertions(+), 465 deletions(-) diff --git a/docs/src/rules/arrow-body-style.md b/docs/src/rules/arrow-body-style.md index 1975af13eed9..1bfdb5a73084 100644 --- a/docs/src/rules/arrow-body-style.md +++ b/docs/src/rules/arrow-body-style.md @@ -45,7 +45,7 @@ Examples of **correct** code for this rule with the `"always"` option: let foo = () => { return 0; }; -let foo = (retv, name) => { +let bar = (retv, name) => { retv[name] = true; return retv; }; @@ -66,7 +66,7 @@ Examples of **incorrect** code for this rule with the default `"as-needed"` opti let foo = () => { return 0; }; -let foo = () => { +let bar = () => { return { bar: { foo: 1, @@ -86,24 +86,24 @@ Examples of **correct** code for this rule with the default `"as-needed"` option /*eslint arrow-body-style: ["error", "as-needed"]*/ /*eslint-env es6*/ -let foo = () => 0; -let foo = (retv, name) => { +let foo1 = () => 0; +let foo2 = (retv, name) => { retv[name] = true; return retv; }; -let foo = () => ({ +let foo3 = () => ({ bar: { foo: 1, bar: 2, } }); -let foo = () => { bar(); }; -let foo = () => {}; -let foo = () => { /* do nothing */ }; -let foo = () => { +let foo4 = () => { bar(); }; +let foo5 = () => {}; +let foo6 = () => { /* do nothing */ }; +let foo7 = () => { // do nothing. }; -let foo = () => ({ bar: 0 }); +let foo8 = () => ({ bar: 0 }); ``` ::: @@ -120,7 +120,7 @@ Examples of **incorrect** code for this rule with the `{ "requireReturnForObject /*eslint arrow-body-style: ["error", "as-needed", { "requireReturnForObjectLiteral": true }]*/ /*eslint-env es6*/ let foo = () => ({}); -let foo = () => ({ bar: 0 }); +let bar = () => ({ bar: 0 }); ``` ::: @@ -134,7 +134,7 @@ Examples of **correct** code for this rule with the `{ "requireReturnForObjectLi /*eslint-env es6*/ let foo = () => {}; -let foo = () => { return { bar: 0 }; }; +let bar = () => { return { bar: 0 }; }; ``` ::: @@ -152,7 +152,7 @@ Examples of **incorrect** code for this rule with the `"never"` option: let foo = () => { return 0; }; -let foo = (retv, name) => { +let bar = (retv, name) => { retv[name] = true; return retv; }; @@ -169,7 +169,7 @@ Examples of **correct** code for this rule with the `"never"` option: /*eslint-env es6*/ let foo = () => 0; -let foo = () => ({ foo: 0 }); +let bar = () => ({ foo: 0 }); ``` ::: diff --git a/docs/src/rules/camelcase.md b/docs/src/rules/camelcase.md index aa75b231becd..536fba9439b8 100644 --- a/docs/src/rules/camelcase.md +++ b/docs/src/rules/camelcase.md @@ -49,11 +49,11 @@ function foo({ no_camelcased }) { // ... }; -function foo({ isCamelcased: no_camelcased }) { +function bar({ isCamelcased: no_camelcased }) { // ... } -function foo({ no_camelcased = 'default value' }) { +function baz({ no_camelcased = 'default value' }) { // ... }; @@ -63,7 +63,7 @@ var obj = { var { category_id = 1 } = query; -var { foo: no_camelcased } = bar; +var { foo: snake_cased } = bar; var { foo: bar_baz = 1 } = quz; ``` @@ -83,8 +83,8 @@ var myFavoriteColor = "#112C85"; var _myFavoriteColor = "#112C85"; var myFavoriteColor_ = "#112C85"; var MY_FAVORITE_COLOR = "#112C85"; -var foo = bar.baz_boom; -var foo = { qux: bar.baz_boom }; +var foo1 = bar.baz_boom; +var foo2 = { qux: bar.baz_boom }; obj.do_something(); do_something(); @@ -96,11 +96,11 @@ function foo({ isCamelCased }) { // ... }; -function foo({ isCamelCased: isAlsoCamelCased }) { +function bar({ isCamelCased: isAlsoCamelCased }) { // ... } -function foo({ isCamelCased = 'default value' }) { +function baz({ isCamelCased = 'default value' }) { // ... }; @@ -143,9 +143,9 @@ Examples of **incorrect** code for this rule with the default `{ "ignoreDestruct var { category_id } = query; -var { category_id = 1 } = query; +var { category_name = 1 } = query; -var { category_id: category_id } = query; +var { category_id: category_title } = query; var { category_id: category_alias } = query; diff --git a/docs/src/rules/class-methods-use-this.md b/docs/src/rules/class-methods-use-this.md index 2269fac8effd..5a12f9af3c93 100644 --- a/docs/src/rules/class-methods-use-this.md +++ b/docs/src/rules/class-methods-use-this.md @@ -86,13 +86,13 @@ class A { } } -class A { +class B { constructor() { // OK. constructor is exempt } } -class A { +class C { static foo() { // OK. static methods aren't expected to use this. } diff --git a/docs/src/rules/constructor-super.md b/docs/src/rules/constructor-super.md index 7c19df77dbab..c6f008f13d6d 100644 --- a/docs/src/rules/constructor-super.md +++ b/docs/src/rules/constructor-super.md @@ -14,6 +14,16 @@ This rule checks whether or not there is a valid `super()` call. This rule is aimed to flag invalid/missing `super()` calls. +This is a syntax error because there is no `extends` clause in the class: + +```js +class A { + constructor() { + super(); + } +} +``` + Examples of **incorrect** code for this rule: :::incorrect @@ -22,24 +32,18 @@ Examples of **incorrect** code for this rule: /*eslint constructor-super: "error"*/ /*eslint-env es6*/ -class A { - constructor() { - super(); // This is a SyntaxError. - } -} - class A extends B { constructor() { } // Would throw a ReferenceError. } // Classes which inherits from a non constructor are always problems. -class A extends null { +class C extends null { constructor() { super(); // Would throw a TypeError. } } -class A extends null { +class D extends null { constructor() { } // Would throw a ReferenceError. } ``` @@ -58,7 +62,7 @@ class A { constructor() { } } -class A extends B { +class B extends C { constructor() { super(); } diff --git a/docs/src/rules/id-denylist.md b/docs/src/rules/id-denylist.md index 850f5923e830..82859ec8b430 100644 --- a/docs/src/rules/id-denylist.md +++ b/docs/src/rules/id-denylist.md @@ -46,7 +46,7 @@ Examples of **incorrect** code for this rule with sample `"data", "callback"` re ```js /*eslint id-denylist: ["error", "data", "callback"] */ -var data = {...}; +var data = { ...values }; function callback() { // ... @@ -57,23 +57,23 @@ element.callback = function() { }; var itemSet = { - data: [...] + data: [...values] }; class Foo { data = []; } -class Foo { +class Bar { #data = []; } -class Foo { - callback( {); +class Baz { + callback() {} } -class Foo { - #callback( {); +class Qux { + #callback() {} } ``` @@ -86,7 +86,7 @@ Examples of **correct** code for this rule with sample `"data", "callback"` rest ```js /*eslint id-denylist: ["error", "data", "callback"] */ -var encodingOptions = {...}; +var encodingOptions = {...values}; function processFileResult() { // ... @@ -97,7 +97,7 @@ element.successHandler = function() { }; var itemSet = { - entities: [...] + entities: [...values] }; callback(); // all function calls are ignored @@ -110,16 +110,16 @@ class Foo { items = []; } -class Foo { +class Bar { #items = []; } -class Foo { - method( {); +class Baz { + method() {} } -class Foo { - #method( {); +class Qux { + #method() {} } ``` diff --git a/docs/src/rules/id-length.md b/docs/src/rules/id-length.md index aed5ada0a7c6..ea5d2fa9d1ab 100644 --- a/docs/src/rules/id-length.md +++ b/docs/src/rules/id-length.md @@ -41,16 +41,16 @@ try { } var myObj = { a: 1 }; (a) => { a * a }; -class x { } +class y { } class Foo { x() {} } -class Foo { #x() {} } -class Foo { x = 1 } -class Foo { #x = 1 } -function foo(...x) { } -function foo([x]) { } +class Bar { #x() {} } +class Baz { x = 1 } +class Qux { #x = 1 } +function bar(...x) { } +function baz([x]) { } var [x] = arr; var { prop: [x]} = {}; -function foo({x}) { } +function qux({x}) { } var { x } = {}; var { prop: a} = {}; ({ prop: obj.x } = {}); @@ -78,19 +78,19 @@ try { } var myObj = { apple: 1 }; (num) => { num * num }; -function foo(num = 0) { } +function bar(num = 0) { } class MyClass { } class Foo { method() {} } -class Foo { #method() {} } -class Foo { field = 1 } -class Foo { #field = 1 } -function foo(...args) { } -function foo([longName]) { } +class Bar { #method() {} } +class Baz { field = 1 } +class Qux { #field = 1 } +function baz(...args) { } +function qux([longName]) { } var { prop } = {}; var { prop: [longName] } = {}; var [longName] = arr; -function foo({ prop }) { } -function foo({ a: prop }) { } +function foobar({ prop }) { } +function foobaz({ a: prop }) { } var { prop } = {}; var { a: prop } = {}; ({ prop: obj.longName } = {}); @@ -129,9 +129,9 @@ try { } var myObj = { a: 1 }; (val) => { val * val }; -class x { } +class y { } class Foo { x() {} } -function foo(...x) { } +function bar(...x) { } var { x } = {}; var { prop: a} = {}; var [x] = arr; @@ -151,7 +151,7 @@ Examples of **correct** code for this rule with the `{ "min": 4 }` option: var value = 5; function func() { return 42; } -obj.element = document.body; +object.element = document.body; var foobar = function (event) { /* do stuff */ }; try { dangerousStuff(); @@ -168,7 +168,7 @@ var { prop } = {}; var [longName] = foo; var { a: [prop] } = {}; var { a: longName } = {}; -({ prop: obj.name } = {}); +({ prop: object.name } = {}); var data = { "x": 1 }; // excused because of quotes data["y"] = 3; // excused because of calculated property access ``` @@ -242,16 +242,16 @@ var myObj = { a: 1 }; ### exceptions -Examples of additional **correct** code for this rule with the `{ "exceptions": ["x"] }` option: +Examples of additional **correct** code for this rule with the `{ "exceptions": ["x", "y", "z", "ζ"] }` option: ::: correct ```js -/*eslint id-length: ["error", { "exceptions": ["x"] }]*/ +/*eslint id-length: ["error", { "exceptions": ["x", "y", "z", "ζ"] }]*/ /*eslint-env es6*/ var x = 5; -function x() { return 42; } +function y() { return 42; } obj.x = document.body; var foo = function (x) { /* do stuff */ }; try { @@ -261,8 +261,8 @@ try { } (x) => { return x * x; }; var [x] = arr; -const { x } = foo; -const { a: x } = foo; +const { z } = foo; +const { a: ζ } = foo; ``` ::: diff --git a/docs/src/rules/id-match.md b/docs/src/rules/id-match.md index 08d5ff3ba9c4..6d15d19e859b 100644 --- a/docs/src/rules/id-match.md +++ b/docs/src/rules/id-match.md @@ -42,17 +42,13 @@ function do_something() { // ... } -obj.do_something = function() { - // ... -}; - class My_Class {} class myClass { do_something() {} } -class myClass { +class anotherClass { #do_something() {} } ``` @@ -76,11 +72,11 @@ var obj = { class myClass {} -class myClass { +class anotherClass { doSomething() {} } -class myClass { +class oneMoreClass { #doSomething() {} } ``` @@ -110,6 +106,10 @@ Examples of **incorrect** code for this rule with the `"^[a-z]+([A-Z][a-z]+)*$", var obj = { my_pref: 1 }; + +obj.do_something = function() { + // ... +}; ``` ::: @@ -121,13 +121,13 @@ Examples of **incorrect** code for this rule with the `"^[a-z]+([A-Z][a-z]+)*$", ::: incorrect ```js -/*eslint id-match: ["error", "^[a-z]+([A-Z][a-z]+)*$", { "properties": true }]*/ +/*eslint id-match: ["error", "^[a-z]+([A-Z][a-z]+)*$", { "classFields": true }]*/ class myClass { my_pref = 1; } -class myClass { +class anotherClass { #my_pref = 1; } ``` diff --git a/docs/src/rules/indent-legacy.md b/docs/src/rules/indent-legacy.md index 97372ebc8ff0..c3543133be4c 100644 --- a/docs/src/rules/indent-legacy.md +++ b/docs/src/rules/indent-legacy.md @@ -39,7 +39,7 @@ For example, for 2-space indentation: ```json { - "indent": ["error", 2] + "indent-legacy": ["error", 2] } ``` @@ -47,7 +47,7 @@ Or for tabbed indentation: ```json { - "indent": ["error", "tab"] + "indent-legacy": ["error", "tab"] } ``` @@ -56,7 +56,7 @@ Examples of **incorrect** code for this rule with the default options: ::: incorrect ```js -/*eslint indent: "error"*/ +/*eslint indent-legacy: "error"*/ if (a) { b=c; @@ -73,7 +73,7 @@ Examples of **correct** code for this rule with the default options: ::: correct ```js -/*eslint indent: "error"*/ +/*eslint indent-legacy: "error"*/ if (a) { b=c; @@ -126,7 +126,7 @@ Examples of **incorrect** code for this rule with the `"tab"` option: ::: incorrect ```js -/*eslint indent: ["error", "tab"]*/ +/*eslint indent-legacy: ["error", "tab"]*/ if (a) { b=c; @@ -143,7 +143,7 @@ Examples of **correct** code for this rule with the `"tab"` option: ::: correct ```js -/*eslint indent: ["error", "tab"]*/ +/*eslint indent-legacy: ["error", "tab"]*/ if (a) { /*tab*/b=c; @@ -162,7 +162,7 @@ Examples of **incorrect** code for this rule with the `2, { "SwitchCase": 1 }` o ::: incorrect ```js -/*eslint indent: ["error", 2, { "SwitchCase": 1 }]*/ +/*eslint indent-legacy: ["error", 2, { "SwitchCase": 1 }]*/ switch(a){ case "a": @@ -179,7 +179,7 @@ Examples of **correct** code for this rule with the `2, { "SwitchCase": 1 }` opt ::: correct ```js -/*eslint indent: ["error", 2, { "SwitchCase": 1 }]*/ +/*eslint indent-legacy: ["error", 2, { "SwitchCase": 1 }]*/ switch(a){ case "a": @@ -198,18 +198,18 @@ Examples of **incorrect** code for this rule with the `2, { "VariableDeclarator" ::: incorrect ```js -/*eslint indent: ["error", 2, { "VariableDeclarator": 1 }]*/ +/*eslint indent-legacy: ["error", 2, { "VariableDeclarator": 1 }]*/ /*eslint-env es6*/ var a, b, c; -let a, - b, - c; -const a = 1, - b = 2, - c = 3; +let d, + e, + f; +const g = 1, + h = 2, + i = 3; ``` ::: @@ -219,18 +219,18 @@ Examples of **correct** code for this rule with the `2, { "VariableDeclarator": ::: correct ```js -/*eslint indent: ["error", 2, { "VariableDeclarator": 1 }]*/ +/*eslint indent-legacy: ["error", 2, { "VariableDeclarator": 1 }]*/ /*eslint-env es6*/ var a, b, c; -let a, - b, - c; -const a = 1, - b = 2, - c = 3; +let d, + e, + f; +const g = 1, + h = 2, + i = 3; ``` ::: @@ -240,18 +240,18 @@ Examples of **correct** code for this rule with the `2, { "VariableDeclarator": ::: correct ```js -/*eslint indent: ["error", 2, { "VariableDeclarator": 2 }]*/ +/*eslint indent-legacy: ["error", 2, { "VariableDeclarator": 2 }]*/ /*eslint-env es6*/ var a, b, c; -let a, - b, - c; -const a = 1, - b = 2, - c = 3; +let d, + e, + f; +const g = 1, + h = 2, + i = 3; ``` ::: @@ -261,18 +261,18 @@ Examples of **correct** code for this rule with the `2, { "VariableDeclarator": ::: correct ```js -/*eslint indent: ["error", 2, { "VariableDeclarator": { "var": 2, "let": 2, "const": 3 } }]*/ +/*eslint indent-legacy: ["error", 2, { "VariableDeclarator": { "var": 2, "let": 2, "const": 3 } }]*/ /*eslint-env es6*/ var a, b, c; -let a, - b, - c; -const a = 1, - b = 2, - c = 3; +let e, + f, + g; +const h = 1, + i = 2, + j = 3; ``` ::: @@ -284,7 +284,7 @@ Examples of **incorrect** code for this rule with the options `2, { "outerIIFEBo ::: incorrect ```js -/*eslint indent: ["error", 2, { "outerIIFEBody": 0 }]*/ +/*eslint indent-legacy: ["error", 2, { "outerIIFEBody": 0 }]*/ (function() { @@ -306,7 +306,7 @@ Examples of **correct** code for this rule with the options `2, {"outerIIFEBody" ::: correct ```js -/*eslint indent: ["error", 2, { "outerIIFEBody": 0 }]*/ +/*eslint indent-legacy: ["error", 2, { "outerIIFEBody": 0 }]*/ (function() { @@ -330,7 +330,7 @@ Examples of **incorrect** code for this rule with the `2, { "MemberExpression": ::: incorrect ```js -/*eslint indent: ["error", 2, { "MemberExpression": 1 }]*/ +/*eslint indent-legacy: ["error", 2, { "MemberExpression": 1 }]*/ foo .bar @@ -344,7 +344,7 @@ Examples of **correct** code for this rule with the `2, { "MemberExpression": 1 ::: correct ```js -/*eslint indent: ["error", 2, { "MemberExpression": 1 }]*/ +/*eslint indent-legacy: ["error", 2, { "MemberExpression": 1 }]*/ foo .bar @@ -364,7 +364,7 @@ Examples of **incorrect** code for this rule with the `2, { "FunctionDeclaration ::: incorrect ```js -/*eslint indent: ["error", 2, { "FunctionDeclaration": {"body": 1, "parameters": 2} }]*/ +/*eslint indent-legacy: ["error", 2, { "FunctionDeclaration": {"body": 1, "parameters": 2} }]*/ function foo(bar, baz, @@ -380,7 +380,7 @@ Examples of **correct** code for this rule with the `2, { "FunctionDeclaration": ::: correct ```js -/*eslint indent: ["error", 2, { "FunctionDeclaration": {"body": 1, "parameters": 2} }]*/ +/*eslint indent-legacy: ["error", 2, { "FunctionDeclaration": {"body": 1, "parameters": 2} }]*/ function foo(bar, baz, @@ -396,7 +396,7 @@ Examples of **incorrect** code for this rule with the `2, { "FunctionDeclaration ::: incorrect ```js -/*eslint indent: ["error", 2, {"FunctionDeclaration": {"parameters": "first"}}]*/ +/*eslint indent-legacy: ["error", 2, {"FunctionDeclaration": {"parameters": "first"}}]*/ function foo(bar, baz, qux, boop) { @@ -411,7 +411,7 @@ Examples of **correct** code for this rule with the `2, { "FunctionDeclaration": ::: correct ```js -/*eslint indent: ["error", 2, {"FunctionDeclaration": {"parameters": "first"}}]*/ +/*eslint indent-legacy: ["error", 2, {"FunctionDeclaration": {"parameters": "first"}}]*/ function foo(bar, baz, qux, boop) { @@ -428,7 +428,7 @@ Examples of **incorrect** code for this rule with the `2, { "FunctionExpression" ::: incorrect ```js -/*eslint indent: ["error", 2, { "FunctionExpression": {"body": 1, "parameters": 2} }]*/ +/*eslint indent-legacy: ["error", 2, { "FunctionExpression": {"body": 1, "parameters": 2} }]*/ var foo = function(bar, baz, @@ -444,7 +444,7 @@ Examples of **correct** code for this rule with the `2, { "FunctionExpression": ::: correct ```js -/*eslint indent: ["error", 2, { "FunctionExpression": {"body": 1, "parameters": 2} }]*/ +/*eslint indent-legacy: ["error", 2, { "FunctionExpression": {"body": 1, "parameters": 2} }]*/ var foo = function(bar, baz, @@ -460,7 +460,7 @@ Examples of **incorrect** code for this rule with the `2, { "FunctionExpression" ::: incorrect ```js -/*eslint indent: ["error", 2, {"FunctionExpression": {"parameters": "first"}}]*/ +/*eslint indent-legacy: ["error", 2, {"FunctionExpression": {"parameters": "first"}}]*/ var foo = function(bar, baz, qux, boop) { @@ -475,7 +475,7 @@ Examples of **correct** code for this rule with the `2, { "FunctionExpression": ::: correct ```js -/*eslint indent: ["error", 2, {"FunctionExpression": {"parameters": "first"}}]*/ +/*eslint indent-legacy: ["error", 2, {"FunctionExpression": {"parameters": "first"}}]*/ var foo = function(bar, baz, qux, boop) { @@ -492,7 +492,7 @@ Examples of **incorrect** code for this rule with the `2, { "CallExpression": {" ::: incorrect ```js -/*eslint indent: ["error", 2, { "CallExpression": {"arguments": 1} }]*/ +/*eslint indent-legacy: ["error", 2, { "CallExpression": {"arguments": 1} }]*/ foo(bar, baz, @@ -507,7 +507,7 @@ Examples of **correct** code for this rule with the `2, { "CallExpression": {"ar ::: correct ```js -/*eslint indent: ["error", 2, { "CallExpression": {"arguments": 1} }]*/ +/*eslint indent-legacy: ["error", 2, { "CallExpression": {"arguments": 1} }]*/ foo(bar, baz, @@ -522,7 +522,7 @@ Examples of **incorrect** code for this rule with the `2, { "CallExpression": {" ::: incorrect ```js -/*eslint indent: ["error", 2, {"CallExpression": {"arguments": "first"}}]*/ +/*eslint indent-legacy: ["error", 2, {"CallExpression": {"arguments": "first"}}]*/ foo(bar, baz, baz, boop, beep); @@ -535,7 +535,7 @@ Examples of **correct** code for this rule with the `2, { "CallExpression": {"ar ::: correct ```js -/*eslint indent: ["error", 2, {"CallExpression": {"arguments": "first"}}]*/ +/*eslint indent-legacy: ["error", 2, {"CallExpression": {"arguments": "first"}}]*/ foo(bar, baz, baz, boop, beep); @@ -550,7 +550,7 @@ Examples of **incorrect** code for this rule with the `2, { "ArrayExpression": 1 ::: incorrect ```js -/*eslint indent: ["error", 2, { "ArrayExpression": 1 }]*/ +/*eslint indent-legacy: ["error", 2, { "ArrayExpression": 1 }]*/ var foo = [ bar, @@ -566,7 +566,7 @@ Examples of **correct** code for this rule with the `2, { "ArrayExpression": 1 } ::: correct ```js -/*eslint indent: ["error", 2, { "ArrayExpression": 1 }]*/ +/*eslint indent-legacy: ["error", 2, { "ArrayExpression": 1 }]*/ var foo = [ bar, @@ -582,7 +582,7 @@ Examples of **incorrect** code for this rule with the `2, { "ArrayExpression": " ::: incorrect ```js -/*eslint indent: ["error", 2, {"ArrayExpression": "first"}]*/ +/*eslint indent-legacy: ["error", 2, {"ArrayExpression": "first"}]*/ var foo = [bar, baz, @@ -597,7 +597,7 @@ Examples of **correct** code for this rule with the `2, { "ArrayExpression": "fi ::: correct ```js -/*eslint indent: ["error", 2, {"ArrayExpression": "first"}]*/ +/*eslint indent-legacy: ["error", 2, {"ArrayExpression": "first"}]*/ var foo = [bar, baz, @@ -614,7 +614,7 @@ Examples of **incorrect** code for this rule with the `2, { "ObjectExpression": ::: incorrect ```js -/*eslint indent: ["error", 2, { "ObjectExpression": 1 }]*/ +/*eslint indent-legacy: ["error", 2, { "ObjectExpression": 1 }]*/ var foo = { bar: 1, @@ -630,7 +630,7 @@ Examples of **correct** code for this rule with the `2, { "ObjectExpression": 1 ::: correct ```js -/*eslint indent: ["error", 2, { "ObjectExpression": 1 }]*/ +/*eslint indent-legacy: ["error", 2, { "ObjectExpression": 1 }]*/ var foo = { bar: 1, @@ -646,7 +646,7 @@ Examples of **incorrect** code for this rule with the `2, { "ObjectExpression": ::: incorrect ```js -/*eslint indent: ["error", 2, {"ObjectExpression": "first"}]*/ +/*eslint indent-legacy: ["error", 2, {"ObjectExpression": "first"}]*/ var foo = { bar: 1, baz: 2 }; @@ -659,7 +659,7 @@ Examples of **correct** code for this rule with the `2, { "ObjectExpression": "f ::: correct ```js -/*eslint indent: ["error", 2, {"ObjectExpression": "first"}]*/ +/*eslint indent-legacy: ["error", 2, {"ObjectExpression": "first"}]*/ var foo = { bar: 1, baz: 2 }; diff --git a/docs/src/rules/indent.md b/docs/src/rules/indent.md index 7f81c0fd57bc..e53a1f9a6e1b 100644 --- a/docs/src/rules/indent.md +++ b/docs/src/rules/indent.md @@ -248,12 +248,12 @@ Examples of **incorrect** code for this rule with the `2, { "VariableDeclarator" var a, b, c; -let a, - b, - c; -const a = 1, - b = 2, - c = 3; +let d, + e, + f; +const g = 1, + h = 2, + i = 3; ``` ::: @@ -269,12 +269,12 @@ Examples of **correct** code for this rule with the `2, { "VariableDeclarator": var a, b, c; -let a, - b, - c; -const a = 1, - b = 2, - c = 3; +let d, + e, + f; +const g = 1, + h = 2, + i = 3; ``` ::: @@ -290,12 +290,12 @@ Examples of **correct** code for this rule with the `2, { "VariableDeclarator": var a, b, c; -let a, - b, - c; -const a = 1, - b = 2, - c = 3; +let d, + e, + f; +const g = 1, + h = 2, + i = 3; ``` ::: @@ -311,12 +311,12 @@ Examples of **incorrect** code for this rule with the `2, { "VariableDeclarator" var a, b, c; -let a, - b, - c; -const a = 1, - b = 2, - c = 3; +let d, + e, + f; +const g = 1, + h = 2, + i = 3; ``` ::: @@ -332,12 +332,12 @@ Examples of **correct** code for this rule with the `2, { "VariableDeclarator": var a, b, c; -let a, - b, - c; -const a = 1, - b = 2, - c = 3; +let d, + e, + f; +const g = 1, + h = 2, + i = 3; ``` ::: @@ -353,12 +353,12 @@ Examples of **correct** code for this rule with the `2, { "VariableDeclarator": var a, b, c; -let a, - b, - c; -const a = 1, - b = 2, - c = 3; +let d, + e, + f; +const g = 1, + h = 2, + i = 3; ``` ::: @@ -858,6 +858,14 @@ import { foo, bar, baz, } from 'qux'; +``` + +::: + +::: correct + +```js +/*eslint indent: ["error", 4, { "ImportDeclaration": 1 }]*/ import { foo, diff --git a/docs/src/rules/jsx-quotes.md b/docs/src/rules/jsx-quotes.md index ddb20002b8a0..4e0799687550 100644 --- a/docs/src/rules/jsx-quotes.md +++ b/docs/src/rules/jsx-quotes.md @@ -9,17 +9,17 @@ related_rules: JSX attribute values can contain string literals, which are delimited with single or double quotes. -```xml - - +```jsx +; +; ``` Unlike string literals in JavaScript, string literals within JSX attributes can’t contain escaped quotes. If you want to have e.g. a double quote within a JSX attribute value, you have to use single quotes as string delimiter. -```xml - - +```jsx +; +; ``` ## Rule Details @@ -42,7 +42,7 @@ Examples of **incorrect** code for this rule with the default `"prefer-double"` ```jsx /*eslint jsx-quotes: ["error", "prefer-double"]*/ - +; ``` ::: @@ -54,8 +54,8 @@ Examples of **correct** code for this rule with the default `"prefer-double"` op ```jsx /*eslint jsx-quotes: ["error", "prefer-double"]*/ - - +; +; ``` ::: @@ -69,7 +69,7 @@ Examples of **incorrect** code for this rule with the `"prefer-single"` option: ```jsx /*eslint jsx-quotes: ["error", "prefer-single"]*/ - +; ``` ::: @@ -81,8 +81,8 @@ Examples of **correct** code for this rule with the `"prefer-single"` option: ```jsx /*eslint jsx-quotes: ["error", "prefer-single"]*/ - - +; +; ``` ::: diff --git a/docs/src/rules/keyword-spacing.md b/docs/src/rules/keyword-spacing.md index 9c1ca55fc380..0ffe1e13df63 100644 --- a/docs/src/rules/keyword-spacing.md +++ b/docs/src/rules/keyword-spacing.md @@ -77,30 +77,30 @@ let a = [this]; let b = [function() {}]; // Avoid conflict with `arrow-spacing` -let a = ()=> this.foo; +let c = ()=> this.foo; // Avoid conflict with `block-spacing` {function foo() {}} // Avoid conflict with `comma-spacing` -let a = [100,this.foo, this.bar]; +let d = [100,this.foo, this.bar]; // Avoid conflict with `computed-property-spacing` obj[this.foo] = 0; // Avoid conflict with `generator-star-spacing` -function *foo() {} +function *bar() {} // Avoid conflict with `key-spacing` -let obj = { +let obj1 = { foo:function() {} }; // Avoid conflict with `object-curly-spacing` -let obj = {foo: this}; +let obj2 = {foo: this}; // Avoid conflict with `semi-spacing` -let a = this;function foo() {} +let e = this;function foo() {} // Avoid conflict with `space-in-parens` (function () {})(); @@ -110,7 +110,7 @@ if ("foo"in {foo: 0}) {} if (10+this.foo<= this.bar) {} // Avoid conflict with `jsx-curly-spacing` -let a = +let f = ``` ::: @@ -190,10 +190,10 @@ if (foo) { let a = [this]; // Avoid conflict with `arrow-spacing` -let a = ()=> this.foo; +let b = ()=> this.foo; // Avoid conflict with `comma-spacing` -let a = [100, this.foo, this.bar]; +let c = [100, this.foo, this.bar]; // Avoid conflict with `computed-property-spacing` obj[this.foo] = 0; @@ -202,42 +202,42 @@ obj[this.foo] = 0; function* foo() {} // Avoid conflict with `key-spacing` -let obj = { +let obj1 = { foo:function() {} }; // Avoid conflict with `func-call-spacing` -class A { +class A extends B { constructor() { super(); } } // Avoid conflict with `object-curly-spacing` -let obj = {foo: this}; +let obj2 = {foo: this}; // Avoid conflict with `semi-spacing` -let a = this;function foo() {} +let d = this;function bar() {} // Avoid conflict with `space-before-function-paren` -function() {} +(function() {})(); // Avoid conflict with `space-infix-ops` if ("foo"in{foo: 0}) {} if (10+this.foo<= this.bar) {} // Avoid conflict with `space-unary-ops` -function* foo(a) { +function* baz(a) { return yield+a; } // Avoid conflict with `yield-star-spacing` -function* foo(a) { +function* qux(a) { return yield* a; } // Avoid conflict with `jsx-curly-spacing` -let a = +let e = ``` ::: diff --git a/docs/src/rules/lines-around-comment.md b/docs/src/rules/lines-around-comment.md index 924ba66cf1a4..0cafa6df7036 100644 --- a/docs/src/rules/lines-around-comment.md +++ b/docs/src/rules/lines-around-comment.md @@ -663,7 +663,7 @@ Examples of **correct** code for the `ignorePattern` option: /*eslint lines-around-comment: ["error"]*/ foo(); -/* eslint mentioned in this comment */, +/* eslint mentioned in this comment */ bar(); /*eslint lines-around-comment: ["error", { "ignorePattern": "pragma" }] */ diff --git a/docs/src/rules/lines-between-class-members.md b/docs/src/rules/lines-between-class-members.md index 55627501096a..42c20b92ddda 100644 --- a/docs/src/rules/lines-between-class-members.md +++ b/docs/src/rules/lines-between-class-members.md @@ -97,9 +97,15 @@ class Foo{ bar(){} baz(){} } +``` + +::: +::: incorrect + +```js /* eslint lines-between-class-members: ["error", "never"]*/ -class Foo{ +class Bar{ x; bar(){} @@ -123,9 +129,15 @@ class Foo{ baz(){} } +``` + +::: +::: correct + +```js /* eslint lines-between-class-members: ["error", "never"]*/ -class Foo{ +class Bar{ x; bar(){} baz(){} diff --git a/docs/src/rules/max-params.md b/docs/src/rules/max-params.md index 681723fb8117..b0a55e9009fa 100644 --- a/docs/src/rules/max-params.md +++ b/docs/src/rules/max-params.md @@ -42,11 +42,11 @@ Examples of **incorrect** code for this rule with the default `{ "max": 3 }` opt /*eslint max-params: ["error", 3]*/ /*eslint-env es6*/ -function foo (bar, baz, qux, qxx) { +function foo1 (bar, baz, qux, qxx) { doSomething(); } -let foo = (bar, baz, qux, qxx) => { +let foo2 = (bar, baz, qux, qxx) => { doSomething(); }; ``` @@ -61,11 +61,11 @@ Examples of **correct** code for this rule with the default `{ "max": 3 }` optio /*eslint max-params: ["error", 3]*/ /*eslint-env es6*/ -function foo (bar, baz, qux) { +function foo1 (bar, baz, qux) { doSomething(); } -let foo = (bar, baz, qux) => { +let foo2 = (bar, baz, qux) => { doSomething(); }; ``` diff --git a/docs/src/rules/max-statements.md b/docs/src/rules/max-statements.md index d41f7f2de4d3..4462011db742 100644 --- a/docs/src/rules/max-statements.md +++ b/docs/src/rules/max-statements.md @@ -63,7 +63,7 @@ function foo() { var foo11 = 11; // Too many. } -let foo = () => { +let bar = () => { var foo1 = 1; var foo2 = 2; var foo3 = 3; @@ -109,7 +109,7 @@ function foo() { }; } -let foo = () => { +let bar = () => { var foo1 = 1; var foo2 = 2; var foo3 = 3; diff --git a/docs/src/rules/newline-after-var.md b/docs/src/rules/newline-after-var.md index db11e25471c3..9d6dc216ecec 100644 --- a/docs/src/rules/newline-after-var.md +++ b/docs/src/rules/newline-after-var.md @@ -52,9 +52,9 @@ var greet = "hello,", name = "world"; console.log(greet, name); -let greet = "hello,", - name = "world"; -console.log(greet, name); +let hello = "hello,", + world = "world"; +console.log(hello, world); var greet = "hello,"; const NAME = "world"; @@ -81,10 +81,10 @@ var greet = "hello,", console.log(greet, name); -let greet = "hello,", - name = "world"; +let hello = "hello,", + world = "world"; -console.log(greet, name); +console.log(hello, world); var greet = "hello,"; const NAME = "world"; @@ -115,10 +115,10 @@ var greet = "hello,", console.log(greet, name); -let greet = "hello,", - name = "world"; +let hello = "hello,", + world = "world"; -console.log(greet, name); +console.log(hello, world); var greet = "hello,"; const NAME = "world"; @@ -146,9 +146,9 @@ var greet = "hello,", name = "world"; console.log(greet, name); -let greet = "hello,", - name = "world"; -console.log(greet, name); +let hello = "hello,", + world = "world"; +console.log(hello, world); var greet = "hello,"; const NAME = "world"; diff --git a/docs/src/rules/no-dupe-class-members.md b/docs/src/rules/no-dupe-class-members.md index 216f3c9fecd3..6565c9f15ee7 100644 --- a/docs/src/rules/no-dupe-class-members.md +++ b/docs/src/rules/no-dupe-class-members.md @@ -34,27 +34,27 @@ Examples of **incorrect** code for this rule: ```js /*eslint no-dupe-class-members: "error"*/ -class Foo { +class A { bar() { } bar() { } } -class Foo { +class B { bar() { } get bar() { } } -class Foo { +class C { bar; bar; } -class Foo { +class D { bar; bar() { } } -class Foo { +class E { static bar() { } static bar() { } } @@ -69,27 +69,27 @@ Examples of **correct** code for this rule: ```js /*eslint no-dupe-class-members: "error"*/ -class Foo { +class A { bar() { } qux() { } } -class Foo { +class B { get bar() { } set bar(value) { } } -class Foo { +class C { bar; qux; } -class Foo { +class D { bar; qux() { } } -class Foo { +class E { static bar() { } bar() { } } diff --git a/docs/src/rules/no-empty-static-block.md b/docs/src/rules/no-empty-static-block.md index 283a4e21b776..1825e5c78321 100644 --- a/docs/src/rules/no-empty-static-block.md +++ b/docs/src/rules/no-empty-static-block.md @@ -42,7 +42,7 @@ class Foo { } } -class Foo { +class Bar { static { // comment } diff --git a/docs/src/rules/no-extra-parens.md b/docs/src/rules/no-extra-parens.md index 1a4d8e2d48a0..5fcbcc639269 100644 --- a/docs/src/rules/no-extra-parens.md +++ b/docs/src/rules/no-extra-parens.md @@ -83,8 +83,6 @@ typeof (a); (Object.prototype.toString.call()); -(function(){} ? a() : b()); - class A { [(x)] = 1; } @@ -218,8 +216,8 @@ Examples of **correct** code for this rule with the `all` and `{ "ignoreJSX": "a ```jsx /* eslint no-extra-parens: ["error", "all", { ignoreJSX: "all" }] */ -const Component = (
) -const Component = ( +const ThisComponent = (
) +const ThatComponent = (
@@ -234,8 +232,8 @@ Examples of **incorrect** code for this rule with the `all` and `{ "ignoreJSX": ```jsx /* eslint no-extra-parens: ["error", "all", { ignoreJSX: "multi-line" }] */ -const Component = (
) -const Component = (

) +const ThisComponent = (
) +const ThatComponent = (

) ``` ::: @@ -246,12 +244,12 @@ Examples of **correct** code for this rule with the `all` and `{ "ignoreJSX": "m ```jsx /* eslint no-extra-parens: ["error", "all", { ignoreJSX: "multi-line" }] */ -const Component = ( +const ThisComponent = (

) -const Component = ( +const ThatComponent = (
@@ -266,12 +264,12 @@ Examples of **incorrect** code for this rule with the `all` and `{ "ignoreJSX": ```jsx /* eslint no-extra-parens: ["error", "all", { ignoreJSX: "single-line" }] */ -const Component = ( +const ThisComponent = (

) -const Component = ( +const ThatComponent = (
@@ -286,8 +284,8 @@ Examples of **correct** code for this rule with the `all` and `{ "ignoreJSX": "s ```jsx /* eslint no-extra-parens: ["error", "all", { ignoreJSX: "single-line" }] */ -const Component = (
) -const Component = (

) +const ThisComponent = (
) +const ThatComponent = (

) ``` ::: diff --git a/docs/src/rules/no-invalid-this.md b/docs/src/rules/no-invalid-this.md index 0c529a970650..454fdbd7185b 100644 --- a/docs/src/rules/no-invalid-this.md +++ b/docs/src/rules/no-invalid-this.md @@ -114,7 +114,7 @@ function Foo() { baz(() => this); } -class Foo { +class Bar { constructor() { // OK, this is in a constructor. this.a = 0; @@ -182,7 +182,7 @@ Foo.prototype.foo = function foo() { this.a = 0; }; -class Foo { +class Baz { // OK, this is in a class field initializer. a = this.b; diff --git a/docs/src/rules/no-loss-of-precision.md b/docs/src/rules/no-loss-of-precision.md index 1bec49266dc1..6674b15da6bf 100644 --- a/docs/src/rules/no-loss-of-precision.md +++ b/docs/src/rules/no-loss-of-precision.md @@ -18,12 +18,12 @@ Examples of **incorrect** code for this rule: ```js /*eslint no-loss-of-precision: "error"*/ -const x = 9007199254740993 -const x = 5123000000000000000000000000001 -const x = 1230000000000000000000000.0 -const x = .1230000000000000000000000 -const x = 0X20000000000001 -const x = 0X2_000000000_0001; +const a = 9007199254740993 +const b = 5123000000000000000000000000001 +const c = 1230000000000000000000000.0 +const d = .1230000000000000000000000 +const e = 0X20000000000001 +const f = 0X2_000000000_0001; ``` ::: @@ -35,13 +35,13 @@ Examples of **correct** code for this rule: ```js /*eslint no-loss-of-precision: "error"*/ -const x = 12345 -const x = 123.456 -const x = 123e34 -const x = 12300000000000000000000000 -const x = 0x1FFFFFFFFFFFFF -const x = 9007199254740991 -const x = 9007_1992547409_91 +const a = 12345 +const b = 123.456 +const c = 123e34 +const d = 12300000000000000000000000 +const e = 0x1FFFFFFFFFFFFF +const f = 9007199254740991 +const g = 9007_1992547409_91 ``` ::: diff --git a/docs/src/rules/no-misleading-character-class.md b/docs/src/rules/no-misleading-character-class.md index e1b182c2ef50..792760f2641b 100644 --- a/docs/src/rules/no-misleading-character-class.md +++ b/docs/src/rules/no-misleading-character-class.md @@ -17,36 +17,36 @@ This rule reports the regular expressions which include multiple code point char The combining characters are characters which belong to one of `Mc`, `Me`, and `Mn` [Unicode general categories](http://www.unicode.org/L2/L1999/UnicodeData.html#General%20Category). ```js -/^[Á]$/u.test("Á") //→ false -/^[❇️]$/u.test("❇️") //→ false +/^[Á]$/u.test("Á"); //→ false +/^[❇️]$/u.test("❇️"); //→ false ``` **A character with Emoji modifiers:** ```js -/^[👶🏻]$/u.test("👶🏻") //→ false -/^[👶🏽]$/u.test("👶🏽") //→ false +/^[👶🏻]$/u.test("👶🏻"); //→ false +/^[👶🏽]$/u.test("👶🏽"); //→ false ``` **A pair of regional indicator symbols:** ```js -/^[🇯🇵]$/u.test("🇯🇵") //→ false +/^[🇯🇵]$/u.test("🇯🇵"); //→ false ``` **Characters that ZWJ joins:** ```js -/^[👨‍👩‍👦]$/u.test("👨‍👩‍👦") //→ false +/^[👨‍👩‍👦]$/u.test("👨‍👩‍👦"); //→ false ``` **A surrogate pair without Unicode flag:** ```js -/^[👍]$/.test("👍") //→ false +/^[👍]$/.test("👍"); //→ false // Surrogate pair is OK if with u flag. -/^[👍]$/u.test("👍") //→ true +/^[👍]$/u.test("👍"); //→ true ``` ## Rule Details @@ -60,12 +60,12 @@ Examples of **incorrect** code for this rule: ```js /*eslint no-misleading-character-class: error */ -/^[Á]$/u -/^[❇️]$/u -/^[👶🏻]$/u -/^[🇯🇵]$/u -/^[👨‍👩‍👦]$/u -/^[👍]$/ +/^[Á]$/u; +/^[❇️]$/u; +/^[👶🏻]$/u; +/^[🇯🇵]$/u; +/^[👨‍👩‍👦]$/u; +/^[👍]$/; ``` ::: @@ -77,9 +77,9 @@ Examples of **correct** code for this rule: ```js /*eslint no-misleading-character-class: error */ -/^[abc]$/ -/^[👍]$/u -/^[\q{👶🏻}]$/v +/^[abc]$/; +/^[👍]$/u; +/^[\q{👶🏻}]$/v; ``` ::: diff --git a/docs/src/rules/no-multi-assign.md b/docs/src/rules/no-multi-assign.md index 7cc4581d1523..f4f4c2fce5aa 100644 --- a/docs/src/rules/no-multi-assign.md +++ b/docs/src/rules/no-multi-assign.md @@ -31,9 +31,9 @@ var a = b = c = 5; const foo = bar = "baz"; -let a = - b = - c; +let d = + e = + f; class Foo { a = b = 10; @@ -58,8 +58,8 @@ var c = 5; const foo = "baz"; const bar = "baz"; -let a = c; -let b = c; +let d = c; +let e = c; class Foo { a = 10; diff --git a/docs/src/rules/no-restricted-exports.md b/docs/src/rules/no-restricted-exports.md index 2f83643f9cb8..44672021a108 100644 --- a/docs/src/rules/no-restricted-exports.md +++ b/docs/src/rules/no-restricted-exports.md @@ -144,7 +144,25 @@ Examples of **incorrect** code for the `"restrictDefaultExports": { "direct": tr /*eslint no-restricted-exports: ["error", { "restrictDefaultExports": { "direct": true } }]*/ export default foo; +``` + +::: + +::: incorrect + +```js +/*eslint no-restricted-exports: ["error", { "restrictDefaultExports": { "direct": true } }]*/ + export default 42; +``` + +::: + +::: incorrect + +```js +/*eslint no-restricted-exports: ["error", { "restrictDefaultExports": { "direct": true } }]*/ + export default function foo() {} ``` @@ -176,6 +194,15 @@ Examples of **incorrect** code for the `"restrictDefaultExports": { "defaultFrom /*eslint no-restricted-exports: ["error", { "restrictDefaultExports": { "defaultFrom": true } }]*/ export { default } from 'foo'; +``` + +::: + +::: incorrect + +```js +/*eslint no-restricted-exports: ["error", { "restrictDefaultExports": { "defaultFrom": true } }]*/ + export { default as default } from 'foo'; ``` diff --git a/docs/src/rules/no-restricted-imports.md b/docs/src/rules/no-restricted-imports.md index 9040170ed133..72d97baf3e70 100644 --- a/docs/src/rules/no-restricted-imports.md +++ b/docs/src/rules/no-restricted-imports.md @@ -207,7 +207,7 @@ import { DisallowedObject } from "foo"; import { DisallowedObject as AllowedObject } from "foo"; -import { "DisallowedObject" as AllowedObject } from "foo"; +import { "DisallowedObject" as SomeObject } from "foo"; ``` ::: diff --git a/docs/src/rules/no-sequences.md b/docs/src/rules/no-sequences.md index 811dae491968..cbacb46ce26f 100644 --- a/docs/src/rules/no-sequences.md +++ b/docs/src/rules/no-sequences.md @@ -87,9 +87,9 @@ Examples of **incorrect** code for arrow functions: /*eslint no-sequences: "error"*/ const foo = (val) => (console.log('bar'), val); -const foo = () => ((bar = 123), 10); +const baz = () => ((bar = 123), 10); -const foo = () => { return (bar = 123), 10 } +const qux = () => { return (bar = 123), 10 } ``` ::: @@ -102,9 +102,9 @@ Examples of **correct** code for arrow functions: /*eslint no-sequences: "error"*/ const foo = (val) => ((console.log('bar'), val)); -const foo = () => (((bar = 123), 10)); +const baz = () => (((bar = 123), 10)); -const foo = () => { return ((bar = 123), 10) } +const qux = () => { return ((bar = 123), 10) } ``` ::: diff --git a/docs/src/rules/no-this-before-super.md b/docs/src/rules/no-this-before-super.md index c1a654796cb6..a06b5735553e 100644 --- a/docs/src/rules/no-this-before-super.md +++ b/docs/src/rules/no-this-before-super.md @@ -24,28 +24,28 @@ Examples of **incorrect** code for this rule: /*eslint no-this-before-super: "error"*/ /*eslint-env es6*/ -class A extends B { +class A1 extends B { constructor() { this.a = 0; super(); } } -class A extends B { +class A2 extends B { constructor() { this.foo(); super(); } } -class A extends B { +class A3 extends B { constructor() { super.foo(); super(); } } -class A extends B { +class A4 extends B { constructor() { super(this.foo()); } @@ -62,20 +62,20 @@ Examples of **correct** code for this rule: /*eslint no-this-before-super: "error"*/ /*eslint-env es6*/ -class A { +class A1 { constructor() { this.a = 0; // OK, this class doesn't have an `extends` clause. } } -class A extends B { +class A2 extends B { constructor() { super(); this.a = 0; // OK, this is after `super()`. } } -class A extends B { +class A3 extends B { foo() { this.a = 0; // OK. this is not in a constructor. } diff --git a/docs/src/rules/no-underscore-dangle.md b/docs/src/rules/no-underscore-dangle.md index c5e7923c2bfb..19157dfb55f7 100644 --- a/docs/src/rules/no-underscore-dangle.md +++ b/docs/src/rules/no-underscore-dangle.md @@ -45,8 +45,8 @@ var obj = _.contains(items, item); obj.__proto__ = {}; var file = __filename; function foo(_bar) {}; -const foo = { onClick(_bar) {} }; -const foo = (_bar) => {}; +const bar = { onClick(_bar) {} }; +const baz = (_bar) => {}; ``` ::: @@ -104,8 +104,12 @@ Examples of **correct** code for this rule with the `{ "allowAfterSuper": true } ```js /*eslint no-underscore-dangle: ["error", { "allowAfterSuper": true }]*/ -var a = super.foo_; -super._bar(); +class Foo extends Bar { + doSomething() { + var a = super.foo_; + super._bar(); + } +} ``` ::: @@ -138,16 +142,16 @@ class Foo { _bar() {} } -class Foo { +class Bar { bar_() {} } -const o = { +const o1 = { _bar() {} }; -const o = { - bar_() = {} +const o2 = { + bar_() {} }; ``` @@ -166,19 +170,19 @@ class Foo { _bar; } -class Foo { +class Bar { _bar = () => {}; } -class Foo { +class Baz { bar_; } -class Foo { +class Qux { #_bar; } -class Foo { +class FooBar { #bar_; } ``` @@ -195,7 +199,7 @@ Examples of **incorrect** code for this rule with the `{ "allowInArrayDestructur /*eslint no-underscore-dangle: ["error", { "allowInArrayDestructuring": false }]*/ const [_foo, _bar] = list; -const [foo_, ..._bar] = list; +const [foo_, ..._qux] = list; const [foo, [bar, _baz]] = list; ``` @@ -211,7 +215,7 @@ Examples of **incorrect** code for this rule with the `{ "allowInObjectDestructu /*eslint no-underscore-dangle: ["error", { "allowInObjectDestructuring": false }]*/ const { foo, bar: _bar } = collection; -const { foo, bar, _baz } = collection; +const { qux, xyz, _baz } = collection; ``` ::: @@ -224,7 +228,7 @@ Examples of **correct** code for this rule with the `{ "allowInObjectDestructuri /*eslint no-underscore-dangle: ["error", { "allowInObjectDestructuring": false }]*/ const { foo, bar, _baz: { a, b } } = collection; -const { foo, bar, _baz: baz } = collection; +const { qux, xyz, _baz: baz } = collection; ``` ::: @@ -238,17 +242,17 @@ Examples of **incorrect** code for this rule with the `{ "allowFunctionParams": ```js /*eslint no-underscore-dangle: ["error", { "allowFunctionParams": false }]*/ -function foo (_bar) {} -function foo (_bar = 0) {} -function foo (..._bar) {} +function foo1 (_bar) {} +function foo2 (_bar = 0) {} +function foo3 (..._bar) {} -const foo = function onClick (_bar) {} -const foo = function onClick (_bar = 0) {} -const foo = function onClick (..._bar) {} +const foo4 = function onClick (_bar) {} +const foo5 = function onClick (_bar = 0) {} +const foo6 = function onClick (..._bar) {} -const foo = (_bar) => {}; -const foo = (_bar = 0) => {}; -const foo = (..._bar) => {}; +const foo7 = (_bar) => {}; +const foo8 = (_bar = 0) => {}; +const foo9 = (..._bar) => {}; ``` ::: diff --git a/docs/src/rules/no-unexpected-multiline.md b/docs/src/rules/no-unexpected-multiline.md index 158a38642a4c..b8f3582fb39d 100644 --- a/docs/src/rules/no-unexpected-multiline.md +++ b/docs/src/rules/no-unexpected-multiline.md @@ -40,11 +40,11 @@ var hello = 'world' let x = function() {} `hello` -let x = function() {} -x +let y = function() {} +y `hello` -let x = foo +let z = foo /regex/g.test(bar) ``` diff --git a/docs/src/rules/no-unused-private-class-members.md b/docs/src/rules/no-unused-private-class-members.md index c92a8827be12..ec6951480b5f 100644 --- a/docs/src/rules/no-unused-private-class-members.md +++ b/docs/src/rules/no-unused-private-class-members.md @@ -20,29 +20,29 @@ Examples of **incorrect** code for this rule: ```js /*eslint no-unused-private-class-members: "error"*/ -class Foo { +class A { #unusedMember = 5; } -class Foo { +class B { #usedOnlyInWrite = 5; method() { this.#usedOnlyInWrite = 42; } } -class Foo { +class C { #usedOnlyToUpdateItself = 5; method() { this.#usedOnlyToUpdateItself++; } } -class Foo { +class D { #unusedMethod() {} } -class Foo { +class E { get #unusedAccessor() {} set #unusedAccessor(value) {} } @@ -57,14 +57,14 @@ Examples of **correct** code for this rule: ```js /*eslint no-unused-private-class-members: "error"*/ -class Foo { +class A { #usedMember = 42; method() { return this.#usedMember; } } -class Foo { +class B { #usedMethod() { return 42; } @@ -73,7 +73,7 @@ class Foo { } } -class Foo { +class C { get #usedAccessor() {} set #usedAccessor(value) {} diff --git a/docs/src/rules/no-useless-constructor.md b/docs/src/rules/no-useless-constructor.md index cfdae434d720..bf2c4c329846 100644 --- a/docs/src/rules/no-useless-constructor.md +++ b/docs/src/rules/no-useless-constructor.md @@ -56,19 +56,19 @@ Examples of **correct** code for this rule: class A { } -class A { +class B { constructor () { doSomething(); } } -class B extends A { +class C extends A { constructor() { super('foo'); } } -class B extends A { +class D extends A { constructor() { super(); doSomething(); diff --git a/docs/src/rules/no-useless-rename.md b/docs/src/rules/no-useless-rename.md index d65541c2ad07..6e79e3e7dc02 100644 --- a/docs/src/rules/no-useless-rename.md +++ b/docs/src/rules/no-useless-rename.md @@ -60,14 +60,14 @@ Examples of **incorrect** code for this rule by default: ```js /*eslint no-useless-rename: "error"*/ -import { foo as foo } from "bar"; -import { "foo" as foo } from "bar"; -export { foo as foo }; -export { foo as "foo" }; -export { foo as foo } from "bar"; -export { "foo" as "foo" } from "bar"; -let { foo: foo } = bar; -let { 'foo': foo } = bar; +import { foo1 as foo1 } from "bar"; +import { "foo2" as foo2 } from "bar"; +export { foo1 as foo1 }; +export { foo2 as "foo2" }; +export { foo3 as foo3 } from "bar"; +export { "foo4" as "foo4" } from "bar"; +let { foo3: foo3 } = bar; +let { 'foo4': foo4 } = bar; function foo({ bar: bar }) {} ({ foo: foo }) => {} ``` @@ -81,23 +81,23 @@ Examples of **correct** code for this rule by default: ```js /*eslint no-useless-rename: "error"*/ -import * as foo from "foo"; -import { foo } from "bar"; -import { foo as bar } from "baz"; -import { "foo" as bar } from "baz"; +import * as foo1 from "foo"; +import { foo2 } from "bar"; +import { foo as bar1 } from "baz"; +import { "foo" as bar2 } from "baz"; export { foo }; -export { foo as bar }; -export { foo as "bar" }; -export { foo as bar } from "foo"; -export { "foo" as "bar" } from "foo"; +export { foo as bar1 }; +export { foo as "bar2" }; +export { foo as bar3 } from "foo"; +export { "foo" as "bar4" } from "foo"; let { foo } = bar; let { foo: bar } = baz; -let { [foo]: foo } = bar; +let { [qux]: qux } = bar; -function foo({ bar }) {} -function foo({ bar: baz }) {} +function foo3({ bar }) {} +function foo4({ bar: baz }) {} ({ foo }) => {} ({ foo: bar }) => {} @@ -124,8 +124,9 @@ Examples of **correct** code for this rule with `{ ignoreExport: true }`: ```js /*eslint no-useless-rename: ["error", { ignoreExport: true }]*/ +const foo = 1; export { foo as foo }; -export { foo as foo } from "bar"; +export { bar as bar } from "bar"; ``` ::: @@ -138,7 +139,7 @@ Examples of **correct** code for this rule with `{ ignoreDestructuring: true }`: /*eslint no-useless-rename: ["error", { ignoreDestructuring: true }]*/ let { foo: foo } = bar; -function foo({ bar: bar }) {} +function baz({ bar: bar }) {} ({ foo: foo }) => {} ``` diff --git a/docs/src/rules/object-curly-newline.md b/docs/src/rules/object-curly-newline.md index a9b8875a5922..4a4f2e14f61e 100644 --- a/docs/src/rules/object-curly-newline.md +++ b/docs/src/rules/object-curly-newline.md @@ -554,9 +554,9 @@ Examples of **incorrect** code for this rule with the `{ "ImportDeclaration": "a /*eslint-env es6*/ import {foo, bar} from 'foo-bar'; -import {foo as f, bar} from 'foo-bar'; -import {foo, - bar} from 'foo-bar'; +import {foo as f, baz} from 'foo-bar'; +import {qux, + foobar} from 'foo-bar'; export { foo, @@ -564,7 +564,7 @@ export { }; export { foo as f, - bar + baz } from 'foo-bar'; ``` @@ -583,15 +583,15 @@ import { bar } from 'foo-bar'; import { - foo, bar + baz, qux } from 'foo-bar'; import { foo as f, - bar + foobar } from 'foo-bar'; export { foo, bar } from 'foo-bar'; -export { foo as f, bar } from 'foo-bar'; +export { foo as f, baz } from 'foo-bar'; ``` ::: diff --git a/docs/src/rules/one-var-declaration-per-line.md b/docs/src/rules/one-var-declaration-per-line.md index e9b159fc992b..659ef73343dc 100644 --- a/docs/src/rules/one-var-declaration-per-line.md +++ b/docs/src/rules/one-var-declaration-per-line.md @@ -46,8 +46,8 @@ Examples of **incorrect** code for this rule with the default `"initializations" var a, b, c = 0; -let a, - b = 0, c; +let d, + e = 0, f; ``` ::: @@ -62,11 +62,11 @@ Examples of **correct** code for this rule with the default `"initializations"` var a, b; -let a, - b; +let c, + d; -let a, - b = 0; +let e, + f = 0; ``` ::: @@ -83,9 +83,9 @@ Examples of **incorrect** code for this rule with the `"always"` option: var a, b; -let a, b = 0; +let c, d = 0; -const a = 0, b = 0; +const e = 0, f = 0; ``` ::: @@ -101,8 +101,8 @@ Examples of **correct** code for this rule with the `"always"` option: var a, b; -let a, - b = 0; +let c, + d = 0; ``` ::: diff --git a/docs/src/rules/one-var.md b/docs/src/rules/one-var.md index 9c41bcd81b21..b44c583dd358 100644 --- a/docs/src/rules/one-var.md +++ b/docs/src/rules/one-var.md @@ -192,14 +192,14 @@ Examples of **incorrect** code for this rule with the `"never"` option: ```js /*eslint one-var: ["error", "never"]*/ -function foo() { +function foo1() { var bar, baz; - const bar = true, - baz = false; + const qux = true, + foobar = false; } -function foo() { +function foo2() { var bar, qux; @@ -208,7 +208,7 @@ function foo() { } } -function foo(){ +function foo3(){ let bar = true, baz = false; } @@ -418,8 +418,8 @@ Examples of **correct** code for this rule with the `{ var: "never" }` option: function foo() { var bar, baz; - const bar = 1; // `const` and `let` declarations are ignored if they are not specified - const baz = 2; + const foobar = 1; // `const` and `let` declarations are ignored if they are not specified + const foobaz = 2; let qux; let norf; } diff --git a/docs/src/rules/prefer-const.md b/docs/src/rules/prefer-const.md index 19801eb952a2..41b144fe4660 100644 --- a/docs/src/rules/prefer-const.md +++ b/docs/src/rules/prefer-const.md @@ -27,9 +27,9 @@ Examples of **incorrect** code for this rule: let a = 3; console.log(a); -let a; -a = 0; -console.log(a); +let b; +b = 0; +console.log(b); class C { static { @@ -63,35 +63,35 @@ Examples of **correct** code for this rule: const a = 0; // it's never initialized. -let a; -console.log(a); +let b; +console.log(b); // it's reassigned after initialized. -let a; -a = 0; -a = 1; -console.log(a); +let c; +c = 0; +c = 1; +console.log(c); // it's initialized in a different block from the declaration. -let a; +let d; if (true) { - a = 0; + d = 0; } -console.log(a); +console.log(d); // it's initialized in a different scope. -let a; +let e; class C { #x; static { - a = obj => obj.#x; + e = obj => obj.#x; } } // it's initialized at a place that we cannot write a variable declaration. -let a; -if (true) a = 0; -console.log(a); +let f; +if (true) f = 0; +console.log(f); // `i` gets a new binding each iteration for (const i in [1, 2, 3]) { @@ -112,14 +112,14 @@ for (let i = 0, end = 10; i < end; ++i) { let predicate; [object.type, predicate] = foo(); -// `a` is only assigned once but cannot be separately declared as `const` -let a; -const b = {}; -({ a, c: b.c } = func()); +// `g` is only assigned once but cannot be separately declared as `const` +let g; +const h = {}; +({ g, c: h.c } = func()); // suggest to use `no-var` rule. -var b = 3; -console.log(b); +var i = 3; +console.log(i); ``` ::: @@ -170,9 +170,9 @@ const {a: a0, b} = obj; const a = a0 + 1; // all variables are reassigned. -let {a, b} = obj; -a = a + 1; -b = b + 1; +let {c, d} = obj; +c = c + 1; +d = d + 1; ``` ::: diff --git a/docs/src/rules/prefer-destructuring.md b/docs/src/rules/prefer-destructuring.md index edb72967b540..34b30c8de32b 100644 --- a/docs/src/rules/prefer-destructuring.md +++ b/docs/src/rules/prefer-destructuring.md @@ -36,6 +36,8 @@ Examples of **incorrect** code for this rule: ::: incorrect ```javascript +/* eslint prefer-destructuring: "error" */ + // With `array` enabled var foo = array[0]; bar.baz = array[0]; @@ -52,6 +54,8 @@ Examples of **correct** code for this rule: ::: correct ```javascript +/* eslint prefer-destructuring: "error" */ + // With `array` enabled var [ foo ] = array; var foo = array[someIndex]; @@ -63,8 +67,8 @@ var { foo } = object; var foo = object.bar; -let foo; -({ foo } = object); +let bar; +({ bar } = object); ``` ::: @@ -74,6 +78,7 @@ Examples of **incorrect** code when `enforceForRenamedProperties` is enabled: ::: incorrect ```javascript +/* eslint "prefer-destructuring": ["error", { "object": true }, { "enforceForRenamedProperties": true }] */ var foo = object.bar; ``` @@ -84,6 +89,7 @@ Examples of **correct** code when `enforceForRenamedProperties` is enabled: ::: correct ```javascript +/* eslint "prefer-destructuring": ["error", { "object": true }, { "enforceForRenamedProperties": true }] */ var { bar: foo } = object; ``` @@ -94,6 +100,7 @@ Examples of additional **correct** code when `enforceForRenamedProperties` is en ::: correct ```javascript +/* eslint "prefer-destructuring": ["error", { "object": true }, { "enforceForRenamedProperties": true }] */ class C { #x; foo() { diff --git a/docs/src/rules/require-unicode-regexp.md b/docs/src/rules/require-unicode-regexp.md index d0069de15963..768f34a71d35 100644 --- a/docs/src/rules/require-unicode-regexp.md +++ b/docs/src/rules/require-unicode-regexp.md @@ -91,7 +91,7 @@ const g = new RegExp("ccc", "v") const h = new RegExp("ddd", "giv") // This rule ignores RegExp calls if the flags could not be evaluated to a static value. -function f(flags) { +function i(flags) { return new RegExp("eee", flags) } ``` diff --git a/docs/src/rules/rest-spread-spacing.md b/docs/src/rules/rest-spread-spacing.md index b27b5378d238..f51ef54be35a 100644 --- a/docs/src/rules/rest-spread-spacing.md +++ b/docs/src/rules/rest-spread-spacing.md @@ -85,8 +85,8 @@ Examples of **incorrect** code for this rule with `"never"`: ```js /*eslint rest-spread-spacing: ["error", "never"]*/ -fn(... args) -[... arr, 4, 5, 6] +fn(... args); +[... arr, 4, 5, 6]; let [a, b, ... arr] = [1, 2, 3, 4, 5]; function fn(... args) { console.log(args); } let { x, y, ... z } = { x: 1, y: 2, a: 3, b: 4 }; @@ -102,8 +102,8 @@ Examples of **correct** code for this rule with `"never"`: ```js /*eslint rest-spread-spacing: ["error", "never"]*/ -fn(...args) -[...arr, 4, 5, 6] +fn(...args); +[...arr, 4, 5, 6]; let [a, b, ...arr] = [1, 2, 3, 4, 5]; function fn(...args) { console.log(args); } let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; @@ -127,8 +127,8 @@ Examples of **incorrect** code for this rule with `"always"`: ```js /*eslint rest-spread-spacing:["error", "always"]*/ -fn(...args) -[...arr, 4, 5, 6] +fn(...args); +[...arr, 4, 5, 6]; let [a, b, ...arr] = [1, 2, 3, 4, 5]; function fn(...args) { console.log(args); } let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; @@ -144,8 +144,8 @@ Examples of **correct** code for this rule with `"always"`: ```js /*eslint rest-spread-spacing: ["error", "always"]*/ -fn(... args) -[... arr, 4, 5, 6] +fn(... args); +[... arr, 4, 5, 6]; let [a, b, ... arr] = [1, 2, 3, 4, 5]; function fn(... args) { console.log(args); } let { x, y, ... z } = { x: 1, y: 2, a: 3, b: 4 }; diff --git a/docs/src/rules/sort-imports.md b/docs/src/rules/sort-imports.md index d48ead6f66e1..762e4acfa439 100644 --- a/docs/src/rules/sort-imports.md +++ b/docs/src/rules/sort-imports.md @@ -82,19 +82,37 @@ import {alpha, beta} from 'alpha.js'; import {delta, gamma} from 'delta.js'; import a from 'baz.js'; import {b} from 'qux.js'; +``` + +::: +::: correct + +```js /*eslint sort-imports: "error"*/ import a from 'foo.js'; import b from 'bar.js'; import c from 'baz.js'; +``` +::: + +::: correct + +```js /*eslint sort-imports: "error"*/ import 'foo.js' import * as bar from 'bar.js'; import {a, b} from 'baz.js'; import c from 'qux.js'; import {d} from 'quux.js'; +``` +::: + +::: correct + +```js /*eslint sort-imports: "error"*/ import {a, b, c} from 'foo.js' ``` @@ -109,27 +127,63 @@ Examples of **incorrect** code for this rule when using default options: /*eslint sort-imports: "error"*/ import b from 'foo.js'; import a from 'bar.js'; +``` + +::: +::: incorrect + +```js /*eslint sort-imports: "error"*/ import a from 'foo.js'; import A from 'bar.js'; +``` + +::: +::: incorrect + +```js /*eslint sort-imports: "error"*/ -import {b, c} from 'foo.js'; +import {c, d} from 'foo.js'; import {a, b} from 'bar.js'; +``` + +::: + +::: incorrect +```js /*eslint sort-imports: "error"*/ import a from 'foo.js'; import {b, c} from 'bar.js'; +``` + +::: + +::: incorrect +```js /*eslint sort-imports: "error"*/ import {a} from 'foo.js'; import {b, c} from 'bar.js'; +``` + +::: +::: incorrect + +```js /*eslint sort-imports: "error"*/ import a from 'foo.js'; import * as b from 'bar.js'; +``` + +::: +::: incorrect + +```js /*eslint sort-imports: "error"*/ import {b, a, c} from 'foo.js' ``` diff --git a/docs/src/rules/sort-keys.md b/docs/src/rules/sort-keys.md index 0fd00aeff7f4..14cdc12f8f30 100644 --- a/docs/src/rules/sort-keys.md +++ b/docs/src/rules/sort-keys.md @@ -21,20 +21,20 @@ Examples of **incorrect** code for this rule: /*eslint sort-keys: "error"*/ /*eslint-env es6*/ -let obj = {a: 1, c: 3, b: 2}; -let obj = {a: 1, "c": 3, b: 2}; +let obj1 = {a: 1, c: 3, b: 2}; +let obj2 = {a: 1, "c": 3, b: 2}; // Case-sensitive by default. -let obj = {a: 1, b: 2, C: 3}; +let obj3 = {a: 1, b: 2, C: 3}; // Non-natural order by default. -let obj = {1: a, 2: c, 10: b}; +let obj4 = {1: a, 2: c, 10: b}; // This rule checks computed properties which have a simple name as well. // Simple names are names which are expressed by an Identifier node or a Literal node. const S = Symbol("s") -let obj = {a: 1, ["c"]: 3, b: 2}; -let obj = {a: 1, [S]: 3, b: 2}; +let obj5 = {a: 1, ["c"]: 3, b: 2}; +let obj6 = {a: 1, [S]: 3, b: 2}; ``` ::: @@ -47,27 +47,27 @@ Examples of **correct** code for this rule: /*eslint sort-keys: "error"*/ /*eslint-env es6*/ -let obj = {a: 1, b: 2, c: 3}; -let obj = {a: 1, "b": 2, c: 3}; +let obj1 = {a: 1, b: 2, c: 3}; +let obj2 = {a: 1, "b": 2, c: 3}; // Case-sensitive by default. -let obj = {C: 3, a: 1, b: 2}; +let obj3 = {C: 3, a: 1, b: 2}; // Non-natural order by default. -let obj = {1: a, 10: b, 2: c}; +let obj4 = {1: a, 10: b, 2: c}; // This rule checks computed properties which have a simple name as well. -let obj = {a: 1, ["b"]: 2, c: 3}; -let obj = {a: 1, [b]: 2, c: 3}; +let obj5 = {a: 1, ["b"]: 2, c: 3}; +let obj6 = {a: 1, [b]: 2, c: 3}; // This rule ignores computed properties which have a non-simple name. -let obj = {a: 1, [c + d]: 3, b: 2}; -let obj = {a: 1, ["c" + "d"]: 3, b: 2}; -let obj = {a: 1, [`${c}`]: 3, b: 2}; -let obj = {a: 1, [tag`c`]: 3, b: 2}; +let obj7 = {a: 1, [c + d]: 3, b: 2}; +let obj8 = {a: 1, ["c" + "d"]: 3, b: 2}; +let obj9 = {a: 1, [`${c}`]: 3, b: 2}; +let obj10 = {a: 1, [tag`c`]: 3, b: 2}; // This rule does not report unsorted properties that are separated by a spread property. -let obj = {b: 1, ...c, a: 2}; +let obj11 = {b: 1, ...c, a: 2}; ``` ::: @@ -118,14 +118,14 @@ Examples of **incorrect** code for the `"desc"` option: /*eslint sort-keys: ["error", "desc"]*/ /*eslint-env es6*/ -let obj = {b: 2, c: 3, a: 1}; -let obj = {"b": 2, c: 3, a: 1}; +let obj1 = {b: 2, c: 3, a: 1}; +let obj2 = {"b": 2, c: 3, a: 1}; // Case-sensitive by default. -let obj = {C: 1, b: 3, a: 2}; +let obj3 = {C: 1, b: 3, a: 2}; // Non-natural order by default. -let obj = {10: b, 2: c, 1: a}; +let obj4 = {10: b, 2: c, 1: a}; ``` ::: @@ -138,14 +138,14 @@ Examples of **correct** code for the `"desc"` option: /*eslint sort-keys: ["error", "desc"]*/ /*eslint-env es6*/ -let obj = {c: 3, b: 2, a: 1}; -let obj = {c: 3, "b": 2, a: 1}; +let obj1 = {c: 3, b: 2, a: 1}; +let obj2 = {c: 3, "b": 2, a: 1}; // Case-sensitive by default. -let obj = {b: 3, a: 2, C: 1}; +let obj3 = {b: 3, a: 2, C: 1}; // Non-natural order by default. -let obj = {2: c, 10: b, 1: a}; +let obj4 = {2: c, 10: b, 1: a}; ``` ::: @@ -160,8 +160,8 @@ Examples of **incorrect** code for the `{caseSensitive: false}` option: /*eslint sort-keys: ["error", "asc", {caseSensitive: false}]*/ /*eslint-env es6*/ -let obj = {a: 1, c: 3, C: 4, b: 2}; -let obj = {a: 1, C: 3, c: 4, b: 2}; +let obj1 = {a: 1, c: 3, C: 4, b: 2}; +let obj2 = {a: 1, C: 3, c: 4, b: 2}; ``` ::: @@ -174,8 +174,8 @@ Examples of **correct** code for the `{caseSensitive: false}` option: /*eslint sort-keys: ["error", "asc", {caseSensitive: false}]*/ /*eslint-env es6*/ -let obj = {a: 1, b: 2, c: 3, C: 4}; -let obj = {a: 1, b: 2, C: 3, c: 4}; +let obj1 = {a: 1, b: 2, c: 3, C: 4}; +let obj2 = {a: 1, b: 2, C: 3, c: 4}; ``` ::: @@ -219,7 +219,7 @@ Examples of **incorrect** code for the `{minKeys: 4}` option: /*eslint-env es6*/ // 4 keys -let obj = { +let obj1 = { b: 2, a: 1, // not sorted correctly (should be 1st key) c: 3, @@ -227,7 +227,7 @@ let obj = { }; // 5 keys -let obj = { +let obj2 = { 2: 'a', 1: 'b', // not sorted correctly (should be 1st key) 3: 'c', @@ -247,14 +247,14 @@ Examples of **correct** code for the `{minKeys: 4}` option: /*eslint-env es6*/ // 3 keys -let obj = { +let obj1 = { b: 2, a: 1, c: 3, }; // 2 keys -let obj = { +let obj2 = { 2: 'b', 1: 'a', }; @@ -318,7 +318,7 @@ Examples of **correct** code for the `{allowLineSeparatedGroups: true}` option: /*eslint sort-keys: ["error", "asc", {allowLineSeparatedGroups: true}]*/ /*eslint-env es6*/ -let obj = { +let obj1 = { e: 1, f: 2, g: 3, @@ -328,7 +328,7 @@ let obj = { c: 6 } -let obj = { +let obj2 = { b: 1, // comment @@ -336,7 +336,7 @@ let obj = { c: 5, } -let obj = { +let obj3 = { c: 1, d: 2, @@ -346,7 +346,7 @@ let obj = { e: 3, } -let obj = { +let obj4 = { c: 1, d: 2, // comment @@ -358,14 +358,14 @@ let obj = { e: 4 } -let obj = { +let obj5 = { b, [foo + bar]: 1, a } -let obj = { +let obj6 = { b: 1 // comment before comma @@ -373,7 +373,7 @@ let obj = { a: 2 }; -var obj = { +var obj7 = { b: 1, a: 2, diff --git a/docs/src/rules/space-before-keywords.md b/docs/src/rules/space-before-keywords.md index 9c2f73581096..5eaa76db7685 100644 --- a/docs/src/rules/space-before-keywords.md +++ b/docs/src/rules/space-before-keywords.md @@ -55,7 +55,7 @@ if (foo) { const foo = 'bar';let baz = 'qux'; -var foo =function bar () {} +var qux =function bar () {} function bar() { if (foo) {return; } @@ -66,7 +66,7 @@ function bar() { Examples of **correct** code for this rule with the default `"always"` option: -::: correct +::: correct { "ecmaFeatures": { "jsx": true } } ```js /*eslint space-before-keywords: ["error", "always"]*/ @@ -76,7 +76,7 @@ if (foo) { // ... } else {} -(function() {})() +(function() {})(); diff --git a/docs/src/rules/space-infix-ops.md b/docs/src/rules/space-infix-ops.md index 984e3b37f418..b278a7c1d781 100644 --- a/docs/src/rules/space-infix-ops.md +++ b/docs/src/rules/space-infix-ops.md @@ -57,7 +57,7 @@ a?b:c const a={b:1}; -var {a=0}=bar; +var {b=0}=bar; function foo(a=0) { } ``` @@ -80,7 +80,7 @@ a ? b : c const a = {b:1}; -var {a = 0} = bar; +var {b = 0} = bar; function foo(a = 0) { } ``` From b7ef2f34fe12b68a366e1b4bf5f64d7332c6e72e Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Wed, 11 Oct 2023 17:59:44 -0400 Subject: [PATCH 10/24] docs: Enable pretty code formatter output (#17635) * docs: Enable pretty code formatter output fixes #17505 * Add note about formatted output * Update templates/formatter-examples.md.ejs Co-authored-by: Milos Djermanovic * Update templates/formatter-examples.md.ejs Co-authored-by: Milos Djermanovic --------- Co-authored-by: Milos Djermanovic --- templates/formatter-examples.md.ejs | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/templates/formatter-examples.md.ejs b/templates/formatter-examples.md.ejs index 20f46f2d5aa3..e18eb18995fd 100644 --- a/templates/formatter-examples.md.ejs +++ b/templates/formatter-examples.md.ejs @@ -14,7 +14,7 @@ You can specify a formatter using the `--format` or `-f` flag in the CLI. For ex The built-in formatter options are: -<% Object.keys(formatterResults).forEach(function(formatterName) { -%> +<% Object.keys(formatterResults).forEach(formatterName => { -%> * [<%= formatterName %>](#<%= formatterName %>) <% }) -%> @@ -56,19 +56,36 @@ npx eslint --format fullOfProblems.js ``` ## Built-In Formatter Options -<% Object.keys(formatterResults).forEach(function(formatterName) { -%> +<% Object.keys(formatterResults).forEach(formatterName => { -%> ### <%= formatterName %> <%= formatterResults[formatterName].description %> +<% if (formatterName !== "html") { -%> +<% + let codeFormat = "text"; + let output = formatterResults[formatterName].result; + let outputNote = "Example output:"; -Example output: + if (output.startsWith("\u003C?xml")) { + codeFormat = "xml"; + } -<% if (formatterName !== "html") { -%> -```text -<%- formatterResults[formatterName].result %> + if (formatterName.includes("json")) { + codeFormat = "json"; + output = JSON.stringify(JSON.parse(output), null, 4); + outputNote = "Example output (formatted for easier reading):"; + } +%> +<%= outputNote %> + +```<%= codeFormat %> +<%- output %> ``` <% } else {-%> + +Example output: + <% } -%> <% }) -%> From f8e5c30636450d4a8baf51f0e227685e6d77ac64 Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot Date: Fri, 13 Oct 2023 08:07:15 +0000 Subject: [PATCH 11/24] docs: Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 97f165daaa6a..c910134a6f41 100644 --- a/README.md +++ b/README.md @@ -294,7 +294,7 @@ The following companies, organizations, and individuals support ESLint's ongoing

Chrome Frameworks Fund Automattic

Gold Sponsors

Salesforce Airbnb

Silver Sponsors

Liftoff American Express

Bronze Sponsors

-

bulkfollow ThemeIsle Anagram Solver Icons8 Discord Transloadit Ignition HeroCoders QuickBooks Tool hub

+

ThemeIsle Anagram Solver Icons8 Discord Transloadit Ignition HeroCoders QuickBooks Tool hub

## Technology Sponsors From 179929bd46892f18f2aef0c159d5cc361cb69987 Mon Sep 17 00:00:00 2001 From: Francesco Trotta Date: Fri, 13 Oct 2023 10:19:12 +0200 Subject: [PATCH 12/24] docs: Remove trailing newline from the code of Playground links (#17641) * Remove trailing newline from Playground links * Update as per discussion --- docs/.eleventy.js | 6 +++- docs/src/rules/eol-last.md | 3 +- docs/src/rules/no-multiple-empty-lines.md | 37 ++++++----------------- 3 files changed, 17 insertions(+), 29 deletions(-) diff --git a/docs/.eleventy.js b/docs/.eleventy.js index a2a0b71c17bc..75a372d3d5e5 100644 --- a/docs/.eleventy.js +++ b/docs/.eleventy.js @@ -208,7 +208,11 @@ module.exports = function(eleventyConfig) { // See https://github.com/eslint/eslint.org/blob/ac38ab41f99b89a8798d374f74e2cce01171be8b/src/playground/App.js#L44 const parserOptionsJSON = tokens[index].info?.split("correct ")[1]?.trim(); const parserOptions = { sourceType: "module", ...(parserOptionsJSON && JSON.parse(parserOptionsJSON)) }; - const { content } = tokens[index + 1]; + + // Remove trailing newline and presentational `⏎` characters (https://github.com/eslint/eslint/issues/17627): + const content = tokens[index + 1].content + .replace(/\n$/u, "") + .replace(/⏎(?=\n)/gu, ""); const state = encodeToBase64( JSON.stringify({ options: { parserOptions }, diff --git a/docs/src/rules/eol-last.md b/docs/src/rules/eol-last.md index 4c9d837c5c32..2a8de22258b5 100644 --- a/docs/src/rules/eol-last.md +++ b/docs/src/rules/eol-last.md @@ -42,7 +42,8 @@ Examples of **correct** code for this rule: function doSomething() { var foo = 2; -}\n +} + ``` ::: diff --git a/docs/src/rules/no-multiple-empty-lines.md b/docs/src/rules/no-multiple-empty-lines.md index 5457c54c1f0b..fbb9363485b6 100644 --- a/docs/src/rules/no-multiple-empty-lines.md +++ b/docs/src/rules/no-multiple-empty-lines.md @@ -59,13 +59,13 @@ Examples of **incorrect** code for this rule with the `{ max: 2, maxEOF: 0 }` op ::: incorrect ```js -/*eslint no-multiple-empty-lines: ["error", { "max": 2, "maxEOF": 0 }]*/ - -var foo = 5; - - -var bar = 3; - +/*eslint no-multiple-empty-lines: ["error", { "max": 2, "maxEOF": 0 }]*/⏎ +⏎ +var foo = 5;⏎ +⏎ +⏎ +var bar = 3;⏎ +⏎ ``` @@ -75,36 +75,19 @@ Examples of **correct** code for this rule with the `{ max: 2, maxEOF: 0 }` opti ::: correct -```js -/*eslint no-multiple-empty-lines: ["error", { "max": 2, "maxEOF": 0 }]*/ - -var foo = 5; - - -var bar = 3; -``` - -::: - -**Note**: Although this ensures zero empty lines at the EOF, most editors will still show one empty line at the end if the file ends with a line break, as illustrated below. There is no empty line at the end of a file after the last `\n`, although editors may show an additional line. A true additional line would be represented by `\n\n`. - -**Incorrect**: - -::: incorrect - ```js /*eslint no-multiple-empty-lines: ["error", { "max": 2, "maxEOF": 0 }]*/⏎ ⏎ var foo = 5;⏎ ⏎ ⏎ -var bar = 3;⏎ -⏎ - +var bar = 3; ``` ::: +**Note**: Although this ensures zero empty lines at the EOF, most editors will still show one empty line at the end if the file ends with a line break, as illustrated below. There is no empty line at the end of a file after the last `\n`, although editors may show an additional line. A true additional line would be represented by `\n\n`. + **Correct**: ::: correct From a58aa200fccedae7e2e9b6129246f2cedab14f8d Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Fri, 13 Oct 2023 16:46:08 +0200 Subject: [PATCH 13/24] docs: fix examples for several rules (#17645) --- docs/src/rules/arrow-body-style.md | 4 + docs/src/rules/function-paren-newline.md | 12 +- docs/src/rules/id-match.md | 2 +- docs/src/rules/indent.md | 4 +- docs/src/rules/lines-around-directive.md | 166 +++++++++++++++------- docs/src/rules/max-statements-per-line.md | 2 +- docs/src/rules/max-statements.md | 10 +- docs/src/rules/no-multiple-empty-lines.md | 16 +++ docs/src/rules/one-var.md | 10 +- 9 files changed, 157 insertions(+), 69 deletions(-) diff --git a/docs/src/rules/arrow-body-style.md b/docs/src/rules/arrow-body-style.md index 1bfdb5a73084..1dc6fcc36e83 100644 --- a/docs/src/rules/arrow-body-style.md +++ b/docs/src/rules/arrow-body-style.md @@ -32,6 +32,7 @@ Examples of **incorrect** code for this rule with the `"always"` option: ```js /*eslint arrow-body-style: ["error", "always"]*/ /*eslint-env es6*/ + let foo = () => 0; ``` @@ -42,6 +43,9 @@ Examples of **correct** code for this rule with the `"always"` option: :::correct ```js +/*eslint arrow-body-style: ["error", "always"]*/ +/*eslint-env es6*/ + let foo = () => { return 0; }; diff --git a/docs/src/rules/function-paren-newline.md b/docs/src/rules/function-paren-newline.md index e6a067cf5f23..ad44aaec3650 100644 --- a/docs/src/rules/function-paren-newline.md +++ b/docs/src/rules/function-paren-newline.md @@ -339,11 +339,15 @@ var barbaz = function( bar, baz ) {}; -var barbaz = (bar, - baz) => {}; +var barbaz = ( + bar, + baz +) => {}; -foo(bar, - baz); +foo( + bar, + baz +); ``` ::: diff --git a/docs/src/rules/id-match.md b/docs/src/rules/id-match.md index 6d15d19e859b..59954fc2a48a 100644 --- a/docs/src/rules/id-match.md +++ b/docs/src/rules/id-match.md @@ -143,7 +143,7 @@ Examples of **correct** code for this rule with the `"^[a-z]+([A-Z][a-z]+)*$", { ```js /*eslint id-match: [2, "^[a-z]+([A-Z][a-z]+)*$", { "onlyDeclarations": true }]*/ -do_something(__dirname); +foo = __dirname; ``` ::: diff --git a/docs/src/rules/indent.md b/docs/src/rules/indent.md index e53a1f9a6e1b..72efad265683 100644 --- a/docs/src/rules/indent.md +++ b/docs/src/rules/indent.md @@ -192,7 +192,7 @@ Examples of **correct** code for this rule with the `4, { "ignoredNodes": ["Call foo(); bar(); -}) +})(); ``` ::: @@ -403,7 +403,7 @@ function foo(x) { })(); if (y) { - console.log('foo'); + console.log('foo'); } ``` diff --git a/docs/src/rules/lines-around-directive.md b/docs/src/rules/lines-around-directive.md index 8a83df1afd7c..7c18b517446d 100644 --- a/docs/src/rules/lines-around-directive.md +++ b/docs/src/rules/lines-around-directive.md @@ -65,14 +65,8 @@ Examples of **incorrect** code for this rule with the `"always"` option: ```js /* eslint lines-around-directive: ["error", "always"] */ -/* Top of file */ -"use strict"; -var foo; - -/* Top of file */ // comment "use strict"; -"use asm"; var foo; function foo() { @@ -90,23 +84,29 @@ function foo() { ::: -Examples of **correct** code for this rule with the `"always"` option: - -::: correct { "sourceType": "script" } +::: incorrect { "sourceType": "script" } ```js /* eslint lines-around-directive: ["error", "always"] */ -/* Top of file */ +// comment "use strict"; - +"use asm"; var foo; +``` + +::: + +Examples of **correct** code for this rule with the `"always"` option: + +::: correct { "sourceType": "script" } + +```js +/* eslint lines-around-directive: ["error", "always"] */ -/* Top of file */ // comment "use strict"; -"use asm"; var foo; @@ -128,6 +128,21 @@ function foo() { ::: +::: correct { "sourceType": "script" } + +```js +/* eslint lines-around-directive: ["error", "always"] */ + +// comment + +"use strict"; +"use asm"; + +var foo; +``` + +::: + ### never Examples of **incorrect** code for this rule with the `"never"` option: @@ -137,17 +152,9 @@ Examples of **incorrect** code for this rule with the `"never"` option: ```js /* eslint lines-around-directive: ["error", "never"] */ -/* Top of file */ - -"use strict"; - -var foo; - -/* Top of file */ // comment "use strict"; -"use asm"; var foo; @@ -169,21 +176,30 @@ function foo() { ::: -Examples of **correct** code for this rule with the `"never"` option: - -::: correct { "sourceType": "script" } +::: incorrect { "sourceType": "script" } ```js /* eslint lines-around-directive: ["error", "never"] */ -/* Top of file */ +// comment + "use strict"; +"use asm"; + var foo; +``` + +::: + +Examples of **correct** code for this rule with the `"never"` option: + +::: correct { "sourceType": "script" } + +```js +/* eslint lines-around-directive: ["error", "never"] */ -/* Top of file */ // comment "use strict"; -"use asm"; var foo; function foo() { @@ -201,6 +217,19 @@ function foo() { ::: +::: correct { "sourceType": "script" } + +```js +/* eslint lines-around-directive: ["error", "never"] */ + +// comment +"use strict"; +"use asm"; +var foo; +``` + +::: + ### before & after Examples of **incorrect** code for this rule with the `{ "before": "never", "after": "always" }` option: @@ -210,16 +239,9 @@ Examples of **incorrect** code for this rule with the `{ "before": "never", "aft ```js /* eslint lines-around-directive: ["error", { "before": "never", "after": "always" }] */ -/* Top of file */ - -"use strict"; -var foo; - -/* Top of file */ // comment "use strict"; -"use asm"; var foo; function foo() { @@ -238,22 +260,29 @@ function foo() { ::: -Examples of **correct** code for this rule with the `{ "before": "never", "after": "always" }` option: - -::: correct { "sourceType": "script" } +::: incorrect { "sourceType": "script" } ```js /* eslint lines-around-directive: ["error", { "before": "never", "after": "always" }] */ -/* Top of file */ -"use strict"; +// comment +"use strict"; +"use asm"; var foo; +``` + +::: + +Examples of **correct** code for this rule with the `{ "before": "never", "after": "always" }` option: + +::: correct { "sourceType": "script" } + +```js +/* eslint lines-around-directive: ["error", { "before": "never", "after": "always" }] */ -/* Top of file */ // comment "use strict"; -"use asm"; var foo; @@ -274,22 +303,29 @@ function foo() { ::: -Examples of **incorrect** code for this rule with the `{ "before": "always", "after": "never" }` option: - -::: incorrect { "sourceType": "script" } +::: correct { "sourceType": "script" } ```js -/* eslint lines-around-directive: ["error", { "before": "always", "after": "never" }] */ +/* eslint lines-around-directive: ["error", { "before": "never", "after": "always" }] */ -/* Top of file */ +// comment "use strict"; +"use asm"; var foo; +``` + +::: + +Examples of **incorrect** code for this rule with the `{ "before": "always", "after": "never" }` option: + +::: incorrect { "sourceType": "script" } + +```js +/* eslint lines-around-directive: ["error", { "before": "always", "after": "never" }] */ -/* Top of file */ // comment "use strict"; -"use asm"; var foo; @@ -310,22 +346,30 @@ function foo() { ::: -Examples of **correct** code for this rule with the `{ "before": "always", "after": "never" }` option: - -::: correct { "sourceType": "script" } +::: incorrect { "sourceType": "script" } ```js /* eslint lines-around-directive: ["error", { "before": "always", "after": "never" }] */ -/* Top of file */ +// comment "use strict"; +"use asm"; + var foo; +``` + +::: + +Examples of **correct** code for this rule with the `{ "before": "always", "after": "never" }` option: + +::: correct { "sourceType": "script" } + +```js +/* eslint lines-around-directive: ["error", { "before": "always", "after": "never" }] */ -/* Top of file */ // comment "use strict"; -"use asm"; var foo; function foo() { @@ -344,6 +388,20 @@ function foo() { ::: +::: correct { "sourceType": "script" } + +```js +/* eslint lines-around-directive: ["error", { "before": "always", "after": "never" }] */ + +// comment + +"use strict"; +"use asm"; +var foo; +``` + +::: + ## When Not To Use It You can safely disable this rule if you do not have any strict conventions about whether or not directive prologues should have blank newlines before or after them. diff --git a/docs/src/rules/max-statements-per-line.md b/docs/src/rules/max-statements-per-line.md index 76a49e3a09b1..d42d2ef55c1a 100644 --- a/docs/src/rules/max-statements-per-line.md +++ b/docs/src/rules/max-statements-per-line.md @@ -76,7 +76,7 @@ if (condition) { bar = 1; } else { baz = 2; } for (var i = 0; i < length; ++i) { bar = 1; baz = 2; } switch (discriminant) { case 'test': break; default: break; } function foo() { bar = 1; baz = 2; } -var qux = function qux() { bar = 1; }; +var qux = function qux() { bar = 1; baz = 2; }; (function foo() { bar = 1; baz = 2; })(); ``` diff --git a/docs/src/rules/max-statements.md b/docs/src/rules/max-statements.md index 4462011db742..5bdc7e8c2f49 100644 --- a/docs/src/rules/max-statements.md +++ b/docs/src/rules/max-statements.md @@ -99,12 +99,13 @@ function foo() { var foo7 = 7; var foo8 = 8; var foo9 = 9; - var foo10 = 10; - return function () { + return function () { // 10 // The number of statements in the inner function does not count toward the // statement maximum. + var bar; + var baz; return 42; }; } @@ -119,12 +120,13 @@ let bar = () => { var foo7 = 7; var foo8 = 8; var foo9 = 9; - var foo10 = 10; - return function () { + return function () { // 10 // The number of statements in the inner function does not count toward the // statement maximum. + var bar; + var baz; return 42; }; } diff --git a/docs/src/rules/no-multiple-empty-lines.md b/docs/src/rules/no-multiple-empty-lines.md index fbb9363485b6..e3d7327c2e43 100644 --- a/docs/src/rules/no-multiple-empty-lines.md +++ b/docs/src/rules/no-multiple-empty-lines.md @@ -111,6 +111,8 @@ Examples of **incorrect** code for this rule with the `{ max: 2, maxBOF: 1 }` op ::: incorrect ```js + + /*eslint no-multiple-empty-lines: ["error", { "max": 2, "maxBOF": 1 }]*/ @@ -132,6 +134,20 @@ Examples of **correct** code for this rule with the `{ max: 2, maxBOF: 1 }` opti var foo = 5; +var bar = 3; +``` + +::: + +::: correct + +```js + +/*eslint no-multiple-empty-lines: ["error", { "max": 2, "maxBOF": 1}]*/ + +var foo = 5; + + var bar = 3; ``` diff --git a/docs/src/rules/one-var.md b/docs/src/rules/one-var.md index b44c583dd358..cb3bc09b955a 100644 --- a/docs/src/rules/one-var.md +++ b/docs/src/rules/one-var.md @@ -416,12 +416,16 @@ Examples of **correct** code for this rule with the `{ var: "never" }` option: /*eslint-env es6*/ function foo() { - var bar, - baz; - const foobar = 1; // `const` and `let` declarations are ignored if they are not specified + var bar; + var baz; + + // `const` and `let` declarations are ignored if they are not specified + const foobar = 1; const foobaz = 2; + const barfoo = 1, bazfoo = 2; let qux; let norf; + let fooqux, foonorf; } ``` From 660ed3afd128ad529234a855345629982caf1bc7 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Mon, 16 Oct 2023 11:40:56 -0400 Subject: [PATCH 14/24] docs: Plugin flat config migration guide (#17640) * docs: Plugin flat config migration guide Fixes #17242 * Switch exports to default * Update docs/src/extend/plugin-migration-flat-config.md Co-authored-by: Milos Djermanovic * Meta information * CommonJS syntax * Backwards compatibility * Update docs/src/extend/plugin-migration-flat-config.md Co-authored-by: Milos Djermanovic --------- Co-authored-by: Milos Djermanovic --- .../extend/plugin-migration-flat-config.md | 293 ++++++++++++++++++ 1 file changed, 293 insertions(+) create mode 100644 docs/src/extend/plugin-migration-flat-config.md diff --git a/docs/src/extend/plugin-migration-flat-config.md b/docs/src/extend/plugin-migration-flat-config.md new file mode 100644 index 000000000000..6c277596fc46 --- /dev/null +++ b/docs/src/extend/plugin-migration-flat-config.md @@ -0,0 +1,293 @@ +--- +title: Plugin Migration to Flat Config +eleventyNavigation: + key: plugin flat config + parent: create plugins + title: Migration to Flat Config + order: 4 + +--- + +Beginning in ESLint v9.0.0, the default configuration system will be the new flat config system. In order for your plugins to work with flat config files, you'll need to make some changes to your existing plugins. + +## Recommended Plugin Structure + +To make it easier to work with your plugin in the flat config system, it's recommended that you switch your existing plugin entrypoint to look like this: + +```js +const plugin = { + meta: {}, + configs: {}, + rules: {}, + processors: {} +}; + +// for ESM +export default plugin; + +// OR for CommonJS +module.exports = plugin; +``` + +This structure allows the most flexibility when making other changes discussed on this page. + +## Adding Plugin Meta Information + +With the old eslintrc configuration system, ESLint could pull information about the plugin from the package name, but with flat config, ESLint no longer has access to the name of the plugin package. To replace that missing information, you should add a `meta` key that contains at least a `name` key, and ideally, a `version` key, such as: + +```js +const plugin = { + meta: { + name: "eslint-plugin-example", + version: "1.0.0" + }, + configs: {}, + rules: {}, + processors: {} +}; + +// for ESM +export default plugin; + +// OR for CommonJS +module.exports = plugin; +``` + +If your plugin is published as an npm package, the `name` and `version` should be the same as in your `package.json` file; otherwise, you can assign any value you'd like. + +Without this meta information, your plugin will not be usable with the `--cache` and `--print-config` command line options. + +## Migrating Rules for Flat Config + +No changes are necessary for the `rules` key in your plugin. Everything works the same as with the old eslintrc configuration system. + +## Migrating Processors for Flat Config + +No changes are necessary for the `processors` key in your plugin as long as you aren't using file extension-named processors. If you have any [file extension-named processors](custom-processors#file-extension-named-processor), you must update the name to a valid identifier (numbers and letters). File extension-named processors were automatically applied in the old configuration system but are not automatically applied when using flat config. Here is an example of a file extension-named processor: + +```js +const plugin = { + configs: {}, + rules: {}, + processors: { + + // no longer supported + ".md": { + preprocess() {}, + postprocess() {} + } + } +}; + +// for ESM +export default plugin; + +// OR for CommonJS +module.exports = plugin; +``` + +The name `".md"` is no longer valid for a processor, so it must be replaced with a valid identifier such as `markdown`: + +```js +const plugin = { + configs: {}, + rules: {}, + processors: { + + // works in both old and new config systems + "markdown": { + preprocess() {}, + postprocess() {} + } + } +}; + +// for ESM +export default plugin; + +// OR for CommonJS +module.exports = plugin; +``` + +In order to use this renamed processor, you'll also need to manually specify it inside of a config, such as: + +```js +import example from "eslint-plugin-example"; + +export default [ + { + plugins: { + example + }, + processor: "example/markdown" + } +]; +``` + +You should update your plugin's documentation to advise your users if you have renamed a file extension-named processor. + +## Migrating Configs for Flat Config + +If your plugin is exporting configs that refer back to your plugin, then you'll need to update your configs to flat config format. As part of the migration, you'll need to reference your plugin directly in the `plugins` key. For example, here is an exported config in the old configuration system format for a plugin named `eslint-plugin-example`: + +```js +// plugin name: eslint-plugin-example +module.exports = { + configs: { + + // the config referenced by example/recommended + recommended: { + plugins: ["example"], + rules: { + "example/rule1": "error", + "example/rule2": "error" + } + } + }, + rules: { + rule1: {}, + rule2: {}; + } +}; +``` + +To migrate to flat config format, you'll need to move the configs to after the definition of the `plugin` variable in the recommended plugin structure, like this: + +```js +const plugin = { + configs: {}, + rules: {}, + processors: {} +}; + +// assign configs here so we can reference `plugin` +Object.assign(plugin.configs, { + recommended: { + plugins: { + example: plugin + }, + rules: { + "example/rule1": "error", + "example/rule2": "error" + } + } +}) + +// for ESM +export default plugin; + +// OR for CommonJS +module.exports = plugin; +``` + +Your users can then use this exported config like this: + +```js +import example from "eslint-plugin-example"; + +export default [ + + // use recommended config + example.configs.recommended, + + // and provide your own overrides + { + rules: { + "example/rule1": "warn" + } + } +]; +``` + +You should update our documentation so your plugin users know how to reference the exported configs. + +## Migrating Environments for Flat Config + +Environments are no longer supported in flat config, and so we recommend transitioning your environments into exported configs. For example, suppose you export a `mocha` environment like this: + +```js +// plugin name: eslint-plugin-example +module.exports = { + environments: { + mocha: { + globals: { + it: true, + xit: true, + describe: true, + xdescribe: true + } + } + }, + rules: { + rule1: {}, + rule2: {}; + } +}; +``` + +To migrate this environment into a config, you need to add a new key in the `plugin.configs` object that has a flat config object containing the same information, like this: + +```js +const plugin = { + configs: {}, + rules: {}, + processors: {} +}; + +// assign configs here so we can reference `plugin` +Object.assign(plugin.configs, { + mocha: { + languageOptions: { + globals: { + it: "writeable", + xit: "writeable", + describe: "writeable", + xdescribe: "writeable" + } + } + } +}) + +// for ESM +export default plugin; + +// OR for CommonJS +module.exports = plugin; +``` + +Your users can then use this exported config like this: + +```js +import example from "eslint-plugin-example"; + +export default [ + + // use the mocha globals + example.configs.mocha, + + // and provide your own overrides + { + languageOptions: { + globals: { + it: "readonly" + } + } + } +]; +``` + +You should update your documentation so your plugin users know how to reference the exported configs. + +## Backwards Compatibility + +If your plugin needs to work with both the old and new configuration systems, then you'll need to: + +1. **Export a CommonJS entrypoint.** The old configuration system cannot load plugins that are published only in ESM format. If your source code is in ESM, then you'll need to use a bundler that can generate a CommonJS version and use the [`exports`](https://nodejs.org/api/packages.html#package-entry-points) key in your `package.json` file to ensure the CommonJS version can be found by Node.js. +1. **Keep the `environments` key.** If your plugin exports custom environments, you should keep those as they are and also export the equivalent flat configs as described above. The `environments` key is ignored when ESLint is running in flat config mode. +1. **Export both eslintrc and flat configs.** The `configs` key is only validated when a config is used, so you can provide both formats of configs in the `configs` key. We recommend that you append older format configs with `-legacy` to make it clear that these configs will not be supported in the future. For example, if your primary config is called `recommended` and is in flat config format, then you can also have a config named `recommended-legacy` that is the eslintrc config format. + +## Further Reading + +* [Overview of the flat config file format blog post](https://eslint.org/blog/2022/08/new-config-system-part-2/) +* [API usage of new configuration system blog post](https://eslint.org/blog/2022/08/new-config-system-part-3/) +* [Background to new configuration system blog post](https://eslint.org/blog/2022/08/new-config-system-part-1/) From dcfe5739c374c9d7ed21f14027870ec0fd453661 Mon Sep 17 00:00:00 2001 From: Francesco Trotta Date: Tue, 17 Oct 2023 16:50:14 +0200 Subject: [PATCH 15/24] fix: add preceding semicolon in suggestions of `no-object-constructor` (#17649) * Add semicolon in suggestions of `no-object-constructor` * Apply suggestions from code review * `output` in test suggestions * Apply suggestions --- lib/rules/no-object-constructor.js | 108 +++++++++- tests/lib/rules/no-object-constructor.js | 258 ++++++++++++++++++++++- 2 files changed, 360 insertions(+), 6 deletions(-) diff --git a/lib/rules/no-object-constructor.js b/lib/rules/no-object-constructor.js index 1299779f7ec8..0659d1633816 100644 --- a/lib/rules/no-object-constructor.js +++ b/lib/rules/no-object-constructor.js @@ -9,12 +9,51 @@ // Requirements //------------------------------------------------------------------------------ -const { getVariableByName, isArrowToken } = require("./utils/ast-utils"); +const { getVariableByName, isArrowToken, isClosingBraceToken, isClosingParenToken } = require("./utils/ast-utils"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ +const BREAK_OR_CONTINUE = new Set(["BreakStatement", "ContinueStatement"]); + +// Declaration types that must contain a string Literal node at the end. +const DECLARATIONS = new Set(["ExportAllDeclaration", "ExportNamedDeclaration", "ImportDeclaration"]); + +const IDENTIFIER_OR_KEYWORD = new Set(["Identifier", "Keyword"]); + +// Keywords that can immediately precede an ExpressionStatement node, mapped to the their node types. +const NODE_TYPES_BY_KEYWORD = { + __proto__: null, + break: "BreakStatement", + continue: "ContinueStatement", + debugger: "DebuggerStatement", + do: "DoWhileStatement", + else: "IfStatement", + return: "ReturnStatement", + yield: "YieldExpression" +}; + +/* + * Before an opening parenthesis, `>` (for JSX), and postfix `++` and `--` always trigger ASI; + * the tokens `:`, `;`, `{` and `=>` don't expect a semicolon, as that would count as an empty statement. + */ +const PUNCTUATORS = new Set([":", ";", ">", "{", "=>", "++", "--"]); + +/* + * Statements that can contain an `ExpressionStatement` after a closing parenthesis. + * DoWhileStatement is an exception in that it always triggers ASI after the closing parenthesis. + */ +const STATEMENTS = new Set([ + "DoWhileStatement", + "ForInStatement", + "ForOfStatement", + "ForStatement", + "IfStatement", + "WhileStatement", + "WithStatement" +]); + /** * Tests if a node appears at the beginning of an ancestor ExpressionStatement node. * @param {ASTNode} node The node to check. @@ -53,7 +92,8 @@ module.exports = { messages: { preferLiteral: "The object literal notation {} is preferable.", - useLiteral: "Replace with '{{replacement}}'." + useLiteral: "Replace with '{{replacement}}'.", + useLiteralAfterSemicolon: "Replace with '{{replacement}}', add preceding semicolon." } }, @@ -80,6 +120,50 @@ module.exports = { return false; } + /** + * Determines whether a parenthesized object literal that replaces a specified node needs to be preceded by a semicolon. + * @param {ASTNode} node The node to be replaced. This node should be at the start of an `ExpressionStatement` or at the start of the body of an `ArrowFunctionExpression`. + * @returns {boolean} Whether a semicolon is required before the parenthesized object literal. + */ + function needsSemicolon(node) { + const prevToken = sourceCode.getTokenBefore(node); + + if (!prevToken || prevToken.type === "Punctuator" && PUNCTUATORS.has(prevToken.value)) { + return false; + } + + const prevNode = sourceCode.getNodeByRangeIndex(prevToken.range[0]); + + if (isClosingParenToken(prevToken)) { + return !STATEMENTS.has(prevNode.type); + } + + if (isClosingBraceToken(prevToken)) { + return ( + prevNode.type === "BlockStatement" && prevNode.parent.type === "FunctionExpression" || + prevNode.type === "ClassBody" && prevNode.parent.type === "ClassExpression" || + prevNode.type === "ObjectExpression" + ); + } + + if (IDENTIFIER_OR_KEYWORD.has(prevToken.type)) { + if (BREAK_OR_CONTINUE.has(prevNode.parent.type)) { + return false; + } + + const keyword = prevToken.value; + const nodeType = NODE_TYPES_BY_KEYWORD[keyword]; + + return prevNode.type !== nodeType; + } + + if (prevToken.type === "String") { + return !DECLARATIONS.has(prevNode.parent.type); + } + + return true; + } + /** * Reports on nodes where the `Object` constructor is called without arguments. * @param {ASTNode} node The node to evaluate. @@ -93,16 +177,30 @@ module.exports = { const variable = getVariableByName(sourceCode.getScope(node), "Object"); if (variable && variable.identifiers.length === 0) { - const replacement = needsParentheses(node) ? "({})" : "{}"; + let replacement; + let fixText; + let messageId = "useLiteral"; + + if (needsParentheses(node)) { + replacement = "({})"; + if (needsSemicolon(node)) { + fixText = ";({})"; + messageId = "useLiteralAfterSemicolon"; + } else { + fixText = "({})"; + } + } else { + replacement = fixText = "{}"; + } context.report({ node, messageId: "preferLiteral", suggest: [ { - messageId: "useLiteral", + messageId, data: { replacement }, - fix: fixer => fixer.replaceText(node, replacement) + fix: fixer => fixer.replaceText(node, fixText) } ] }); diff --git a/tests/lib/rules/no-object-constructor.js b/tests/lib/rules/no-object-constructor.js index 789b9e84cb7e..4d51f2a21d69 100644 --- a/tests/lib/rules/no-object-constructor.js +++ b/tests/lib/rules/no-object-constructor.js @@ -104,6 +104,262 @@ ruleTester.run("no-object-constructor", rule, { output: "({} instanceof Object);" }] }] - } + }, + + ...[ + + // Semicolon required before `({})` to compensate for ASI + { + code: ` + foo + Object() + ` + }, + { + code: ` + foo() + Object() + ` + }, + { + code: ` + new foo + Object() + ` + }, + { + code: ` + (a++) + Object() + ` + }, + { + code: ` + ++a + Object() + ` + }, + { + code: ` + const foo = function() {} + Object() + ` + }, + { + code: ` + const foo = class {} + Object() + ` + }, + { + code: ` + foo = this.return + Object() + ` + }, + { + code: ` + var yield = bar.yield + Object() + ` + }, + { + code: ` + var foo = { bar: baz } + Object() + ` + } + ].map(props => ({ + ...props, + errors: [{ + messageId: "preferLiteral", + suggestions: [{ + desc: "Replace with '({})', add preceding semicolon.", + messageId: "useLiteralAfterSemicolon", + output: props.code.replace(/(new )?Object\(\)/u, ";({})") + }] + }] + })), + + ...[ + + // No semicolon required before `({})` because ASI does not occur + { code: "Object()" }, + { + code: ` + {} + Object() + ` + }, + { + code: ` + function foo() {} + Object() + ` + }, + { + code: ` + class Foo {} + Object() + ` + }, + { code: "foo: Object();" }, + { code: "foo();Object();" }, + { code: "{ Object(); }" }, + { code: "if (a) Object();" }, + { code: "if (a); else Object();" }, + { code: "while (a) Object();" }, + { + code: ` + do Object(); + while (a); + ` + }, + { code: "for (let i = 0; i < 10; i++) Object();" }, + { code: "for (const prop in obj) Object();" }, + { code: "for (const element of iterable) Object();" }, + { code: "with (obj) Object();" }, + + // No semicolon required before `({})` because ASI still occurs + { + code: ` + const foo = () => {} + Object() + ` + }, + { + code: ` + a++ + Object() + ` + }, + { + code: ` + a-- + Object() + ` + }, + { + code: ` + function foo() { + return + Object(); + } + ` + }, + { + code: ` + function * foo() { + yield + Object(); + } + ` + }, + { + code: ` + do {} + while (a) + Object() + ` + }, + { + code: ` + debugger + Object() + ` + }, + { + code: ` + for (;;) { + break + Object() + } + ` + }, + { + code: ` + for (;;) { + continue + Object() + } + ` + }, + { + code: ` + foo: break foo + Object() + ` + }, + { + code: ` + foo: while (true) continue foo + Object() + ` + }, + { + code: ` + + Object() + `, + parserOptions: { ecmaFeatures: { jsx: true } } + }, + { + code: ` + + Object() + `, + parserOptions: { ecmaFeatures: { jsx: true } } + }, + { + code: ` + const foo = bar + export { foo } + Object() + `, + parserOptions: { sourceType: "module" } + }, + { + code: ` + export { foo } from 'bar' + Object() + `, + parserOptions: { sourceType: "module" } + }, + { + code: ` + export * as foo from 'bar' + Object() + `, + parserOptions: { sourceType: "module" } + }, + { + code: ` + import foo from 'bar' + Object() + `, + parserOptions: { sourceType: "module" } + }, + { + code: ` + var yield = 5; + + yield: while (foo) { + if (bar) + break yield + new Object(); + } + ` + } + ].map(props => ({ + ...props, + errors: [{ + messageId: "preferLiteral", + suggestions: [{ + desc: "Replace with '({})'.", + messageId: "useLiteral", + output: props.code.replace(/(new )?Object\(\)/u, "({})") + }] + }] + })) ] }); From 70648ee49c07f7b533d09f6bf8a5291e5a5a8601 Mon Sep 17 00:00:00 2001 From: Yosuke Ota Date: Wed, 18 Oct 2023 00:08:38 +0900 Subject: [PATCH 16/24] feat: report-unused-disable-directive to report unused eslint-enable (#17611) * feat: report-unused-disable-directive to report unused eslint-enable * test: fix test case * chore: refactor * test: add test cases * chore: update order * chore: fix test case order * fix: revert test case * docs: update docs * chore: minor refactor * fix: false positive * chore: update comment * Update lib/linter/apply-disable-directives.js Co-authored-by: Milos Djermanovic * chore: refactored collectUsedEnableDirectives to return a Set * Update lib/linter/apply-disable-directives.js Co-authored-by: Milos Djermanovic * Update lib/linter/apply-disable-directives.js Co-authored-by: Nicholas C. Zakas * fix: doc comments * test: fix test cases * fix: remove withoutRuleIdKey and fix jsdoc * chore: refactor jsdoc * Update lib/linter/apply-disable-directives.js Co-authored-by: Milos Djermanovic --------- Co-authored-by: Milos Djermanovic Co-authored-by: Nicholas C. Zakas --- docs/src/integrate/nodejs-api.md | 4 +- docs/src/use/command-line-interface.md | 4 +- .../use/configure/configuration-files-new.md | 6 +- lib/linter/apply-disable-directives.js | 138 +- lib/options.js | 4 +- tests/lib/linter/apply-disable-directives.js | 1807 ++++++++++++++--- tests/lib/linter/linter.js | 1252 +++++++++++- 7 files changed, 2847 insertions(+), 368 deletions(-) diff --git a/docs/src/integrate/nodejs-api.md b/docs/src/integrate/nodejs-api.md index 5560a8080a0e..744f98295f49 100644 --- a/docs/src/integrate/nodejs-api.md +++ b/docs/src/integrate/nodejs-api.md @@ -152,7 +152,7 @@ The `ESLint` constructor takes an `options` object. If you omit the `options` ob * `options.plugins` (`Record | null`)
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`)
- 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. + Default is `null`. The severity to report unused eslint-disable and eslint-enable directives. If this option is a severity, it overrides the `reportUnusedDisableDirectives` setting in your configurations. * `options.resolvePluginsRelativeTo` (`string` | `null`)
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[]`)
@@ -537,7 +537,7 @@ The most important method on `Linter` is `verify()`, which initiates linting of * `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. + * `reportUnusedDisableDirectives` - (optional) when set to `true`, adds reported errors for unused `eslint-disable` and `eslint-enable` 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`. diff --git a/docs/src/use/command-line-interface.md b/docs/src/use/command-line-interface.md index da4faf70ebae..6087aae4fcc6 100644 --- a/docs/src/use/command-line-interface.md +++ b/docs/src/use/command-line-interface.md @@ -97,7 +97,7 @@ Output: 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 + --report-unused-disable-directives Adds reported errors for unused eslint-disable and eslint-enable directives Caching: --cache Only check changed files - default: false @@ -577,7 +577,7 @@ This option causes ESLint to report directive comments like `// eslint-disable-l * **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. +This can be useful to prevent future errors from unexpectedly being suppressed, by cleaning up old `eslint-disable` and `eslint-enable` 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. diff --git a/docs/src/use/configure/configuration-files-new.md b/docs/src/use/configure/configuration-files-new.md index 2d472a4e7e15..d3ba4cd2bcfb 100644 --- a/docs/src/use/configure/configuration-files-new.md +++ b/docs/src/use/configure/configuration-files-new.md @@ -76,7 +76,7 @@ Each configuration object contains all of the information ESLint needs to execut * `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. + * `reportUnusedDisableDirectives` - A Boolean value indicating if unused disable and enable 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. @@ -244,7 +244,7 @@ export default [ #### 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: +Disable and enable directives such as `/*eslint-disable*/`, `/*eslint-enable*/` 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 [ @@ -257,7 +257,7 @@ export default [ ]; ``` -By default, unused disable directives are reported as warnings. You can change this setting using the `--report-unused-disable-directives` command line option. +By default, unused disable and enable directives are reported as warnings. You can change this setting using the `--report-unused-disable-directives` command line option. ### Configuring language options diff --git a/lib/linter/apply-disable-directives.js b/lib/linter/apply-disable-directives.js index 55f7683f3f53..c5e3c9ddc1ce 100644 --- a/lib/linter/apply-disable-directives.js +++ b/lib/linter/apply-disable-directives.js @@ -30,7 +30,7 @@ function compareLocations(itemA, itemB) { /** * Groups a set of directives into sub-arrays by their parent comment. - * @param {Directive[]} directives Unused directives to be removed. + * @param {Iterable} directives Unused directives to be removed. * @returns {Directive[][]} Directives grouped by their parent comment. */ function groupByParentComment(directives) { @@ -177,10 +177,10 @@ function createCommentRemoval(directives, commentToken) { /** * Parses details from directives to create output Problems. - * @param {Directive[]} allDirectives Unused directives to be removed. + * @param {Iterable} allDirectives Unused directives to be removed. * @returns {{ description, fix, unprocessedDirective }[]} Details for later creation of output Problems. */ -function processUnusedDisableDirectives(allDirectives) { +function processUnusedDirectives(allDirectives) { const directiveGroups = groupByParentComment(allDirectives); return directiveGroups.flatMap( @@ -199,6 +199,95 @@ function processUnusedDisableDirectives(allDirectives) { ); } +/** + * Collect eslint-enable comments that are removing suppressions by eslint-disable comments. + * @param {Directive[]} directives The directives to check. + * @returns {Set} The used eslint-enable comments + */ +function collectUsedEnableDirectives(directives) { + + /** + * A Map of `eslint-enable` keyed by ruleIds that may be marked as used. + * If `eslint-enable` does not have a ruleId, the key will be `null`. + * @type {Map} + */ + const enabledRules = new Map(); + + /** + * A Set of `eslint-enable` marked as used. + * It is also the return value of `collectUsedEnableDirectives` function. + * @type {Set} + */ + const usedEnableDirectives = new Set(); + + /* + * Checks the directives backwards to see if the encountered `eslint-enable` is used by the previous `eslint-disable`, + * and if so, stores the `eslint-enable` in `usedEnableDirectives`. + */ + for (let index = directives.length - 1; index >= 0; index--) { + const directive = directives[index]; + + if (directive.type === "disable") { + if (enabledRules.size === 0) { + continue; + } + if (directive.ruleId === null) { + + // If encounter `eslint-disable` without ruleId, + // mark all `eslint-enable` currently held in enabledRules as used. + // e.g. + // /* eslint-disable */ <- current directive + // /* eslint-enable rule-id1 */ <- used + // /* eslint-enable rule-id2 */ <- used + // /* eslint-enable */ <- used + for (const enableDirective of enabledRules.values()) { + usedEnableDirectives.add(enableDirective); + } + enabledRules.clear(); + } else { + const enableDirective = enabledRules.get(directive.ruleId); + + if (enableDirective) { + + // If encounter `eslint-disable` with ruleId, and there is an `eslint-enable` with the same ruleId in enabledRules, + // mark `eslint-enable` with ruleId as used. + // e.g. + // /* eslint-disable rule-id */ <- current directive + // /* eslint-enable rule-id */ <- used + usedEnableDirectives.add(enableDirective); + } else { + const enabledDirectiveWithoutRuleId = enabledRules.get(null); + + if (enabledDirectiveWithoutRuleId) { + + // If encounter `eslint-disable` with ruleId, and there is no `eslint-enable` with the same ruleId in enabledRules, + // mark `eslint-enable` without ruleId as used. + // e.g. + // /* eslint-disable rule-id */ <- current directive + // /* eslint-enable */ <- used + usedEnableDirectives.add(enabledDirectiveWithoutRuleId); + } + } + } + } else if (directive.type === "enable") { + if (directive.ruleId === null) { + + // If encounter `eslint-enable` without ruleId, the `eslint-enable` that follows it are unused. + // So clear enabledRules. + // e.g. + // /* eslint-enable */ <- current directive + // /* eslint-enable rule-id *// <- unused + // /* eslint-enable */ <- unused + enabledRules.clear(); + enabledRules.set(null, directive); + } else { + enabledRules.set(directive.ruleId, directive); + } + } + } + return usedEnableDirectives; +} + /** * This is the same as the exported function, except that it * doesn't handle disable-line and disable-next-line directives, and it always reports unused @@ -206,7 +295,7 @@ function processUnusedDisableDirectives(allDirectives) { * @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: LintMessage[], unusedDisableDirectives: LintMessage[]}} An object with a list + * @returns {{problems: LintMessage[], unusedDirectives: LintMessage[]}} An object with a list * of problems (including suppressed ones) and unused eslint-disable directives */ function applyDirectives(options) { @@ -258,17 +347,42 @@ function applyDirectives(options) { const unusedDisableDirectivesToReport = options.directives .filter(directive => directive.type === "disable" && !usedDisableDirectives.has(directive)); - const processed = processUnusedDisableDirectives(unusedDisableDirectivesToReport); - const unusedDisableDirectives = processed + const unusedEnableDirectivesToReport = new Set( + options.directives.filter(directive => directive.unprocessedDirective.type === "enable") + ); + + /* + * If directives has the eslint-enable directive, + * check whether the eslint-enable comment is used. + */ + if (unusedEnableDirectivesToReport.size > 0) { + for (const directive of collectUsedEnableDirectives(options.directives)) { + unusedEnableDirectivesToReport.delete(directive); + } + } + + const processed = processUnusedDirectives(unusedDisableDirectivesToReport) + .concat(processUnusedDirectives(unusedEnableDirectivesToReport)); + + const unusedDirectives = processed .map(({ description, fix, unprocessedDirective }) => { const { parentComment, type, line, column } = unprocessedDirective; + let message; + + if (type === "enable") { + message = description + ? `Unused eslint-enable directive (no matching eslint-disable directives were found for ${description}).` + : "Unused eslint-enable directive (no matching eslint-disable directives were found)."; + } else { + message = description + ? `Unused eslint-disable directive (no problems were reported from ${description}).` + : "Unused eslint-disable directive (no problems were reported)."; + } return { ruleId: null, - message: description - ? `Unused eslint-disable directive (no problems were reported from ${description}).` - : "Unused eslint-disable directive (no problems were reported).", + message, line: type === "disable-next-line" ? parentComment.commentToken.loc.start.line : line, column: type === "disable-next-line" ? parentComment.commentToken.loc.start.column + 1 : column, severity: options.reportUnusedDisableDirectives === "warn" ? 1 : 2, @@ -277,7 +391,7 @@ function applyDirectives(options) { }; }); - return { problems, unusedDisableDirectives }; + return { problems, unusedDirectives }; } /** @@ -344,8 +458,8 @@ module.exports = ({ directives, disableFixes, problems, reportUnusedDisableDirec return reportUnusedDisableDirectives !== "off" ? lineDirectivesResult.problems - .concat(blockDirectivesResult.unusedDisableDirectives) - .concat(lineDirectivesResult.unusedDisableDirectives) + .concat(blockDirectivesResult.unusedDirectives) + .concat(lineDirectivesResult.unusedDirectives) .sort(compareLocations) : lineDirectivesResult.problems; }; diff --git a/lib/options.js b/lib/options.js index ae9a5d5552a2..81c0fa60ab98 100644 --- a/lib/options.js +++ b/lib/options.js @@ -47,7 +47,7 @@ const optionator = require("optionator"); * @property {Object} [parserOptions] Specify parser options * @property {string[]} [plugin] Specify plugins * @property {string} [printConfig] Print the configuration for the given file - * @property {boolean | undefined} reportUnusedDisableDirectives Adds reported errors for unused eslint-disable directives + * @property {boolean | undefined} reportUnusedDisableDirectives Adds reported errors for unused eslint-disable and eslint-enable directives * @property {string} [resolvePluginsRelativeTo] A folder where plugins should be resolved from, CWD by default * @property {Object} [rule] Specify rules * @property {string[]} [rulesdir] Load additional rules from this directory. Deprecated: Use rules from plugins @@ -304,7 +304,7 @@ module.exports = function(usingFlatConfig) { option: "report-unused-disable-directives", type: "Boolean", default: void 0, - description: "Adds reported errors for unused eslint-disable directives" + description: "Adds reported errors for unused eslint-disable and eslint-enable directives" }, { heading: "Caching" diff --git a/tests/lib/linter/apply-disable-directives.js b/tests/lib/linter/apply-disable-directives.js index de56f729627f..d56bf5bc1b0f 100644 --- a/tests/lib/linter/apply-disable-directives.js +++ b/tests/lib/linter/apply-disable-directives.js @@ -680,7 +680,7 @@ describe("apply-disable-directives", () => { applyDisableDirectives({ directives: [ { parentComment: createParentComment([0, 31]), type: "disable-next-line", line: 1, column: 1, ruleId: null, justification: "j1" }, - { type: "enable", line: 1, column: 5, ruleId: null, justification: "j2" } + { parentComment: createParentComment([31, 50]), type: "enable", line: 1, column: 31, ruleId: null, justification: "j2" } ], problems: [{ line: 2, column: 2, ruleId: "foo" }] }), @@ -1365,28 +1365,140 @@ describe("apply-disable-directives", () => { ); }); - it("Adds a problem for // eslint-disable-line", () => { + it("Adds a problem for /* eslint-enable */", () => { assert.deepStrictEqual( applyDisableDirectives({ directives: [{ - parentComment: createParentComment([0, 22]), - type: "disable-line", + parentComment: createParentComment([0, 20]), + type: "enable", line: 1, column: 1, - ruleId: null, justification: "justification" }], problems: [], reportUnusedDisableDirectives: "error" }), + [{ + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + line: 1, + column: 1, + fix: { + range: [0, 20], + text: " " + }, + severity: 2, + nodeType: null + }] + ); + }); + + it("Does not fix a problem for /* eslint-enable */ when disableFixes is enabled", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [{ + parentComment: createParentComment([0, 20]), + type: "enable", + line: 1, + column: 1, + justification: "justification" + }], + disableFixes: true, + problems: [], + reportUnusedDisableDirectives: "error" + }), + [{ + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + line: 1, + column: 1, + severity: 2, + nodeType: null + }] + ); + }); + + it("Does not add a problem for /* eslint-disable */ /* (problem) */ /* eslint-enable */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { type: "disable", line: 1, column: 1, ruleId: null, justification: "justification" }, + { type: "enable", line: 3, column: 1, ruleId: null, justification: "justification" } + ], + problems: [{ line: 2, column: 1, ruleId: "foo" }], + reportUnusedDisableDirectives: "error" + }), + [{ line: 2, column: 1, ruleId: "foo", suppressions: [{ kind: "directive", justification: "justification" }] }] + ); + }); + + it("Adds a problem for /* eslint-enable foo */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [{ + parentComment: createParentComment([0, 21]), + type: "enable", + line: 1, + column: 1, + ruleId: "foo", + justification: "justification" + }], + problems: [], + reportUnusedDisableDirectives: "error" + }), + [{ + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'foo').", + line: 1, + column: 1, + fix: { + range: [0, 21], + text: " " + }, + severity: 2, + nodeType: null + }] + ); + }); + + it("Adds a problem for /* eslint-disable not-foo */ /* (problem from not-foo) */ /* eslint-enable foo */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment: createParentComment([0, 24]), + type: "disable", + line: 1, + column: 1, + ruleId: "not-foo", + justification: "justification" + }, + { + parentComment: createParentComment([48, 72]), + type: "enable", + line: 3, + column: 1, + ruleId: "foo", + justification: "justification" + } + ], + problems: [{ line: 2, column: 1, ruleId: "not-foo" }], + reportUnusedDisableDirectives: "error" + }), [ + { + ruleId: "not-foo", + line: 2, + column: 1, + suppressions: [{ justification: "justification", kind: "directive" }] + }, { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported).", - line: 1, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'foo').", + line: 3, column: 1, fix: { - range: [0, 22], + range: [48, 72], text: " " }, severity: 2, @@ -1396,40 +1508,1155 @@ describe("apply-disable-directives", () => { ); }); + it("Adds a problem for /* eslint-disable foo */ /* (problem from foo) */ /* eslint-enable */ /* eslint-enable */ /* eslint-enable foo */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment: createParentComment([0, 21]), + type: "disable", + line: 1, + column: 1, + ruleId: "foo", + justification: "j1" + }, + { + parentComment: createParentComment([42, 63]), + type: "enable", + line: 3, + column: 1, + ruleId: null, + justification: "j1" + }, + { + parentComment: createParentComment([63, 84]), + type: "enable", + line: 4, + column: 1, + ruleId: null, + justification: "j1" + }, + { + parentComment: createParentComment([84, 105]), + type: "enable", + line: 5, + column: 1, + ruleId: "foo", + justification: "j2" + } + ], + problems: [{ line: 2, column: 1, ruleId: "foo" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: "foo", + line: 2, + column: 1, + suppressions: [{ justification: "j1", kind: "directive" }] + }, + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + fix: { + range: [63, 84], + text: " " + }, + line: 4, + column: 1, + severity: 2, + nodeType: null + }, + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'foo').", + fix: { + range: [84, 105], + text: " " + }, + line: 5, + column: 1, + severity: 2, + nodeType: null + } + ] + ); + }); - it("Does not add a problem for // eslint-disable-line (problem)", () => { + it("Adds a problem for /* eslint-disable foo */ /* (problem from foo) */ /* eslint-enable */ /* eslint-enable */", () => { assert.deepStrictEqual( applyDisableDirectives({ - directives: [{ type: "disable-line", line: 1, column: 1, ruleId: null, justification: "justification" }], - problems: [{ line: 1, column: 10, ruleId: "foo" }], + directives: [ + { + parentComment: createParentComment([0, 21]), + type: "disable", + line: 1, + column: 1, + ruleId: "foo", + justification: "j1" + }, + { + parentComment: createParentComment([42, 63]), + type: "enable", + line: 3, + column: 1, + ruleId: null, + justification: "j1" + }, + { + parentComment: createParentComment([63, 84]), + type: "enable", + line: 4, + column: 1, + ruleId: null, + justification: "j1" + } + ], + problems: [{ line: 2, column: 1, ruleId: "foo" }], reportUnusedDisableDirectives: "error" }), - [{ line: 1, column: 10, ruleId: "foo", suppressions: [{ kind: "directive", justification: "justification" }] }] + [ + { + ruleId: "foo", + line: 2, + column: 1, + suppressions: [{ justification: "j1", kind: "directive" }] + }, + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + fix: { + range: [63, 84], + text: " " + }, + line: 4, + column: 1, + severity: 2, + nodeType: null + } + ] ); }); - it("Adds a problem for // eslint-disable-next-line", () => { + it("Adds two problems for /* eslint-enable */ /* eslint-enable */", () => { assert.deepStrictEqual( applyDisableDirectives({ - directives: [{ - parentComment: createParentComment([0, 27]), - type: "disable-next-line", + directives: [ + { + parentComment: createParentComment([0, 21]), + type: "enable", + line: 1, + column: 1, + ruleId: null, + justification: "j1" + }, + { + parentComment: createParentComment([21, 42]), + type: "enable", + line: 2, + column: 1, + ruleId: null, + justification: "j2" + } + ], + problems: [], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", line: 1, - column: 2, + column: 1, + fix: { + range: [0, 21], + text: " " + }, + severity: 2, + nodeType: null + }, + { ruleId: null, - justification: "justification" - }], + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + line: 2, + column: 1, + fix: { + range: [21, 42], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + }); + + it("Adds a problem for /* eslint-enable */ /* eslint-disable */ /* (problem) */ /* eslint-enable */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment: createParentComment([0, 21]), + type: "enable", + line: 1, + column: 1, + ruleId: null, + justification: "j1" + }, + { + parentComment: createParentComment([21, 42]), + type: "disable", + line: 2, + column: 1, + ruleId: null, + justification: "j2" + }, + { + parentComment: createParentComment([63, 84]), + type: "enable", + line: 4, + column: 1, + ruleId: null, + justification: "j3" + } + ], + problems: [{ line: 3, column: 1, ruleId: "foo" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + line: 1, + column: 1, + fix: { + range: [0, 21], + text: " " + }, + severity: 2, + nodeType: null + }, + { + line: 3, + column: 1, + ruleId: "foo", + suppressions: [{ kind: "directive", justification: "j2" }] + } + ] + ); + }); + + it("Adds a problem for /* eslint-disable foo */ /* (problem from foo) */ /* eslint-enable */ /* eslint-enable foo */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment: createParentComment([0, 21]), + type: "disable", + line: 1, + column: 1, + ruleId: "foo", + justification: "j1" + }, + { + parentComment: createParentComment([42, 63]), + type: "enable", + line: 3, + column: 1, + ruleId: null, + justification: "j2" + }, + { + parentComment: createParentComment([63, 84]), + type: "enable", + line: 4, + column: 1, + ruleId: "foo", + justification: "j3" + } + ], + problems: [{ line: 2, column: 1, ruleId: "foo" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + line: 2, + column: 1, + ruleId: "foo", + suppressions: [{ kind: "directive", justification: "j1" }] + }, + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'foo').", + line: 4, + column: 1, + fix: { + range: [63, 84], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + }); + + it("Does not add a problem for /* eslint-disable foo */ /* (problem from foo) */ /* eslint-enable foo */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { type: "disable", line: 1, column: 1, ruleId: "foo", justification: "j1" }, + { type: "enable", line: 3, column: 1, ruleId: "foo", justification: "j2" } + ], + problems: [{ line: 2, column: 1, ruleId: "foo" }], + reportUnusedDisableDirectives: "error" + }), + [{ line: 2, column: 1, ruleId: "foo", suppressions: [{ kind: "directive", justification: "j1" }] }] + ); + }); + + it("Adds a problem for /* eslint-disable foo */ /* (problem from foo) */ /* eslint-enable foo */ /* eslint-enable */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment: createParentComment([0, 21]), + type: "disable", + line: 1, + column: 1, + ruleId: "foo", + justification: "j1" + }, + { + parentComment: createParentComment([42, 63]), + type: "enable", + line: 3, + column: 1, + ruleId: "foo", + justification: "j2" + }, + { + parentComment: createParentComment([63, 84]), + type: "enable", + line: 4, + column: 1, + ruleId: null, + justification: "j3" + } + ], + problems: [{ line: 2, column: 1, ruleId: "foo" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + line: 2, + column: 1, + ruleId: "foo", + suppressions: [ + { kind: "directive", justification: "j1" } + ] + }, + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + line: 4, + column: 1, + fix: { + range: [63, 84], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + }); + + it("Adds a problem for /* eslint-disable bar */ /* (problem from bar) */ /* eslint-enable foo */ /* eslint-enable */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment: createParentComment([0, 20]), + type: "disable", + line: 1, + column: 1, + ruleId: "bar", + justification: "j1" + }, + { + parentComment: createParentComment([60, 80]), + type: "enable", + line: 3, + column: 1, + ruleId: "foo", + justification: "j2" + }, + { + parentComment: createParentComment([80, 100]), + type: "enable", + line: 4, + column: 1, + ruleId: null, + justification: "j3" + } + ], + problems: [{ line: 2, column: 1, ruleId: "bar" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + line: 2, + column: 1, + ruleId: "bar", + suppressions: [{ kind: "directive", justification: "j1" }] + }, + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'foo').", + line: 3, + column: 1, + fix: { + range: [60, 80], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + }); + + it("Adds a problem for /* eslint-disable foo */ /* (problem from foo) */ /* eslint-enable foo */ /* eslint-enable */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment: createParentComment([0, 20]), + type: "disable", + line: 1, + column: 1, + ruleId: "foo", + justification: "j1" + }, + { + parentComment: createParentComment([60, 80]), + type: "enable", + line: 3, + column: 1, + ruleId: "foo", + justification: "j2" + }, + { + parentComment: createParentComment([80, 100]), + type: "enable", + line: 4, + column: 1, + ruleId: "foo", + justification: "j3" + } + ], + problems: [{ line: 2, column: 1, ruleId: "foo" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + line: 2, + column: 1, + ruleId: "foo", + suppressions: [{ kind: "directive", justification: "j1" }] + }, + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'foo').", + line: 4, + column: 1, + fix: { + range: [80, 100], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + }); + + it("Adds two problems for /* eslint-disable foo */ /* (problem from foo) */ /* eslint-enable foo */ /* eslint-enable foo */ /* eslint-enable */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment: createParentComment([0, 20]), + type: "disable", + line: 1, + column: 1, + ruleId: "foo", + justification: "j1" + }, + { + parentComment: createParentComment([40, 60]), + type: "enable", + line: 3, + column: 1, + ruleId: "foo", + justification: "j2" + }, + { + parentComment: createParentComment([60, 80]), + type: "enable", + line: 4, + column: 1, + ruleId: "foo", + justification: "j3" + }, + { + parentComment: createParentComment([80, 100]), + type: "enable", + line: 5, + column: 1, + ruleId: null, + justification: "j4" + } + ], + problems: [{ line: 2, column: 1, ruleId: "foo" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: "foo", + line: 2, + column: 1, + suppressions: [{ kind: "directive", justification: "j1" }] + }, + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'foo').", + line: 4, + column: 1, + fix: { + range: [60, 80], + text: " " + }, + severity: 2, + nodeType: null + }, + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + line: 5, + column: 1, + fix: { + range: [80, 100], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + }); + + it("Adds a problem for /* eslint-disable used */ /* (problem from used) */ /* eslint-disable used */ /* (problem from used) */ /* eslint-enable used */ /* eslint-enable */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment: createParentComment([0, 20]), + ruleId: "used", + type: "disable", + line: 1, + column: 1, + justification: "j1" + }, + { + parentComment: createParentComment([40, 60]), + ruleId: "used", + type: "disable", + line: 3, + column: 1, + justification: "j2" + }, + { + parentComment: createParentComment([80, 100]), + ruleId: "used", + type: "enable", + line: 5, + column: 1, + justification: "j3" + }, + { + parentComment: createParentComment([100, 120]), + ruleId: null, + type: "enable", + line: 6, + column: 1, + justification: "j4" + } + ], + problems: [{ line: 2, column: 1, ruleId: "used" }, { line: 4, column: 1, ruleId: "used" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j1" }] + }, + { + line: 4, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j1" }, { kind: "directive", justification: "j2" }] + }, + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + line: 6, + column: 1, + fix: { + range: [100, 120], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + }); + + it("Adds a problem for // eslint-disable-line", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [{ + parentComment: createParentComment([0, 22]), + type: "disable-line", + line: 1, + column: 1, + ruleId: null, + justification: "justification" + }], + problems: [], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported).", + line: 1, + column: 1, + fix: { + range: [0, 22], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + }); + + + it("Does not add a problem for // eslint-disable-line (problem)", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [{ type: "disable-line", line: 1, column: 1, ruleId: null, justification: "justification" }], + problems: [{ line: 1, column: 10, ruleId: "foo" }], + reportUnusedDisableDirectives: "error" + }), + [{ line: 1, column: 10, ruleId: "foo", suppressions: [{ kind: "directive", justification: "justification" }] }] + ); + }); + + it("Adds a problem for // eslint-disable-next-line", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [{ + parentComment: createParentComment([0, 27]), + type: "disable-next-line", + line: 1, + column: 2, + ruleId: null, + justification: "justification" + }], + problems: [], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported).", + line: 1, + column: 2, + fix: { + range: [0, 27], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + }); + + it("Does not add a problem for // eslint-disable-next-line \\n (problem)", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [{ type: "disable-next-line", line: 1, column: 1, ruleId: null, justification: "justification" }], + problems: [{ line: 2, column: 10, ruleId: "foo" }], + reportUnusedDisableDirectives: "error" + }), + [{ line: 2, column: 10, ruleId: "foo", suppressions: [{ kind: "directive", justification: "justification" }] }] + ); + }); + + it("adds two problems for /* eslint-disable */ // eslint-disable-line", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { parentComment: createParentComment([0, 20]), type: "disable", line: 1, column: 1, ruleId: null }, + { parentComment: createParentComment([20, 43]), type: "disable-line", line: 1, column: 22, ruleId: null } + ], + problems: [], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported).", + line: 1, + column: 1, + fix: { + range: [0, 20], + text: " " + }, + severity: 2, + nodeType: null + }, + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported).", + line: 1, + column: 22, + fix: { + range: [20, 43], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + }); + + it("Does not add problems when reportUnusedDisableDirectives: \"off\" is used", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [{ + parentComment: createParentComment([0, 27]), + type: "disable-next-line", + line: 1, + column: 1, + ruleId: null, + justification: "justification" + }], + problems: [], + reportUnusedDisableDirectives: "off" + }), + [] + ); + }); + }); + + describe("unused rules within directives", () => { + it("Adds a problem for /* eslint-disable used, unused */", () => { + const parentComment = createParentComment([0, 32], " eslint-disable used, unused ", ["used", "unused"]); + + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment, + ruleId: "used", + type: "disable", + line: 1, + column: 18, + justification: "j1" + }, + { + parentComment, + ruleId: "unused", + type: "disable", + line: 1, + column: 22, + justification: "j2" + } + ], + problems: [{ line: 2, column: 1, ruleId: "used" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'unused').", + line: 1, + column: 22, + fix: { + range: [22, 30], + text: "" + }, + severity: 2, + nodeType: null + }, + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j1" }] + } + ] + ); + }); + it("Adds a problem for /* eslint-disable used , unused , -- unused and used are ok */", () => { + const parentComment = createParentComment([0, 62], " eslint-disable used , unused , -- unused and used are ok ", ["used", "unused"]); + + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment, + ruleId: "used", + type: "disable", + line: 1, + column: 18, + justification: "j1" + }, + { + parentComment, + ruleId: "unused", + type: "disable", + line: 1, + column: 24, + justification: "j2" + } + ], + problems: [{ line: 2, column: 1, ruleId: "used" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'unused').", + line: 1, + column: 24, + fix: { + range: [23, 32], + text: "" + }, + severity: 2, + nodeType: null + }, + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j1" }] + } + ] + ); + }); + + it("Adds a problem for /* eslint-disable unused, used */", () => { + const parentComment = createParentComment([0, 32], " eslint-disable unused, used ", ["unused", "used"]); + + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment, + ruleId: "unused", + type: "disable", + line: 1, + column: 18, + justification: "j1" + }, + { + parentComment, + ruleId: "used", + type: "disable", + line: 1, + column: 25, + justification: "j2" + } + ], + problems: [{ line: 2, column: 1, ruleId: "used" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'unused').", + line: 1, + column: 18, + fix: { + range: [18, 26], + text: "" + }, + severity: 2, + nodeType: null + }, + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j2" }] + } + ] + ); + }); + + it("Adds a problem for /* eslint-disable unused,, ,, used */", () => { + const parentComment = createParentComment([0, 37], " eslint-disable unused,, ,, used ", ["unused", "used"]); + + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment, + ruleId: "unused", + type: "disable", + line: 1, + column: 18, + justification: "j1" + }, + { + parentComment, + ruleId: "used", + type: "disable", + line: 1, + column: 29, + justification: "j2" + } + ], + problems: [{ line: 2, column: 1, ruleId: "used" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'unused').", + line: 1, + column: 18, + fix: { + range: [18, 25], + text: "" + }, + severity: 2, + nodeType: null + }, + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j2" }] + } + ] + ); + }); + + it("Adds a problem for /* eslint-disable unused-1, unused-2, used */", () => { + const parentComment = createParentComment([0, 45], " eslint-disable unused-1, unused-2, used ", ["unused-1", "unused-2", "used"]); + + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment, + ruleId: "unused-1", + type: "disable", + line: 1, + column: 18, + justification: "j1" + }, + { + parentComment, + ruleId: "unused-2", + type: "disable", + line: 1, + column: 28, + justification: "j2" + }, + { + parentComment, + ruleId: "used", + type: "disable", + line: 1, + column: 38, + justification: "j3" + } + ], + problems: [{ line: 2, column: 1, ruleId: "used" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'unused-1').", + line: 1, + column: 18, + fix: { + range: [18, 28], + text: "" + }, + severity: 2, + nodeType: null + }, + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'unused-2').", + line: 1, + column: 28, + fix: { + range: [26, 36], + text: "" + }, + severity: 2, + nodeType: null + }, + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j3" }] + } + ] + ); + }); + + it("Adds a problem for /* eslint-disable unused-1, unused-2, used, unused-3 */", () => { + const parentComment = createParentComment([0, 55], " eslint-disable unused-1, unused-2, used, unused-3 ", ["unused-1", "unused-2", "used", "unused-3"]); + + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment, + ruleId: "unused-1", + type: "disable", + line: 1, + column: 18, + justification: "j1" + }, + { + parentComment, + ruleId: "unused-2", + type: "disable", + line: 1, + column: 28, + justification: "j2" + }, + { + parentComment, + ruleId: "used", + type: "disable", + line: 1, + column: 38, + justification: "j3" + }, + { + parentComment, + ruleId: "unused-3", + type: "disable", + line: 1, + column: 43, + justification: "j4" + } + ], + problems: [{ line: 2, column: 1, ruleId: "used" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'unused-1').", + line: 1, + column: 18, + fix: { + range: [18, 28], + text: "" + }, + severity: 2, + nodeType: null + }, + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'unused-2').", + line: 1, + column: 28, + fix: { + range: [26, 36], + text: "" + }, + severity: 2, + nodeType: null + }, + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'unused-3').", + line: 1, + column: 43, + fix: { + range: [42, 52], + text: "" + }, + severity: 2, + nodeType: null + }, + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j3" }] + } + ] + ); + }); + + it("Adds a problem for /* eslint-disable unused-1, unused-2 */", () => { + const parentComment = createParentComment([0, 39], " eslint-disable unused-1, unused-2 ", ["unused-1", "unused-2"]); + + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment, + ruleId: "unused-1", + type: "disable", + line: 1, + column: 18, + justification: "j1" + }, + { + parentComment, + ruleId: "unused-2", + type: "disable", + line: 1, + column: 28, + justification: "j2" + } + ], problems: [], reportUnusedDisableDirectives: "error" }), [ { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported).", + message: "Unused eslint-disable directive (no problems were reported from 'unused-1' or 'unused-2').", line: 1, - column: 2, + column: 18, fix: { - range: [0, 27], + range: [0, 39], text: " " }, severity: 2, @@ -1439,23 +2666,33 @@ describe("apply-disable-directives", () => { ); }); - it("Does not add a problem for // eslint-disable-next-line \\n (problem)", () => { - assert.deepStrictEqual( - applyDisableDirectives({ - directives: [{ type: "disable-next-line", line: 1, column: 1, ruleId: null, justification: "justification" }], - problems: [{ line: 2, column: 10, ruleId: "foo" }], - reportUnusedDisableDirectives: "error" - }), - [{ line: 2, column: 10, ruleId: "foo", suppressions: [{ kind: "directive", justification: "justification" }] }] - ); - }); + it("Adds a problem for /* eslint-disable unused-1, unused-2, unused-3 */", () => { + const parentComment = createParentComment([0, 49], " eslint-disable unused-1, unused-2, unused-3 ", ["unused-1", "unused-2", "unused-3"]); - it("adds two problems for /* eslint-disable */ // eslint-disable-line", () => { assert.deepStrictEqual( applyDisableDirectives({ directives: [ - { parentComment: createParentComment([0, 20]), type: "disable", line: 1, column: 1, ruleId: null }, - { parentComment: createParentComment([20, 43]), type: "disable-line", line: 1, column: 22, ruleId: null } + { + parentComment, + ruleId: "unused-1", + type: "disable", + line: 1, + column: 18 + }, + { + parentComment, + ruleId: "unused-2", + type: "disable", + line: 1, + column: 28 + }, + { + parentComment, + ruleId: "unused-3", + type: "disable", + line: 1, + column: 38 + } ], problems: [], reportUnusedDisableDirectives: "error" @@ -1463,23 +2700,11 @@ describe("apply-disable-directives", () => { [ { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported).", - line: 1, - column: 1, - fix: { - range: [0, 20], - text: " " - }, - severity: 2, - nodeType: null - }, - { - ruleId: null, - message: "Unused eslint-disable directive (no problems were reported).", + message: "Unused eslint-disable directive (no problems were reported from 'unused-1', 'unused-2', or 'unused-3').", line: 1, - column: 22, + column: 18, fix: { - range: [20, 43], + range: [0, 49], text: " " }, severity: 2, @@ -1489,263 +2714,356 @@ describe("apply-disable-directives", () => { ); }); - it("Does not add problems when reportUnusedDisableDirectives: \"off\" is used", () => { + it("Adds a problem for /* eslint-disable foo */ \\n (problem from foo and bar) // eslint-disable-line foo, bar", () => { assert.deepStrictEqual( applyDisableDirectives({ - directives: [{ - parentComment: createParentComment([0, 27]), - type: "disable-next-line", - line: 1, + directives: [ + { + parentComment: createParentComment([0, 29], " eslint-disable foo ", ["foo"]), + ruleId: "foo", + type: "disable", + line: 1, + column: 1, + justification: "j1" + }, + { + parentComment: createParentComment([41, 81], " eslint-disable-line foo, bar", ["foo", "bar"]), + ruleId: "foo", + type: "disable-line", + line: 2, + column: 11, + justification: "j2" + }, + { + parentComment: createParentComment([41, 81], " eslint-disable-line foo, bar ", ["foo", "bar"]), + ruleId: "bar", + type: "disable-line", + line: 2, + column: 11, + justification: "j2" + } + ], + problems: [ + { line: 2, column: 1, ruleId: "bar" }, + { line: 2, column: 6, ruleId: "foo" } + ], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: "bar", + line: 2, column: 1, + suppressions: [{ kind: "directive", justification: "j2" }] + }, + { + ruleId: "foo", + line: 2, + column: 6, + suppressions: [ + { kind: "directive", justification: "j1" }, + { kind: "directive", justification: "j2" } + ] + }, + { ruleId: null, - justification: "justification" - }], - problems: [], - reportUnusedDisableDirectives: "off" - }), - [] + message: "Unused eslint-disable directive (no problems were reported from 'foo').", + line: 2, + column: 11, + fix: { + range: [64, 69], + text: "" + }, + severity: 2, + nodeType: null + } + ] ); }); - }); - describe("unused rules within directives", () => { - it("Adds a problem for /* eslint-disable used, unused */", () => { - const parentComment = createParentComment([0, 32], " eslint-disable used, unused ", ["used", "unused"]); + it("Adds a problem for /* eslint-disable used */ /* (problem from used) */ /* eslint-enable used, unused */", () => { + const parentComment = createParentComment([0, 32], " eslint-enable used, unused ", ["used", "unused"]); assert.deepStrictEqual( applyDisableDirectives({ directives: [ { - parentComment, + parentComment: createParentComment([0, 29], " eslint-disable foo ", ["foo"]), ruleId: "used", type: "disable", line: 1, - column: 18, + column: 1, justification: "j1" }, { parentComment, - ruleId: "unused", - type: "disable", - line: 1, - column: 22, + ruleId: "used", + type: "enable", + line: 3, + column: 1, justification: "j2" + }, + { + parentComment, + ruleId: "unused", + type: "enable", + line: 4, + column: 1, + justification: "j3" } ], problems: [{ line: 2, column: 1, ruleId: "used" }], reportUnusedDisableDirectives: "error" }), [ + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j1" }] + }, { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'unused').", - line: 1, - column: 22, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'unused').", + line: 4, + column: 1, fix: { - range: [22, 30], + range: [21, 29], text: "" }, severity: 2, nodeType: null - }, - { - line: 2, - column: 1, - ruleId: "used", - suppressions: [{ kind: "directive", justification: "j1" }] } ] ); }); - it("Adds a problem for /* eslint-disable used , unused , -- unused and used are ok */", () => { - const parentComment = createParentComment([0, 62], " eslint-disable used , unused , -- unused and used are ok ", ["used", "unused"]); + it("Adds a problem for /* eslint-disable used */ /* (problem from used) */ /* eslint-enable used , unused , -- unused and used are ok */", () => { + const parentComment = createParentComment([0, 62], " eslint-enable used , unused , -- unused and used are ok ", ["used", "unused"]); assert.deepStrictEqual( applyDisableDirectives({ directives: [ { - parentComment, + parentComment: createParentComment([0, 29], " eslint-disable foo ", ["foo"]), ruleId: "used", type: "disable", line: 1, - column: 18, + column: 1, justification: "j1" }, { parentComment, - ruleId: "unused", - type: "disable", - line: 1, - column: 24, + ruleId: "used", + type: "enable", + line: 3, + column: 1, justification: "j2" + }, + { + parentComment, + ruleId: "unused", + type: "enable", + line: 4, + column: 1, + justification: "j3" } ], problems: [{ line: 2, column: 1, ruleId: "used" }], reportUnusedDisableDirectives: "error" }), [ + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j1" }] + }, { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'unused').", - line: 1, - column: 24, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'unused').", + line: 4, + column: 1, fix: { - range: [23, 32], + range: [22, 31], text: "" }, severity: 2, nodeType: null - }, - { - line: 2, - column: 1, - ruleId: "used", - suppressions: [{ kind: "directive", justification: "j1" }] } ] ); }); - it("Adds a problem for /* eslint-disable unused, used */", () => { - const parentComment = createParentComment([0, 32], " eslint-disable unused, used ", ["unused", "used"]); + it("Adds a problem for /* eslint-disable used */ /* (problem from used) */ /* eslint-enable unused, used */", () => { + const parentComment = createParentComment([0, 32], " eslint-enable unused, used ", ["unused", "used"]); assert.deepStrictEqual( applyDisableDirectives({ directives: [ { - parentComment, - ruleId: "unused", + parentComment: createParentComment([0, 29], " eslint-disable foo ", ["foo"]), + ruleId: "used", type: "disable", line: 1, - column: 18, + column: 1, justification: "j1" }, { parentComment, - ruleId: "used", - type: "disable", - line: 1, - column: 25, + ruleId: "unused", + type: "enable", + line: 3, + column: 1, justification: "j2" + }, + { + parentComment, + ruleId: "used", + type: "enable", + line: 4, + column: 1, + justification: "j3" } ], problems: [{ line: 2, column: 1, ruleId: "used" }], reportUnusedDisableDirectives: "error" }), [ + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j1" }] + }, { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'unused').", - line: 1, - column: 18, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'unused').", + line: 3, + column: 1, fix: { - range: [18, 26], + range: [17, 25], text: "" }, severity: 2, nodeType: null - }, - { - line: 2, - column: 1, - ruleId: "used", - suppressions: [{ kind: "directive", justification: "j2" }] } ] ); }); - it("Adds a problem for /* eslint-disable unused,, ,, used */", () => { - const parentComment = createParentComment([0, 37], " eslint-disable unused,, ,, used ", ["unused", "used"]); + it("Adds a problem for /* eslint-disable used */ /* (problem from used) */ /* eslint-enable unused,, ,, used */", () => { + const parentComment = createParentComment([0, 37], " eslint-enable unused,, ,, used ", ["unused", "used"]); assert.deepStrictEqual( applyDisableDirectives({ directives: [ { - parentComment, - ruleId: "unused", + parentComment: createParentComment([0, 29], " eslint-disable foo ", ["foo"]), + ruleId: "used", type: "disable", line: 1, - column: 18, + column: 1, justification: "j1" }, { parentComment, - ruleId: "used", - type: "disable", - line: 1, - column: 29, + ruleId: "unused", + type: "enable", + line: 3, + column: 1, justification: "j2" + }, + { + parentComment, + ruleId: "used", + type: "enable", + line: 4, + column: 1, + justification: "j3" } ], problems: [{ line: 2, column: 1, ruleId: "used" }], reportUnusedDisableDirectives: "error" }), [ + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j1" }] + }, { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'unused').", - line: 1, - column: 18, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'unused').", + line: 3, + column: 1, fix: { - range: [18, 25], + range: [17, 24], text: "" }, severity: 2, nodeType: null - }, - { - line: 2, - column: 1, - ruleId: "used", - suppressions: [{ kind: "directive", justification: "j2" }] } ] ); }); - it("Adds a problem for /* eslint-disable unused-1, unused-2, used */", () => { - const parentComment = createParentComment([0, 45], " eslint-disable unused-1, unused-2, used ", ["unused-1", "unused-2", "used"]); + it("Adds a problem for /* eslint-disable used */ /* (problem from used) */ /* eslint-enable unused-1, unused-2, used */", () => { + const parentComment = createParentComment([0, 45], " eslint-enable unused-1, unused-2, used ", ["unused-1", "unused-2", "used"]); assert.deepStrictEqual( applyDisableDirectives({ directives: [ { - parentComment, - ruleId: "unused-1", + parentComment: createParentComment([0, 29], " eslint-disable foo ", ["foo"]), + ruleId: "used", type: "disable", line: 1, - column: 18, + column: 1, justification: "j1" }, { parentComment, - ruleId: "unused-2", - type: "disable", - line: 1, - column: 28, + ruleId: "unused-1", + type: "enable", + line: 3, + column: 1, justification: "j2" }, { parentComment, - ruleId: "used", - type: "disable", - line: 1, - column: 38, + ruleId: "unused-2", + type: "enable", + line: 4, + column: 1, justification: "j3" + }, + { + parentComment, + ruleId: "used", + type: "enable", + line: 5, + column: 1, + justification: "j4" } ], problems: [{ line: 2, column: 1, ruleId: "used" }], reportUnusedDisableDirectives: "error" }), [ + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j1" }] + }, { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'unused-1').", - line: 1, - column: 18, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'unused-1').", + line: 3, + column: 1, fix: { - range: [18, 28], + range: [17, 27], text: "" }, severity: 2, @@ -1753,76 +3071,84 @@ describe("apply-disable-directives", () => { }, { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'unused-2').", - line: 1, - column: 28, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'unused-2').", + line: 4, + column: 1, fix: { - range: [26, 36], + range: [25, 35], text: "" }, severity: 2, nodeType: null - }, - { - line: 2, - column: 1, - ruleId: "used", - suppressions: [{ kind: "directive", justification: "j3" }] } ] ); }); - it("Adds a problem for /* eslint-disable unused-1, unused-2, used, unused-3 */", () => { - const parentComment = createParentComment([0, 55], " eslint-disable unused-1, unused-2, used, unused-3 ", ["unused-1", "unused-2", "used", "unused-3"]); + it("Adds a problem for /* eslint-disable used */ /* (problem from used) */ /* eslint-enable unused-1, unused-2, used, unused-3 */", () => { + const parentComment = createParentComment([0, 55], " eslint-enable unused-1, unused-2, used, unused-3 ", ["unused-1", "unused-2", "used", "unused-3"]); assert.deepStrictEqual( applyDisableDirectives({ directives: [ { - parentComment, - ruleId: "unused-1", + parentComment: createParentComment([0, 29], " eslint-disable foo ", ["foo"]), + ruleId: "used", type: "disable", line: 1, - column: 18, + column: 1, justification: "j1" }, { parentComment, - ruleId: "unused-2", - type: "disable", - line: 1, - column: 28, + ruleId: "unused-1", + type: "enable", + line: 3, + column: 1, justification: "j2" }, { parentComment, - ruleId: "used", - type: "disable", - line: 1, - column: 38, + ruleId: "unused-2", + type: "enable", + line: 4, + column: 1, justification: "j3" }, { parentComment, - ruleId: "unused-3", - type: "disable", - line: 1, - column: 43, + ruleId: "used", + type: "enable", + line: 5, + column: 1, justification: "j4" + }, + { + parentComment, + ruleId: "unused-3", + type: "enable", + line: 6, + column: 1, + justification: "j5" } ], problems: [{ line: 2, column: 1, ruleId: "used" }], reportUnusedDisableDirectives: "error" }), [ + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j1" }] + }, { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'unused-1').", - line: 1, - column: 18, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'unused-1').", + line: 3, + column: 1, fix: { - range: [18, 28], + range: [17, 27], text: "" }, severity: 2, @@ -1830,11 +3156,11 @@ describe("apply-disable-directives", () => { }, { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'unused-2').", - line: 1, - column: 28, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'unused-2').", + line: 4, + column: 1, fix: { - range: [26, 36], + range: [25, 35], text: "" }, severity: 2, @@ -1842,28 +3168,22 @@ describe("apply-disable-directives", () => { }, { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'unused-3').", - line: 1, - column: 43, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'unused-3').", + line: 6, + column: 1, fix: { - range: [42, 52], + range: [41, 51], text: "" }, severity: 2, nodeType: null - }, - { - line: 2, - column: 1, - ruleId: "used", - suppressions: [{ kind: "directive", justification: "j3" }] } ] ); }); - it("Adds a problem for /* eslint-disable unused-1, unused-2 */", () => { - const parentComment = createParentComment([0, 39], " eslint-disable unused-1, unused-2 ", ["unused-1", "unused-2"]); + it("Adds a problem for /* eslint-enable unused-1, unused-2 */", () => { + const parentComment = createParentComment([0, 39], " eslint-enable unused-1, unused-2 ", ["unused-1", "unused-2"]); assert.deepStrictEqual( applyDisableDirectives({ @@ -1871,7 +3191,7 @@ describe("apply-disable-directives", () => { { parentComment, ruleId: "unused-1", - type: "disable", + type: "enable", line: 1, column: 18, justification: "j1" @@ -1879,7 +3199,7 @@ describe("apply-disable-directives", () => { { parentComment, ruleId: "unused-2", - type: "disable", + type: "enable", line: 1, column: 28, justification: "j2" @@ -1891,7 +3211,7 @@ describe("apply-disable-directives", () => { [ { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'unused-1' or 'unused-2').", + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'unused-1' or 'unused-2').", line: 1, column: 18, fix: { @@ -1905,8 +3225,8 @@ describe("apply-disable-directives", () => { ); }); - it("Adds a problem for /* eslint-disable unused-1, unused-2, unused-3 */", () => { - const parentComment = createParentComment([0, 49], " eslint-disable unused-1, unused-2, unused-3 ", ["unused-1", "unused-2", "unused-3"]); + it("Adds a problem for /* eslint-enable unused-1, unused-2, unused-3 */", () => { + const parentComment = createParentComment([0, 49], " eslint-enable unused-1, unused-2, unused-3 ", ["unused-1", "unused-2", "unused-3"]); assert.deepStrictEqual( applyDisableDirectives({ @@ -1914,21 +3234,21 @@ describe("apply-disable-directives", () => { { parentComment, ruleId: "unused-1", - type: "disable", + type: "enable", line: 1, column: 18 }, { parentComment, ruleId: "unused-2", - type: "disable", + type: "enable", line: 1, column: 28 }, { parentComment, ruleId: "unused-3", - type: "disable", + type: "enable", line: 1, column: 38 } @@ -1939,7 +3259,7 @@ describe("apply-disable-directives", () => { [ { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'unused-1', 'unused-2', or 'unused-3').", + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'unused-1', 'unused-2', or 'unused-3').", line: 1, column: 18, fix: { @@ -1952,72 +3272,5 @@ describe("apply-disable-directives", () => { ] ); }); - - it("Adds a problem for /* eslint-disable foo */ \\n (problem from foo and bar) // eslint-disable-line foo, bar", () => { - assert.deepStrictEqual( - applyDisableDirectives({ - directives: [ - { - parentComment: createParentComment([0, 29], " eslint-disable foo ", ["foo"]), - ruleId: "foo", - type: "disable", - line: 1, - column: 1, - justification: "j1" - }, - { - parentComment: createParentComment([41, 81], " eslint-disable-line foo, bar", ["foo", "bar"]), - ruleId: "foo", - type: "disable-line", - line: 2, - column: 11, - justification: "j2" - }, - { - parentComment: createParentComment([41, 81], " eslint-disable-line foo, bar ", ["foo", "bar"]), - ruleId: "bar", - type: "disable-line", - line: 2, - column: 11, - justification: "j2" - } - ], - problems: [ - { line: 2, column: 1, ruleId: "bar" }, - { line: 2, column: 6, ruleId: "foo" } - ], - reportUnusedDisableDirectives: "error" - }), - [ - { - ruleId: "bar", - line: 2, - column: 1, - suppressions: [{ kind: "directive", justification: "j2" }] - }, - { - ruleId: "foo", - line: 2, - column: 6, - suppressions: [ - { kind: "directive", justification: "j1" }, - { kind: "directive", justification: "j2" } - ] - }, - { - ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'foo').", - line: 2, - column: 11, - fix: { - range: [64, 69], - text: "" - }, - severity: 2, - nodeType: null - } - ] - ); - }); }); }); diff --git a/tests/lib/linter/linter.js b/tests/lib/linter/linter.js index c8fd4134caa6..b89b073ecaf9 100644 --- a/tests/lib/linter/linter.js +++ b/tests/lib/linter/linter.js @@ -4323,6 +4323,166 @@ var a = "test2"; assert.strictEqual(suppressedMessages.length, 0); }); + it("reports problems for unused eslint-enable comments", () => { + const messages = linter.verify("/* eslint-enable */", {}, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.deepStrictEqual( + messages, + [ + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + line: 1, + column: 1, + fix: { + range: [0, 19], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + + assert.strictEqual(suppressedMessages.length, 0); + }); + + it("reports problems for unused eslint-enable comments with ruleId", () => { + const messages = linter.verify("/* eslint-enable no-alert */", {}, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.deepStrictEqual( + messages, + [ + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'no-alert').", + line: 1, + column: 1, + fix: { + range: [0, 28], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + + assert.strictEqual(suppressedMessages.length, 0); + }); + + it("reports problems for unused eslint-enable comments with mismatch ruleId", () => { + const code = [ + "/* eslint-disable no-alert */", + "alert(\"test\");", + "/* eslint-enable no-console */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.deepStrictEqual( + messages, + [ + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'no-console').", + line: 3, + column: 1, + fix: { + range: [45, 75], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + + assert.strictEqual(suppressedMessages.length, 1); + }); + + it("reports problems for unused eslint-enable comments with used eslint-enable comments", () => { + const code = [ + "/* eslint-disable no-alert -- j1 */", + "alert(\"test\");", + "/* eslint-disable no-alert -- j2 */", + "alert(\"test\");", + "/* eslint-enable no-alert -- j3 */", + "/* eslint-enable -- j4 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.deepStrictEqual( + messages, + [ + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + line: 6, + column: 1, + fix: { + range: [137, 162], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + + assert.strictEqual(suppressedMessages.length, 2); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + assert.strictEqual(suppressedMessages[1].suppressions.length, 2); + }); + + it("reports problems for unused eslint-disable comments with used eslint-enable comments", () => { + const code = [ + "/* eslint-disable no-alert -- j1 */", + "console.log(\"test\"); //", + "/* eslint-enable no-alert -- j2 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.deepStrictEqual( + messages, + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'no-alert').", + line: 1, + column: 1, + fix: { + range: [0, 35], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + + assert.strictEqual(suppressedMessages.length, 0); + }); + it("reports problems for unused eslint-disable comments (in config)", () => { const messages = linter.verify("/* eslint-disable */", { reportUnusedDisableDirectives: true }); const suppressedMessages = linter.getSuppressedMessages(); @@ -4407,12 +4567,156 @@ var a = "test2"; assert.strictEqual(suppressedMessages[0].ruleId, "no-fallthrough"); }); + it("reports problems for multiple eslint-enable comments with same ruleId", () => { + const code = [ + "/* eslint-disable no-alert -- j1 */", + "alert(\"test\"); //", + "/* eslint-enable no-alert -- j2 */", + "/* eslint-enable no-alert -- j3 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.strictEqual(messages.length, 1); + assert.strictEqual(messages[0].line, 4); + assert.strictEqual(suppressedMessages.length, 1); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + }); + + it("reports problems for multiple eslint-enable comments without ruleId (Rule is already enabled)", () => { + const code = [ + "/* eslint-disable no-alert -- j1 */", + "alert(\"test\"); //", + "/* eslint-enable no-alert -- j2 */", + "/* eslint-enable -- j3 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.strictEqual(messages.length, 1); + assert.strictEqual(messages[0].line, 4); + assert.strictEqual(suppressedMessages.length, 1); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + }); + + it("reports problems for multiple eslint-enable comments with ruleId (Rule is already enabled by eslint-enable comments without ruleId)", () => { + const code = [ + "/* eslint-disable no-alert -- j1 */", + "alert(\"test\"); //", + "/* eslint-enable -- j3 */", + "/* eslint-enable no-alert -- j2 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.strictEqual(messages.length, 1); + assert.strictEqual(messages[0].line, 4); + assert.strictEqual(suppressedMessages.length, 1); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + }); + + it("reports problems for eslint-enable comments without ruleId (Two rules are already enabled)", () => { + const code = [ + "/* eslint-disable no-alert, no-console -- j1 */", + "alert(\"test\"); //", + "console.log(\"test\"); //", + "/* eslint-enable no-alert -- j2 */", + "/* eslint-enable no-console -- j3 */", + "/* eslint-enable -- j4 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2, + "no-console": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.strictEqual(messages.length, 1); + assert.strictEqual(messages[0].line, 6); + assert.strictEqual(suppressedMessages.length, 2); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + assert.strictEqual(suppressedMessages[1].suppressions.length, 1); + }); + + it("reports problems for multiple eslint-enable comments with ruleId (Two rules are already enabled by eslint-enable comments without ruleId)", () => { + const code = [ + "/* eslint-disable no-alert, no-console -- j1 */", + "alert(\"test\"); //", + "console.log(\"test\"); //", + "/* eslint-enable -- j2 */", + "/* eslint-enable no-console -- j3 */", + "/* eslint-enable no-alert -- j4 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2, + "no-console": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.strictEqual(messages.length, 2); + assert.strictEqual(messages[0].line, 5); + assert.strictEqual(messages[1].line, 6); + assert.strictEqual(suppressedMessages.length, 2); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + assert.strictEqual(suppressedMessages[1].suppressions.length, 1); + }); + + it("reports problems for multiple eslint-enable comments", () => { + const code = [ + "/* eslint-disable no-alert, no-console -- j1 */", + "alert(\"test\"); //", + "console.log(\"test\"); //", + "/* eslint-enable no-console -- j2 */", + "/* eslint-enable -- j3 */", + "/* eslint-enable no-alert -- j4 */", + "/* eslint-enable -- j5 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2, + "no-console": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.strictEqual(messages.length, 2); + assert.strictEqual(messages[0].line, 6); + assert.strictEqual(messages[1].line, 7); + assert.strictEqual(suppressedMessages.length, 2); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + assert.strictEqual(suppressedMessages[1].suppressions.length, 1); + }); + describe("autofix", () => { const alwaysReportsRule = { create(context) { return { Program(node) { context.report({ message: "bad code", loc: node.loc.end }); + }, + "Identifier[name=bad]"(node) { + context.report({ message: "bad id", loc: node.loc }); } }; } @@ -4482,6 +4786,10 @@ var a = "test2"; code: "/* eslint-disable \nunused\n*/", output: " " }, + { + code: "/* eslint-enable \nunused\n*/", + output: " " + }, //----------------------------------------------- // Removing only individual rules @@ -4520,6 +4828,26 @@ var a = "test2"; code: "/*\u00A0eslint-disable unused, used*/", output: "/*\u00A0eslint-disable used*/" }, + { + code: "/* eslint-disable used*/ bad /*\neslint-enable unused, used*/", + output: "/* eslint-disable used*/ bad /*\neslint-enable used*/" + }, + { + code: "/* eslint-disable used*/ bad /*\n eslint-enable unused, used*/", + output: "/* eslint-disable used*/ bad /*\n eslint-enable used*/" + }, + { + code: "/* eslint-disable used*/ bad /*\r\neslint-enable unused, used*/", + output: "/* eslint-disable used*/ bad /*\r\neslint-enable used*/" + }, + { + code: "/* eslint-disable used*/ bad /*\u2028eslint-enable unused, used*/", + output: "/* eslint-disable used*/ bad /*\u2028eslint-enable used*/" + }, + { + code: "/* eslint-disable used*/ bad /*\u00A0eslint-enable unused, used*/", + output: "/* eslint-disable used*/ bad /*\u00A0eslint-enable used*/" + }, { code: "// eslint-disable-line unused, used", output: "// eslint-disable-line used" @@ -4544,6 +4872,26 @@ var a = "test2"; code: "/* eslint-disable\u00A0unused, used*/", output: "/* eslint-disable\u00A0used*/" }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable\nunused, used*/", + output: "/* eslint-disable used*/ bad /* eslint-enable\nused*/" + }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable\n unused, used*/", + output: "/* eslint-disable used*/ bad /* eslint-enable\n used*/" + }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable\r\nunused, used*/", + output: "/* eslint-disable used*/ bad /* eslint-enable\r\nused*/" + }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable\u2028unused, used*/", + output: "/* eslint-disable used*/ bad /* eslint-enable\u2028used*/" + }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable\u00A0unused, used*/", + output: "/* eslint-disable used*/ bad /* eslint-enable\u00A0used*/" + }, // when removing the first rule, the comma and all whitespace up to the next rule (or next lone comma) should also be removed { @@ -4578,6 +4926,18 @@ var a = "test2"; code: "/* eslint-disable unused\u2028,\u2028used */", output: "/* eslint-disable used */" }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable unused\n,\nused */", + output: "/* eslint-disable used*/ bad /* eslint-enable used */" + }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable unused \n \n,\n\n used */", + output: "/* eslint-disable used*/ bad /* eslint-enable used */" + }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable unused\u2028,\u2028used */", + output: "/* eslint-disable used*/ bad /* eslint-enable used */" + }, { code: "// eslint-disable-line unused\u00A0,\u00A0used", output: "// eslint-disable-line used" @@ -4632,6 +4992,18 @@ var a = "test2"; code: "/* eslint-disable used-1,\u2028unused\u2028,used-2 */", output: "/* eslint-disable used-1,used-2 */" }, + { + code: "/* eslint-disable used-1, used-2*/ bad /* eslint-enable used-1,\nunused\n,used-2 */", + output: "/* eslint-disable used-1, used-2*/ bad /* eslint-enable used-1,used-2 */" + }, + { + code: "/* eslint-disable used-1, used-2*/ bad /* eslint-enable used-1,\n\n unused \n \n ,used-2 */", + output: "/* eslint-disable used-1, used-2*/ bad /* eslint-enable used-1,used-2 */" + }, + { + code: "/* eslint-disable used-1, used-2*/ bad /* eslint-enable used-1,\u2028unused\u2028,used-2 */", + output: "/* eslint-disable used-1, used-2*/ bad /* eslint-enable used-1,used-2 */" + }, { code: "// eslint-disable-line used-1,\u00A0unused\u00A0,used-2", output: "// eslint-disable-line used-1,used-2" @@ -4666,6 +5038,14 @@ var a = "test2"; code: "/* eslint-disable used-1\u2028,unused,\u2028used-2 */", output: "/* eslint-disable used-1\u2028,\u2028used-2 */" }, + { + code: "/* eslint-disable used-1, used-2 */ bad /* eslint-enable used-1\n,unused,\nused-2 */", + output: "/* eslint-disable used-1, used-2 */ bad /* eslint-enable used-1\n,\nused-2 */" + }, + { + code: "/* eslint-disable used-1, used-2 */ bad /* eslint-enable used-1\u2028,unused,\u2028used-2 */", + output: "/* eslint-disable used-1, used-2 */ bad /* eslint-enable used-1\u2028,\u2028used-2 */" + }, { code: "// eslint-disable-line used-1\u00A0,unused,\u00A0used-2", output: "// eslint-disable-line used-1\u00A0,\u00A0used-2" @@ -4690,6 +5070,18 @@ var a = "test2"; code: "/* eslint-disable used-1,\n,unused,\n,used-2 */", output: "/* eslint-disable used-1,\n,\n,used-2 */" }, + { + code: "/* eslint-disable used-1, used-2 */ bad /* eslint-enable used-1,\n,unused,used-2 */", + output: "/* eslint-disable used-1, used-2 */ bad /* eslint-enable used-1,\n,used-2 */" + }, + { + code: "/* eslint-disable used-1, used-2 */ bad /* eslint-enable used-1,unused,\n,used-2 */", + output: "/* eslint-disable used-1, used-2 */ bad /* eslint-enable used-1,\n,used-2 */" + }, + { + code: "/* eslint-disable used-1, used-2 */ bad /* eslint-enable used-1,\n,unused,\n,used-2 */", + output: "/* eslint-disable used-1, used-2 */ bad /* eslint-enable used-1,\n,\n,used-2 */" + }, { code: "// eslint-disable-line used, unused,", output: "// eslint-disable-line used," @@ -4710,6 +5102,10 @@ var a = "test2"; code: "/* eslint-disable used, unused,\n*/", output: "/* eslint-disable used,\n*/" }, + { + code: "/* eslint-disable used */ bad /* eslint-enable used, unused,\n*/", + output: "/* eslint-disable used */ bad /* eslint-enable used,\n*/" + }, // when removing the last rule, the comma and all whitespace up to the previous rule (or previous lone comma) should also be removed { @@ -4748,6 +5144,18 @@ var a = "test2"; code: "/* eslint-disable used\u2028,\u2028unused */", output: "/* eslint-disable used */" }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable used\n,\nunused */", + output: "/* eslint-disable used*/ bad /* eslint-enable used */" + }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable used \n \n,\n\n unused */", + output: "/* eslint-disable used*/ bad /* eslint-enable used */" + }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable used\u2028,\u2028unused */", + output: "/* eslint-disable used*/ bad /* eslint-enable used */" + }, { code: "// eslint-disable-line used\u00A0,\u00A0unused", output: "// eslint-disable-line used" @@ -4768,6 +5176,14 @@ var a = "test2"; code: "/* eslint-disable used\n, ,unused */", output: "/* eslint-disable used\n, */" }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable used,\n,unused */", + output: "/* eslint-disable used*/ bad /* eslint-enable used, */" + }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable used\n, ,unused */", + output: "/* eslint-disable used*/ bad /* eslint-enable used\n, */" + }, // content after the last rule should not be changed { @@ -4798,6 +5214,10 @@ var a = "test2"; code: "/* eslint-disable used,unused\u2028*/", output: "/* eslint-disable used\u2028*/" }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable used,unused\u2028*/", + output: "/* eslint-disable used*/ bad /* eslint-enable used\u2028*/" + }, { code: "// eslint-disable-line used,unused\u00A0", output: "// eslint-disable-line used\u00A0" @@ -4813,34 +5233,172 @@ var a = "test2"; output: "// eslint-disable-line used" }, { - code: "// eslint-disable-line unused-1, unused-2, used", - output: "// eslint-disable-line used" + code: "// eslint-disable-line unused-1, unused-2, used", + output: "// eslint-disable-line used" + }, + { + code: "// eslint-disable-line used-1, unused-1, used-2, unused-2", + output: "// eslint-disable-line used-1, used-2" + }, + { + code: "// eslint-disable-line unused-1, used-1, unused-2, used-2", + output: "// eslint-disable-line used-1, used-2" + }, + { + code: ` + /* eslint-disable unused-1, + used-1, + unused-2, + used-2 + */ + `, + output: ` + /* eslint-disable used-1, + used-2 + */ + ` + }, + { + code: ` + /* eslint-disable + unused-1, + used-1, + unused-2, + used-2 + */ + `, + output: ` + /* eslint-disable + used-1, + used-2 + */ + ` + }, + { + code: ` + /* eslint-disable + used-1, + unused-1, + used-2, + unused-2 + */ + `, + output: ` + /* eslint-disable + used-1, + used-2 + */ + ` + }, + { + code: ` + /* eslint-disable + used-1, + unused-1, + used-2, + unused-2, + */ + `, + output: ` + /* eslint-disable + used-1, + used-2, + */ + ` + }, + { + code: ` + /* eslint-disable + ,unused-1 + ,used-1 + ,unused-2 + ,used-2 + */ + `, + output: ` + /* eslint-disable + ,used-1 + ,used-2 + */ + ` + }, + { + code: ` + /* eslint-disable + ,used-1 + ,unused-1 + ,used-2 + ,unused-2 + */ + `, + output: ` + /* eslint-disable + ,used-1 + ,used-2 + */ + ` }, { - code: "// eslint-disable-line used-1, unused-1, used-2, unused-2", - output: "// eslint-disable-line used-1, used-2" + code: ` + /* eslint-disable + used-1, + unused-1, + used-2, + unused-2 + + -- comment + */ + `, + output: ` + /* eslint-disable + used-1, + used-2 + + -- comment + */ + ` }, { - code: "// eslint-disable-line unused-1, used-1, unused-2, used-2", - output: "// eslint-disable-line used-1, used-2" + code: ` + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable unused-1, + used-1, + unused-2, + used-2 + */ + `, + output: ` + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable used-1, + used-2 + */ + ` }, { code: ` - /* eslint-disable unused-1, + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable unused-1, used-1, unused-2, used-2 */ `, output: ` - /* eslint-disable used-1, + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable used-1, used-2 */ ` }, { code: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable unused-1, used-1, unused-2, @@ -4848,7 +5406,9 @@ var a = "test2"; */ `, output: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable used-1, used-2 */ @@ -4856,7 +5416,9 @@ var a = "test2"; }, { code: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable used-1, unused-1, used-2, @@ -4864,7 +5426,9 @@ var a = "test2"; */ `, output: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable used-1, used-2 */ @@ -4872,7 +5436,9 @@ var a = "test2"; }, { code: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable used-1, unused-1, used-2, @@ -4880,7 +5446,9 @@ var a = "test2"; */ `, output: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable used-1, used-2, */ @@ -4888,7 +5456,9 @@ var a = "test2"; }, { code: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable ,unused-1 ,used-1 ,unused-2 @@ -4896,7 +5466,9 @@ var a = "test2"; */ `, output: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable ,used-1 ,used-2 */ @@ -4904,7 +5476,9 @@ var a = "test2"; }, { code: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable ,used-1 ,unused-1 ,used-2 @@ -4912,7 +5486,9 @@ var a = "test2"; */ `, output: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable ,used-1 ,used-2 */ @@ -4920,7 +5496,9 @@ var a = "test2"; }, { code: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable used-1, unused-1, used-2, @@ -4930,7 +5508,9 @@ var a = "test2"; */ `, output: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable used-1, used-2 @@ -15015,82 +15595,373 @@ var a = "test2"; ); }); - it("reports problems for partially unused eslint-disable-next-line comments (in config)", () => { - const code = "// eslint-disable-next-line no-alert, no-redeclare \nalert('test');"; + it("reports problems for partially unused eslint-disable-next-line comments (in config)", () => { + const code = "// eslint-disable-next-line no-alert, no-redeclare \nalert('test');"; + const config = { + linterOptions: { + reportUnusedDisableDirectives: true + }, + rules: { + "no-alert": 1, + "no-redeclare": 1 + } + }; + + const messages = linter.verify(code, config, { + filename, + allowInlineConfig: true + }); + + assert.deepStrictEqual( + messages, + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'no-redeclare').", + line: 1, + column: 1, + fix: { + range: [36, 50], + text: "" + }, + severity: 1, + nodeType: null + } + ] + ); + }); + + it("reports problems for partially unused multiline eslint-disable-next-line comments (in config)", () => { + const code = ` + /* eslint-disable-next-line no-alert, no-redeclare -- + * Here's a very long description about why this configuration is necessary + * along with some additional information + **/ + alert('test'); + `; + const config = { + linterOptions: { + reportUnusedDisableDirectives: true + }, + rules: { + "no-alert": 1, + "no-redeclare": 1 + } + }; + + const messages = linter.verify(code, config, { + filename, + allowInlineConfig: true + }); + + assert.deepStrictEqual( + messages, + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'no-redeclare').", + line: 2, + column: 21, + fix: { + range: [57, 71], + text: "" + }, + severity: 1, + nodeType: null + } + ] + ); + }); + + it("reports problems for unused eslint-enable comments", () => { + const messages = linter.verify("/* eslint-enable */", {}, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.deepStrictEqual( + messages, + [ + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + line: 1, + column: 1, + fix: { + range: [0, 19], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + + assert.strictEqual(suppressedMessages.length, 0); + }); + + it("reports problems for unused eslint-enable comments with ruleId", () => { + const messages = linter.verify("/* eslint-enable no-alert */", {}, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.deepStrictEqual( + messages, + [ + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'no-alert').", + line: 1, + column: 1, + fix: { + range: [0, 28], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + + assert.strictEqual(suppressedMessages.length, 0); + }); + + it("reports problems for unused eslint-enable comments with mismatch ruleId", () => { + const code = [ + "/* eslint-disable no-alert */", + "alert(\"test\");", + "/* eslint-enable no-console */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.deepStrictEqual( + messages, + [ + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'no-console').", + line: 3, + column: 1, + fix: { + range: [45, 75], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + + assert.strictEqual(suppressedMessages.length, 1); + }); + + it("reports problems for unused eslint-enable comments with used eslint-enable comments", () => { + const code = [ + "/* eslint-disable no-alert -- j1 */", + "alert(\"test\");", + "/* eslint-disable no-alert -- j2 */", + "alert(\"test\");", + "/* eslint-enable no-alert -- j3 */", + "/* eslint-enable -- j4 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.deepStrictEqual( + messages, + [ + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + line: 6, + column: 1, + fix: { + range: [137, 162], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + + assert.strictEqual(suppressedMessages.length, 2); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + assert.strictEqual(suppressedMessages[1].suppressions.length, 2); + }); + + it("reports problems for multiple eslint-enable comments with same ruleId", () => { + const code = [ + "/* eslint-disable no-alert -- j1 */", + "alert(\"test\"); //", + "/* eslint-enable no-alert -- j2 */", + "/* eslint-enable no-alert -- j3 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.strictEqual(messages.length, 1); + assert.strictEqual(messages[0].line, 4); + assert.strictEqual(suppressedMessages.length, 1); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + }); + + it("reports problems for multiple eslint-enable comments without ruleId (Rule is already enabled)", () => { + const code = [ + "/* eslint-disable no-alert -- j1 */", + "alert(\"test\"); //", + "/* eslint-enable no-alert -- j2 */", + "/* eslint-enable -- j3 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.strictEqual(messages.length, 1); + assert.strictEqual(messages[0].line, 4); + assert.strictEqual(suppressedMessages.length, 1); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + }); + + it("reports problems for multiple eslint-enable comments with ruleId (Rule is already enabled by eslint-enable comments without ruleId)", () => { + const code = [ + "/* eslint-disable no-alert -- j1 */", + "alert(\"test\"); //", + "/* eslint-enable -- j3 */", + "/* eslint-enable no-alert -- j2 */" + ].join("\n"); const config = { - linterOptions: { - reportUnusedDisableDirectives: true - }, rules: { - "no-alert": 1, - "no-redeclare": 1 + "no-alert": 2 } }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); - const messages = linter.verify(code, config, { - filename, - allowInlineConfig: true - }); + assert.strictEqual(messages.length, 1); + assert.strictEqual(messages[0].line, 4); + assert.strictEqual(suppressedMessages.length, 1); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + }); - assert.deepStrictEqual( - messages, - [ - { - ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'no-redeclare').", - line: 1, - column: 1, - fix: { - range: [36, 50], - text: "" - }, - severity: 1, - nodeType: null - } - ] - ); + it("reports problems for eslint-enable comments without ruleId (Two rules are already enabled)", () => { + const code = [ + "/* eslint-disable no-alert, no-console -- j1 */", + "alert(\"test\"); //", + "console.log(\"test\"); //", + "/* eslint-enable no-alert -- j2 */", + "/* eslint-enable no-console -- j3 */", + "/* eslint-enable -- j4 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2, + "no-console": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.strictEqual(messages.length, 1); + assert.strictEqual(messages[0].line, 6); + assert.strictEqual(suppressedMessages.length, 2); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + assert.strictEqual(suppressedMessages[1].suppressions.length, 1); }); - it("reports problems for partially unused multiline eslint-disable-next-line comments (in config)", () => { - const code = ` - /* eslint-disable-next-line no-alert, no-redeclare -- - * Here's a very long description about why this configuration is necessary - * along with some additional information - **/ - alert('test'); - `; + it("reports problems for multiple eslint-enable comments with ruleId (Two rules are already enabled by eslint-enable comments without ruleId)", () => { + const code = [ + "/* eslint-disable no-alert, no-console -- j1 */", + "alert(\"test\"); //", + "console.log(\"test\"); //", + "/* eslint-enable -- j2 */", + "/* eslint-enable no-console -- j3 */", + "/* eslint-enable no-alert -- j4 */" + ].join("\n"); const config = { - linterOptions: { - reportUnusedDisableDirectives: true - }, rules: { - "no-alert": 1, - "no-redeclare": 1 + "no-alert": 2, + "no-console": 2 } }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); - const messages = linter.verify(code, config, { - filename, - allowInlineConfig: true - }); + assert.strictEqual(messages.length, 2); + assert.strictEqual(messages[0].line, 5); + assert.strictEqual(messages[1].line, 6); + assert.strictEqual(suppressedMessages.length, 2); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + assert.strictEqual(suppressedMessages[1].suppressions.length, 1); + }); + + it("reports problems for multiple eslint-enable comments", () => { + const code = [ + "/* eslint-disable no-alert, no-console -- j1 */", + "alert(\"test\"); //", + "console.log(\"test\"); //", + "/* eslint-enable no-console -- j2 */", + "/* eslint-enable -- j3 */", + "/* eslint-enable no-alert -- j4 */", + "/* eslint-enable -- j5 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2, + "no-console": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.strictEqual(messages.length, 2); + assert.strictEqual(messages[0].line, 6); + assert.strictEqual(messages[1].line, 7); + assert.strictEqual(suppressedMessages.length, 2); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + assert.strictEqual(suppressedMessages[1].suppressions.length, 1); + }); + + it("reports problems for unused eslint-disable comments (warn)", () => { + const messages = linter.verify("/* eslint-disable */", {}, { reportUnusedDisableDirectives: "warn" }); + const suppressedMessages = linter.getSuppressedMessages(); assert.deepStrictEqual( messages, [ { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'no-redeclare').", - line: 2, - column: 21, + message: "Unused eslint-disable directive (no problems were reported).", + line: 1, + column: 1, fix: { - range: [57, 71], - text: "" + range: [0, 20], + text: " " }, severity: 1, nodeType: null } ] ); + + assert.strictEqual(suppressedMessages.length, 0); }); describe("autofix", () => { @@ -15099,6 +15970,9 @@ var a = "test2"; return { Program(node) { context.report({ message: "bad code", loc: node.loc.end }); + }, + "Identifier[name=bad]"(node) { + context.report({ message: "bad id", loc: node.loc }); } }; } @@ -15177,6 +16051,10 @@ var a = "test2"; code: "/* eslint-disable \ntest/unused\n*/", output: " " }, + { + code: "/* eslint-enable \ntest/unused\n*/", + output: " " + }, //----------------------------------------------- // Removing only individual rules @@ -15215,6 +16093,26 @@ var a = "test2"; code: "/*\u00A0eslint-disable test/unused, test/used*/", output: "/*\u00A0eslint-disable test/used*/" }, + { + code: "/* eslint-disable test/used */ bad /*\neslint-enable test/unused, test/used*/", + output: "/* eslint-disable test/used */ bad /*\neslint-enable test/used*/" + }, + { + code: "/* eslint-disable test/used */ bad /*\n eslint-enable test/unused, test/used*/", + output: "/* eslint-disable test/used */ bad /*\n eslint-enable test/used*/" + }, + { + code: "/* eslint-disable test/used */ bad /*\r\neslint-enable test/unused, test/used*/", + output: "/* eslint-disable test/used */ bad /*\r\neslint-enable test/used*/" + }, + { + code: "/* eslint-disable test/used */ bad /*\u2028eslint-enable test/unused, test/used*/", + output: "/* eslint-disable test/used */ bad /*\u2028eslint-enable test/used*/" + }, + { + code: "/* eslint-disable test/used */ bad /*\u00A0eslint-enable test/unused, test/used*/", + output: "/* eslint-disable test/used */ bad /*\u00A0eslint-enable test/used*/" + }, { code: "// eslint-disable-line test/unused, test/used", output: "// eslint-disable-line test/used" @@ -15273,6 +16171,18 @@ var a = "test2"; code: "/* eslint-disable test/unused\u2028,\u2028test/used */", output: "/* eslint-disable test/used */" }, + { + code: "/* eslint-disable test/used */ bad /* eslint-enable test/unused\n,\ntest/used */", + output: "/* eslint-disable test/used */ bad /* eslint-enable test/used */" + }, + { + code: "/* eslint-disable test/used */ bad /* eslint-enable test/unused \n \n,\n\n test/used */", + output: "/* eslint-disable test/used */ bad /* eslint-enable test/used */" + }, + { + code: "/* eslint-disable test/used */ bad /* eslint-enable test/unused\u2028,\u2028test/used */", + output: "/* eslint-disable test/used */ bad /* eslint-enable test/used */" + }, { code: "// eslint-disable-line test/unused\u00A0,\u00A0test/used", output: "// eslint-disable-line test/used" @@ -15327,6 +16237,18 @@ var a = "test2"; code: "/* eslint-disable test/used-1,\u2028test/unused\u2028,test/used-2 */", output: "/* eslint-disable test/used-1,test/used-2 */" }, + { + code: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,\ntest/unused\n,test/used-2 */", + output: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,test/used-2 */" + }, + { + code: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,\n\n test/unused \n \n ,test/used-2 */", + output: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,test/used-2 */" + }, + { + code: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,\u2028test/unused\u2028,test/used-2 */", + output: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,test/used-2 */" + }, { code: "// eslint-disable-line test/used-1,\u00A0test/unused\u00A0,test/used-2", output: "// eslint-disable-line test/used-1,test/used-2" @@ -15361,6 +16283,14 @@ var a = "test2"; code: "/* eslint-disable test/used-1\u2028,test/unused,\u2028test/used-2 */", output: "/* eslint-disable test/used-1\u2028,\u2028test/used-2 */" }, + { + code: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1\n,test/unused,\ntest/used-2 */", + output: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1\n,\ntest/used-2 */" + }, + { + code: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1\u2028,test/unused,\u2028test/used-2 */", + output: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1\u2028,\u2028test/used-2 */" + }, { code: "// eslint-disable-line test/used-1\u00A0,test/unused,\u00A0test/used-2", output: "// eslint-disable-line test/used-1\u00A0,\u00A0test/used-2" @@ -15385,6 +16315,18 @@ var a = "test2"; code: "/* eslint-disable test/used-1,\n,test/unused,\n,test/used-2 */", output: "/* eslint-disable test/used-1,\n,\n,test/used-2 */" }, + { + code: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,\n,test/unused,test/used-2 */", + output: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,\n,test/used-2 */" + }, + { + code: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,test/unused,\n,test/used-2 */", + output: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,\n,test/used-2 */" + }, + { + code: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,\n,test/unused,\n,test/used-2 */", + output: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,\n,\n,test/used-2 */" + }, { code: "// eslint-disable-line test/used, test/unused,", output: "// eslint-disable-line test/used," @@ -15405,6 +16347,10 @@ var a = "test2"; code: "/* eslint-disable test/used, test/unused,\n*/", output: "/* eslint-disable test/used,\n*/" }, + { + code: "/* eslint-disable test/used */ bad /* eslint-enable test/used, test/unused,\n*/", + output: "/* eslint-disable test/used */ bad /* eslint-enable test/used,\n*/" + }, // when removing the last rule, the comma and all whitespace up to the previous rule (or previous lone comma) should also be removed { @@ -15443,6 +16389,18 @@ var a = "test2"; code: "/* eslint-disable test/used\u2028,\u2028test/unused */", output: "/* eslint-disable test/used */" }, + { + code: "/* eslint-disable test/used */ bad /* eslint-enable test/used\n,\ntest/unused */", + output: "/* eslint-disable test/used */ bad /* eslint-enable test/used */" + }, + { + code: "/* eslint-disable test/used */ bad /* eslint-enable test/used \n \n,\n\n test/unused */", + output: "/* eslint-disable test/used */ bad /* eslint-enable test/used */" + }, + { + code: "/* eslint-disable test/used */ bad /* eslint-enable test/used\u2028,\u2028test/unused */", + output: "/* eslint-disable test/used */ bad /* eslint-enable test/used */" + }, { code: "// eslint-disable-line test/used\u00A0,\u00A0test/unused", output: "// eslint-disable-line test/used" @@ -15463,6 +16421,14 @@ var a = "test2"; code: "/* eslint-disable test/used\n, ,test/unused */", output: "/* eslint-disable test/used\n, */" }, + { + code: "/* eslint-disable test/used */ bad /* eslint-enable test/used,\n,test/unused */", + output: "/* eslint-disable test/used */ bad /* eslint-enable test/used, */" + }, + { + code: "/* eslint-disable test/used */ bad /* eslint-enable test/used\n, ,test/unused */", + output: "/* eslint-disable test/used */ bad /* eslint-enable test/used\n, */" + }, // content after the last rule should not be changed { @@ -15493,6 +16459,10 @@ var a = "test2"; code: "/* eslint-disable test/used,test/unused\u2028*/", output: "/* eslint-disable test/used\u2028*/" }, + { + code: "/* eslint-disable test/used */ bad /* eslint-enable test/used,test/unused\u2028*/", + output: "/* eslint-disable test/used */ bad /* eslint-enable test/used\u2028*/" + }, { code: "// eslint-disable-line test/used,test/unused\u00A0", output: "// eslint-disable-line test/used\u00A0" @@ -15633,6 +16603,148 @@ var a = "test2"; */ ` }, + { + code: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable test/unused-1, + test/used-1, + test/unused-2, + test/used-2 + */ + `, + output: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable test/used-1, + test/used-2 + */ + ` + }, + { + code: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + test/unused-1, + test/used-1, + test/unused-2, + test/used-2 + */ + `, + output: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + test/used-1, + test/used-2 + */ + ` + }, + { + code: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + test/used-1, + test/unused-1, + test/used-2, + test/unused-2 + */ + `, + output: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + test/used-1, + test/used-2 + */ + ` + }, + { + code: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + test/used-1, + test/unused-1, + test/used-2, + test/unused-2, + */ + `, + output: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + test/used-1, + test/used-2, + */ + ` + }, + { + code: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + ,test/unused-1 + ,test/used-1 + ,test/unused-2 + ,test/used-2 + */ + `, + output: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + ,test/used-1 + ,test/used-2 + */ + ` + }, + { + code: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + ,test/used-1 + ,test/unused-1 + ,test/used-2 + ,test/unused-2 + */ + `, + output: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + ,test/used-1 + ,test/used-2 + */ + ` + }, + { + code: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + test/used-1, + test/unused-1, + test/used-2, + test/unused-2 + + -- comment + */ + `, + output: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + test/used-1, + test/used-2 + + -- comment + */ + ` + }, // duplicates in the list { From ef650cb612510bcfa1379c1f0af56dd563b3a705 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Wed, 18 Oct 2023 14:04:11 +0200 Subject: [PATCH 17/24] test: update tests for no-promise-executor-return (#17661) --- tests/lib/rules/no-promise-executor-return.js | 694 ++++++++++++++---- 1 file changed, 531 insertions(+), 163 deletions(-) diff --git a/tests/lib/rules/no-promise-executor-return.js b/tests/lib/rules/no-promise-executor-return.js index 4054edc72441..ee8a53929fbb 100644 --- a/tests/lib/rules/no-promise-executor-return.js +++ b/tests/lib/rules/no-promise-executor-return.js @@ -12,49 +12,6 @@ const rule = require("../../../lib/rules/no-promise-executor-return"); const { RuleTester } = require("../../../lib/rule-tester"); -//------------------------------------------------------------------------------ -// Helpers -//------------------------------------------------------------------------------ - -/** - * Creates an error object. - * @param {number} [column] Reported column. - * @param {string} [type="ReturnStatement"] Reported node type. - * @returns {Object} The error object. - */ -function eReturnsValue(column, type = "ReturnStatement") { - const errorObject = { - messageId: "returnsValue", - type - }; - - if (column) { - errorObject.column = column; - } - - return errorObject; -} - - -/** - * Creates invalid object - * @param {Object} [properties] suggestion properties - * @param {string} [properties.code] code - * @param {number} [properties.options] rule options - * @param {string[]} [fixes] Code suggestions - * @returns {Object} The invalid object. - */ -function suggestion(properties, fixes = []) { - return { - ...properties, - errors: [{ - suggestions: fixes.map(fix => ({ - output: fix - })) - }] - }; -} - //------------------------------------------------------------------------------ // Tests //------------------------------------------------------------------------------ @@ -207,7 +164,13 @@ ruleTester.run("no-promise-executor-return", rule, { // full error tests { code: "new Promise(function (resolve, reject) { return 1; })", - errors: [{ message: "Return values from promise executor functions cannot be read.", type: "ReturnStatement", column: 42, endColumn: 51 }] + errors: [{ + message: "Return values from promise executor functions cannot be read.", + type: "ReturnStatement", + column: 42, + endColumn: 51, + suggestions: null + }] }, { code: "new Promise((resolve, reject) => resolve(1))", @@ -220,8 +183,14 @@ ruleTester.run("no-promise-executor-return", rule, { column: 34, endColumn: 44, suggestions: [ - { output: "new Promise((resolve, reject) => void resolve(1))" }, - { output: "new Promise((resolve, reject) => {resolve(1)})" } + { + messageId: "prependVoid", + output: "new Promise((resolve, reject) => void resolve(1))" + }, + { + messageId: "wrapBraces", + output: "new Promise((resolve, reject) => {resolve(1)})" + } ] }] }, @@ -236,351 +205,750 @@ ruleTester.run("no-promise-executor-return", rule, { column: 36, endColumn: 44, suggestions: [ - { output: "new Promise((resolve, reject) => { return void 1 })" } + { + messageId: "prependVoid", + output: "new Promise((resolve, reject) => { return void 1 })" + } ] }] }, // suggestions arrow function expression - suggestion({ + { code: "new Promise(r => 1)", options: [{ allowVoid: true + }], + errors: [{ + messageId: "returnsValue", + type: "Literal", + suggestions: [ + { + messageId: "prependVoid", + output: "new Promise(r => void 1)" + }, + { + messageId: "wrapBraces", + output: "new Promise(r => {1})" + } + ] }] - }, [ - "new Promise(r => void 1)", - "new Promise(r => {1})" - ]), - suggestion({ + }, + { code: "new Promise(r => 1 ? 2 : 3)", options: [{ allowVoid: true + }], + errors: [{ + messageId: "returnsValue", + type: "ConditionalExpression", + suggestions: [ + { + messageId: "prependVoid", + output: "new Promise(r => void (1 ? 2 : 3))" + }, + { + messageId: "wrapBraces", + output: "new Promise(r => {1 ? 2 : 3})" + } + ] }] - }, [ - "new Promise(r => void (1 ? 2 : 3))", - "new Promise(r => {1 ? 2 : 3})" - ]), - suggestion({ + }, + { code: "new Promise(r => (1 ? 2 : 3))", options: [{ allowVoid: true + }], + errors: [{ + messageId: "returnsValue", + type: "ConditionalExpression", + suggestions: [ + { + messageId: "prependVoid", + output: "new Promise(r => void (1 ? 2 : 3))" + }, + { + messageId: "wrapBraces", + output: "new Promise(r => {(1 ? 2 : 3)})" + } + ] }] - }, [ - "new Promise(r => void (1 ? 2 : 3))", - "new Promise(r => {(1 ? 2 : 3)})" - ]), - suggestion({ + }, + { code: "new Promise(r => (1))", options: [{ allowVoid: true + }], + errors: [{ + messageId: "returnsValue", + type: "Literal", + suggestions: [ + { + messageId: "prependVoid", + output: "new Promise(r => void (1))" + }, + { + messageId: "wrapBraces", + output: "new Promise(r => {(1)})" + } + ] }] - }, [ - "new Promise(r => void (1))", - "new Promise(r => {(1)})" - ]), - suggestion({ + }, + { code: "new Promise(r => () => {})", options: [{ allowVoid: true + }], + errors: [{ + messageId: "returnsValue", + type: "ArrowFunctionExpression", + suggestions: [ + { + messageId: "prependVoid", + output: "new Promise(r => void (() => {}))" + }, + { + messageId: "wrapBraces", + output: "new Promise(r => {() => {}})" + } + ] }] - }, [ - "new Promise(r => void (() => {}))", - "new Promise(r => {() => {}})" - ]), + }, // primitives - suggestion({ + { code: "new Promise(r => null)", options: [{ allowVoid: true + }], + errors: [{ + messageId: "returnsValue", + type: "Literal", + suggestions: [ + { + messageId: "prependVoid", + output: "new Promise(r => void null)" + }, + { + messageId: "wrapBraces", + output: "new Promise(r => {null})" + } + ] }] - }, [ - "new Promise(r => void null)", - "new Promise(r => {null})" - ]), - suggestion({ + }, + { code: "new Promise(r => null)", options: [{ allowVoid: false + }], + errors: [{ + messageId: "returnsValue", + type: "Literal", + suggestions: [ + { + messageId: "wrapBraces", + output: "new Promise(r => {null})" + } + ] }] - }, [ - "new Promise(r => {null})" - ]), + }, // inline comments - suggestion({ + { code: "new Promise(r => /*hi*/ ~0)", options: [{ allowVoid: true + }], + errors: [{ + messageId: "returnsValue", + type: "UnaryExpression", + suggestions: [ + { + messageId: "prependVoid", + output: "new Promise(r => /*hi*/ void ~0)" + }, + { + messageId: "wrapBraces", + output: "new Promise(r => /*hi*/ {~0})" + } + ] }] - }, [ - "new Promise(r => /*hi*/ void ~0)", - "new Promise(r => /*hi*/ {~0})" - ]), - suggestion({ + }, + { code: "new Promise(r => /*hi*/ ~0)", options: [{ allowVoid: false + }], + errors: [{ + messageId: "returnsValue", + type: "UnaryExpression", + suggestions: [ + { + messageId: "wrapBraces", + output: "new Promise(r => /*hi*/ {~0})" + } + ] }] - }, [ - "new Promise(r => /*hi*/ {~0})" - ]), + }, // suggestions function - suggestion({ + { code: "new Promise(r => { return 0 })", options: [{ allowVoid: true + }], + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + suggestions: [ + { + messageId: "prependVoid", + output: "new Promise(r => { return void 0 })" + } + ] }] - }, [ - "new Promise(r => { return void 0 })" - ]), - suggestion({ - code: - "new Promise(r => { return 0 })", + }, + { + code: "new Promise(r => { return 0 })", options: [{ allowVoid: false + }], + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + suggestions: null }] - }), + }, // multiple returns - suggestion({ + { code: "new Promise(r => { if (foo) { return void 0 } return 0 })", options: [{ allowVoid: true + }], + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + suggestions: [ + { + messageId: "prependVoid", + output: "new Promise(r => { if (foo) { return void 0 } return void 0 })" + } + ] }] - }, [ - "new Promise(r => { if (foo) { return void 0 } return void 0 })" - ]), + }, // return assignment - suggestion({ + { code: "new Promise(resolve => { return (foo = resolve(1)); })", options: [{ allowVoid: true + }], + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + suggestions: [ + { + messageId: "prependVoid", + output: "new Promise(resolve => { return void (foo = resolve(1)); })" + } + ] }] - }, [ - "new Promise(resolve => { return void (foo = resolve(1)); })" - ]), - suggestion({ + }, + { code: "new Promise(resolve => r = resolve)", options: [{ allowVoid: true + }], + errors: [{ + messageId: "returnsValue", + type: "AssignmentExpression", + suggestions: [ + { + messageId: "prependVoid", + output: "new Promise(resolve => void (r = resolve))" + }, + { + messageId: "wrapBraces", + output: "new Promise(resolve => {r = resolve})" + } + ] }] - }, [ - "new Promise(resolve => void (r = resolve))", - "new Promise(resolve => {r = resolve})" - ]), + }, // return (range check) - suggestion({ + { code: "new Promise(r => { return(1) })", options: [{ allowVoid: true + }], + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + suggestions: [ + { + messageId: "prependVoid", + output: "new Promise(r => { return void (1) })" + } + ] }] - }, [ - "new Promise(r => { return void (1) })" - ]), - suggestion({ + }, + { code: "new Promise(r =>1)", options: [{ allowVoid: true + }], + errors: [{ + messageId: "returnsValue", + type: "Literal", + suggestions: [ + { + messageId: "prependVoid", + output: "new Promise(r =>void 1)" + }, + { + messageId: "wrapBraces", + output: "new Promise(r =>{1})" + } + ] }] - }, [ - "new Promise(r =>void 1)", - "new Promise(r =>{1})" - ]), + }, // snapshot - suggestion({ + { code: "new Promise(r => ((1)))", options: [{ allowVoid: true + }], + errors: [{ + messageId: "returnsValue", + type: "Literal", + suggestions: [ + { + messageId: "prependVoid", + output: "new Promise(r => void ((1)))" + }, + { + messageId: "wrapBraces", + output: "new Promise(r => {((1))})" + } + ] }] - }, [ - "new Promise(r => void ((1)))", - "new Promise(r => {((1))})" - ]), + }, // other basic tests { code: "new Promise(function foo(resolve, reject) { return 1; })", - errors: [eReturnsValue()] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + suggestions: null + }] }, { code: "new Promise((resolve, reject) => { return 1; })", - errors: [eReturnsValue()] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + suggestions: null + }] }, // any returned value { code: "new Promise(function (resolve, reject) { return undefined; })", - errors: [eReturnsValue()] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + suggestions: null + }] }, { code: "new Promise((resolve, reject) => { return null; })", - errors: [eReturnsValue()] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + suggestions: null + }] }, { code: "new Promise(function (resolve, reject) { return false; })", - errors: [eReturnsValue()] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + suggestions: null + }] }, { code: "new Promise((resolve, reject) => resolve)", - errors: [eReturnsValue(34, "Identifier")] + errors: [{ + messageId: "returnsValue", + type: "Identifier", + column: 34, + suggestions: [ + { + messageId: "wrapBraces", + output: "new Promise((resolve, reject) => {resolve})" + } + ] + }] }, { code: "new Promise((resolve, reject) => null)", - errors: [eReturnsValue(34, "Literal")] + errors: [{ + messageId: "returnsValue", + type: "Literal", + column: 34, + suggestions: [ + { + messageId: "wrapBraces", + output: "new Promise((resolve, reject) => {null})" + } + ] + }] }, { code: "new Promise(function (resolve, reject) { return resolve(foo); })", - errors: [eReturnsValue()] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + suggestions: null + }] }, { code: "new Promise((resolve, reject) => { return reject(foo); })", - errors: [eReturnsValue()] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + suggestions: null + }] }, { code: "new Promise((resolve, reject) => x + y)", - errors: [eReturnsValue(34, "BinaryExpression")] + errors: [{ + messageId: "returnsValue", + type: "BinaryExpression", + column: 34, + suggestions: [ + { + messageId: "wrapBraces", + output: "new Promise((resolve, reject) => {x + y})" + } + ] + }] }, { code: "new Promise((resolve, reject) => { return Promise.resolve(42); })", - errors: [eReturnsValue()] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + suggestions: null + }] }, // any return statement location { code: "new Promise(function (resolve, reject) { if (foo) { return 1; } })", - errors: [eReturnsValue()] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + suggestions: null + }] }, { code: "new Promise((resolve, reject) => { try { return 1; } catch(e) {} })", - errors: [eReturnsValue()] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + suggestions: null + }] }, { code: "new Promise(function (resolve, reject) { while (foo){ if (bar) break; else return 1; } })", - errors: [eReturnsValue()] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + suggestions: null + }] }, // `return void` is not allowed without `allowVoid: true` { code: "new Promise(() => { return void 1; })", - errors: [eReturnsValue()] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + suggestions: null + }] }, { code: "new Promise(() => (1))", - errors: [eReturnsValue(20, "Literal")] + errors: [{ + messageId: "returnsValue", + type: "Literal", + column: 20, + suggestions: [ + { + messageId: "wrapBraces", + output: "new Promise(() => {(1)})" + } + ] + }] }, { code: "() => new Promise(() => ({}));", - errors: [eReturnsValue(26, "ObjectExpression")] + errors: [{ + messageId: "returnsValue", + type: "ObjectExpression", + column: 26, + suggestions: [ + { + messageId: "wrapBraces", + output: "() => new Promise(() => {({})});" + } + ] + }] }, // absence of arguments has no effect { code: "new Promise(function () { return 1; })", - errors: [eReturnsValue()] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + suggestions: null + }] }, { code: "new Promise(() => { return 1; })", - errors: [eReturnsValue()] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + suggestions: null + }] }, { code: "new Promise(() => 1)", - errors: [eReturnsValue(19, "Literal")] + errors: [{ + messageId: "returnsValue", + type: "Literal", + column: 19, + suggestions: [ + { + messageId: "wrapBraces", + output: "new Promise(() => {1})" + } + ] + }] }, // various scope tracking tests { code: "function foo() {} new Promise(function () { return 1; });", - errors: [eReturnsValue(45)] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + column: 45, + suggestions: null + }] }, { code: "function foo() { return; } new Promise(() => { return 1; });", - errors: [eReturnsValue(48)] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + column: 48, + suggestions: null + }] }, { code: "function foo() { return 1; } new Promise(() => { return 2; });", - errors: [eReturnsValue(50)] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + column: 50, + suggestions: null + }] }, { code: "function foo () { return new Promise(function () { return 1; }); }", - errors: [eReturnsValue(52)] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + column: 52, + suggestions: null + }] }, { code: "function foo() { return new Promise(() => { bar(() => { return 1; }); return false; }); }", - errors: [eReturnsValue(71)] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + column: 71, + suggestions: null + }] }, { code: "() => new Promise(() => { if (foo) { return 0; } else bar(() => { return 1; }); })", - errors: [eReturnsValue(38)] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + column: 38, + suggestions: null + }] }, { code: "function foo () { return 1; return new Promise(function () { return 2; }); return 3;}", - errors: [eReturnsValue(62)] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + column: 62, + suggestions: null + }] }, { code: "() => 1; new Promise(() => { return 1; })", - errors: [eReturnsValue(30)] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + column: 30, + suggestions: null + }] }, { code: "new Promise(function () { return 1; }); function foo() { return 1; } ", - errors: [eReturnsValue(27)] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + column: 27, + suggestions: null + }] }, { code: "() => new Promise(() => { return 1; });", - errors: [eReturnsValue(27)] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + column: 27, + suggestions: null + }] }, { code: "() => new Promise(() => 1);", - errors: [eReturnsValue(25, "Literal")] + errors: [{ + messageId: "returnsValue", + type: "Literal", + column: 25, + suggestions: [ + { + messageId: "wrapBraces", + output: "() => new Promise(() => {1});" + } + ] + }] }, { code: "() => new Promise(() => () => 1);", - errors: [eReturnsValue(25, "ArrowFunctionExpression")] + errors: [{ + messageId: "returnsValue", + type: "ArrowFunctionExpression", + column: 25, + suggestions: [ + { + messageId: "wrapBraces", + output: "() => new Promise(() => {() => 1});" + } + ] + }] }, { code: "() => new Promise(() => async () => 1);", parserOptions: { ecmaVersion: 2017 }, // for async - errors: [eReturnsValue(25, "ArrowFunctionExpression")] + errors: [{ + messageId: "returnsValue", + type: "ArrowFunctionExpression", + column: 25, + suggestions: [ + { + messageId: "wrapBraces", + output: "() => new Promise(() => {async () => 1});" + } + ] + }] }, { code: "() => new Promise(() => function () {});", - errors: [eReturnsValue(25, "FunctionExpression")] + errors: [{ + messageId: "returnsValue", + type: "FunctionExpression", + column: 25, + suggestions: [ + { + messageId: "wrapBraces", + output: "() => new Promise(() => {function () {}});" + } + ] + }] }, { code: "() => new Promise(() => function foo() {});", - errors: [eReturnsValue(25, "FunctionExpression")] + errors: [{ + messageId: "returnsValue", + type: "FunctionExpression", + column: 25, + suggestions: [ + { + messageId: "wrapBraces", + output: "() => new Promise(() => {function foo() {}});" + } + ] + }] }, { code: "() => new Promise(() => []);", - errors: [eReturnsValue(25, "ArrayExpression")] + errors: [{ + messageId: "returnsValue", + type: "ArrayExpression", + column: 25, + suggestions: [ + { + messageId: "wrapBraces", + output: "() => new Promise(() => {[]});" + } + ] + }] }, // edge cases for global Promise reference { code: "new Promise((Promise) => { return 1; })", - errors: [eReturnsValue()] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + suggestions: null + }] }, { code: "new Promise(function Promise(resolve, reject) { return 1; })", - errors: [eReturnsValue()] + errors: [{ + messageId: "returnsValue", + type: "ReturnStatement", + suggestions: null + }] } ] }); From f30cefee6bda2789ede18e1664b84c2638ea1bb5 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Wed, 18 Oct 2023 17:54:20 +0200 Subject: [PATCH 18/24] test: fix FlatESLint tests for caching (#17658) --- tests/lib/eslint/flat-eslint.js | 387 +++++++++++++++++++------------- 1 file changed, 228 insertions(+), 159 deletions(-) diff --git a/tests/lib/eslint/flat-eslint.js b/tests/lib/eslint/flat-eslint.js index d20dce0c3195..8fdb96ca7bcc 100644 --- a/tests/lib/eslint/flat-eslint.js +++ b/tests/lib/eslint/flat-eslint.js @@ -2215,33 +2215,43 @@ describe("FlatESLint", () => { } } - /** - * helper method to delete the cache files created during testing - * @returns {void} - */ - function deleteCache() { - doDelete(path.resolve(".eslintcache")); - doDelete(path.resolve(".cache/custom-cache")); - } + let cacheFilePath; beforeEach(() => { - deleteCache(); + cacheFilePath = null; }); afterEach(() => { sinon.restore(); - deleteCache(); + if (cacheFilePath) { + doDelete(cacheFilePath); + } }); - describe("when the cacheFile is a directory or looks like a directory", () => { + describe("when cacheLocation is a directory or looks like a directory", () => { + + const cwd = getFixturePath(); /** - * helper method to delete the cache files created during testing + * helper method to delete the directory used in testing * @returns {void} */ function deleteCacheDir() { try { - fs.unlinkSync("./tmp/.cacheFileDir/.cache_hashOfCurrentWorkingDirectory"); + + /* + * `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") { + + // eslint-disable-next-line n/no-unsupported-features/node-builtins -- conditionally used + fs.rmSync(path.resolve(cwd, "tmp/.cacheFileDir/"), { recursive: true, force: true }); + } else { + fs.rmdirSync(path.resolve(cwd, "tmp/.cacheFileDir/"), { recursive: true, force: true }); + } + } catch { /* @@ -2258,11 +2268,12 @@ describe("FlatESLint", () => { deleteCacheDir(); }); - it("should create the cache file inside the provided directory", async () => { - assert(!shell.test("-d", path.resolve("./tmp/.cacheFileDir/.cache_hashOfCurrentWorkingDirectory")), "the cache for eslint does not exist"); + it("should create the directory and the cache file inside it when cacheLocation ends with a slash", async () => { + assert(!shell.test("-d", path.resolve(cwd, "./tmp/.cacheFileDir/")), "the cache directory already exists and wasn't successfully deleted"); eslint = new FlatESLint({ overrideConfigFile: true, + cwd, // specifying cache true the cache will be created cache: true, @@ -2279,41 +2290,71 @@ describe("FlatESLint", () => { await eslint.lintFiles([file]); - assert(shell.test("-f", path.resolve(`./tmp/.cacheFileDir/.cache_${hash(process.cwd())}`)), "the cache for eslint was created"); - - sinon.restore(); + assert(shell.test("-f", path.resolve(cwd, `./tmp/.cacheFileDir/.cache_${hash(cwd)}`)), "the cache for eslint should have been created"); }); - }); - it("should create the cache file inside the provided directory using the cacheLocation option", async () => { - assert(!shell.test("-d", path.resolve("./tmp/.cacheFileDir/.cache_hashOfCurrentWorkingDirectory")), "the cache for eslint does not exist"); + it("should create the cache file inside existing cacheLocation directory when cacheLocation ends with a slash", async () => { + assert(!shell.test("-d", path.resolve(cwd, "./tmp/.cacheFileDir/")), "the cache directory already exists and wasn't successfully deleted"); - eslint = new FlatESLint({ - overrideConfigFile: true, + fs.mkdirSync(path.resolve(cwd, "./tmp/.cacheFileDir/")); - // specifying cache true the cache will be created - cache: true, - cacheLocation: "./tmp/.cacheFileDir/", - overrideConfig: { - rules: { - "no-console": 0, - "no-unused-vars": 2 - } - }, - ignore: false + eslint = new FlatESLint({ + overrideConfigFile: true, + cwd, + + // specifying cache true the cache will be created + cache: true, + cacheLocation: "./tmp/.cacheFileDir/", + overrideConfig: { + rules: { + "no-console": 0, + "no-unused-vars": 2 + } + }, + ignore: false + }); + const file = getFixturePath("cache/src", "test-file.js"); + + await eslint.lintFiles([file]); + + assert(shell.test("-f", path.resolve(cwd, `./tmp/.cacheFileDir/.cache_${hash(cwd)}`)), "the cache for eslint should have been created"); }); - const file = getFixturePath("cache/src", "test-file.js"); - await eslint.lintFiles([file]); + it("should create the cache file inside existing cacheLocation directory when cacheLocation doesn't end with a path separator", async () => { + assert(!shell.test("-d", path.resolve(cwd, "./tmp/.cacheFileDir/")), "the cache directory already exists and wasn't successfully deleted"); - assert(shell.test("-f", path.resolve(`./tmp/.cacheFileDir/.cache_${hash(process.cwd())}`)), "the cache for eslint was created"); + fs.mkdirSync(path.resolve(cwd, "./tmp/.cacheFileDir/")); - sinon.restore(); + eslint = new FlatESLint({ + overrideConfigFile: true, + cwd, + + // specifying cache true the cache will be created + cache: true, + cacheLocation: "./tmp/.cacheFileDir", + overrideConfig: { + rules: { + "no-console": 0, + "no-unused-vars": 2 + } + }, + ignore: false + }); + const file = getFixturePath("cache/src", "test-file.js"); + + await eslint.lintFiles([file]); + + assert(shell.test("-f", path.resolve(cwd, `./tmp/.cacheFileDir/.cache_${hash(cwd)}`)), "the cache for eslint should have been created"); + }); }); it("should create the cache file inside cwd when no cacheLocation provided", async () => { const cwd = path.resolve(getFixturePath("cli-engine")); + cacheFilePath = path.resolve(cwd, ".eslintcache"); + doDelete(cacheFilePath); + assert(!shell.test("-f", cacheFilePath), "the cache file already exists and wasn't successfully deleted"); + eslint = new FlatESLint({ overrideConfigFile: true, cache: true, @@ -2329,14 +2370,15 @@ describe("FlatESLint", () => { await eslint.lintFiles([file]); - assert(shell.test("-f", path.resolve(cwd, ".eslintcache")), "the cache for eslint was created at provided cwd"); + assert(shell.test("-f", cacheFilePath), "the cache for eslint should have been created at provided cwd"); }); it("should invalidate the cache if the overrideConfig changed between executions", async () => { const cwd = getFixturePath("cache/src"); - const cacheLocation = path.resolve(cwd, ".eslintcache"); - assert(!shell.test("-f", cacheLocation), "the cache for eslint does not exist"); + cacheFilePath = path.resolve(cwd, ".eslintcache"); + doDelete(cacheFilePath); + assert(!shell.test("-f", cacheFilePath), "the cache file already exists and wasn't successfully deleted"); eslint = new FlatESLint({ overrideConfigFile: true, @@ -2361,11 +2403,11 @@ describe("FlatESLint", () => { const results = await eslint.lintFiles([file]); for (const { errorCount, warningCount } of results) { - assert.strictEqual(errorCount + warningCount, 0, "the file passed without errors or warnings"); + assert.strictEqual(errorCount + warningCount, 0, "the file should have passed linting without errors or warnings"); } - assert(spy.calledWith(file), "ESLint should have read the file because it's considered changed"); - assert(shell.test("-f", cacheLocation), "the cache for eslint should still exist"); + assert(spy.calledWith(file), "ESLint should have read the file because there was no cache file"); + assert(shell.test("-f", cacheFilePath), "the cache for eslint should have been created"); // destroy the spy sinon.restore(); @@ -2388,17 +2430,20 @@ describe("FlatESLint", () => { // create a new spy spy = sinon.spy(fs.promises, "readFile"); - const [cachedResult] = await eslint.lintFiles([file]); + const [newResult] = await eslint.lintFiles([file]); - assert(spy.calledWith(file), "ESLint should have read the file again because is considered changed because the config changed"); - assert.strictEqual(cachedResult.errorCount, 1, "since configuration changed the cache was not used and one error was reported"); - assert(shell.test("-f", cacheLocation), "The cache for ESLint should still exist (2)"); + assert(spy.calledWith(file), "ESLint should have read the file again because it's considered changed because the config changed"); + assert.strictEqual(newResult.errorCount, 1, "since configuration changed the cache should have not been used and one error should have been reported"); + assert.strictEqual(newResult.messages[0].ruleId, "no-console"); + assert(shell.test("-f", cacheFilePath), "The cache for ESLint should still exist"); }); it("should remember the files from a previous run and do not operate on them if not changed", async () => { - const cwd = getFixturePath("cache/src"); - const cacheLocation = path.resolve(cwd, ".eslintcache"); + + cacheFilePath = path.resolve(cwd, ".eslintcache"); + doDelete(cacheFilePath); + assert(!shell.test("-f", cacheFilePath), "the cache file already exists and wasn't successfully deleted"); eslint = new FlatESLint({ overrideConfigFile: true, @@ -2423,8 +2468,8 @@ describe("FlatESLint", () => { const result = await eslint.lintFiles([file]); - assert(spy.calledWith(file), "the module read the file because is considered changed"); - assert(shell.test("-f", cacheLocation), "the cache for eslint was created"); + assert(spy.calledWith(file), "ESLint should have read the file because there was no cache file"); + assert(shell.test("-f", cacheFilePath), "the cache for eslint should have been created"); // destroy the spy sinon.restore(); @@ -2449,20 +2494,23 @@ describe("FlatESLint", () => { const cachedResult = await eslint.lintFiles([file]); - assert.deepStrictEqual(result, cachedResult, "the result is the same regardless of using cache or not"); + assert.deepStrictEqual(result, cachedResult, "the result should have been the same"); // assert the file was not processed because the cache was used - assert(!spy.calledWith(file), "the file was not loaded because it used the cache"); + assert(!spy.calledWith(file), "the file should not have been reloaded"); }); - it("should remember the files from a previous run and do not operate on then if not changed", async () => { - const cacheLocation = getFixturePath(".eslintcache"); + it("when `cacheLocation` is specified, should create the cache file with `cache:true` and then delete it with `cache:false`", async () => { + cacheFilePath = getFixturePath(".eslintcache"); + doDelete(cacheFilePath); + assert(!shell.test("-f", cacheFilePath), "the cache file already exists and wasn't successfully deleted"); + const eslintOptions = { overrideConfigFile: true, // specifying cache true the cache will be created cache: true, - cacheLocation, + cacheLocation: cacheFilePath, overrideConfig: { rules: { "no-console": 0, @@ -2472,8 +2520,6 @@ describe("FlatESLint", () => { cwd: path.join(fixtureDir, "..") }; - assert(!shell.test("-f", cacheLocation), "the cache for eslint does not exist"); - eslint = new FlatESLint(eslintOptions); let file = getFixturePath("cache/src", "test-file.js"); @@ -2482,20 +2528,20 @@ describe("FlatESLint", () => { await eslint.lintFiles([file]); - assert(shell.test("-f", cacheLocation), "the cache for eslint was created"); + assert(shell.test("-f", cacheFilePath), "the cache for eslint should have been created"); eslintOptions.cache = false; eslint = new FlatESLint(eslintOptions); await eslint.lintFiles([file]); - assert(!shell.test("-f", cacheLocation), "the cache for eslint was deleted since last run did not used the cache"); + assert(!shell.test("-f", cacheFilePath), "the cache for eslint should have been deleted since last run did not use the cache"); }); - it("should store in the cache a file that failed the test", async () => { - const cacheLocation = getFixturePath(".eslintcache"); - - assert(!shell.test("-f", cacheLocation), "the cache for eslint does not exist"); + it("should store in the cache a file that has lint messages and a file that doesn't have lint messages", async () => { + cacheFilePath = getFixturePath(".eslintcache"); + doDelete(cacheFilePath); + assert(!shell.test("-f", cacheFilePath), "the cache file already exists and wasn't successfully deleted"); eslint = new FlatESLint({ cwd: path.join(fixtureDir, ".."), @@ -2503,7 +2549,7 @@ describe("FlatESLint", () => { // specifying cache true the cache will be created cache: true, - cacheLocation, + cacheLocation: cacheFilePath, overrideConfig: { rules: { "no-console": 0, @@ -2514,22 +2560,27 @@ describe("FlatESLint", () => { const badFile = fs.realpathSync(getFixturePath("cache/src", "fail-file.js")); const goodFile = fs.realpathSync(getFixturePath("cache/src", "test-file.js")); const result = await eslint.lintFiles([badFile, goodFile]); + const [badFileResult, goodFileResult] = result; + + assert.notStrictEqual(badFileResult.errorCount + badFileResult.warningCount, 0, "the bad file should have some lint errors or warnings"); + assert.strictEqual(goodFileResult.errorCount + badFileResult.warningCount, 0, "the good file should have passed linting without errors or warnings"); + + assert(shell.test("-f", cacheFilePath), "the cache for eslint should have been created"); - assert(shell.test("-f", cacheLocation), "the cache for eslint was created"); - const fileCache = fCache.createFromFile(cacheLocation); + const fileCache = fCache.createFromFile(cacheFilePath); const { cache } = fileCache; - assert.strictEqual(typeof cache.getKey(goodFile), "object", "the entry for the good file is in the cache"); - assert.strictEqual(typeof cache.getKey(badFile), "object", "the entry for the bad file is in the cache"); + assert.strictEqual(typeof cache.getKey(goodFile), "object", "the entry for the good file should have been in the cache"); + assert.strictEqual(typeof cache.getKey(badFile), "object", "the entry for the bad file should have been in the cache"); const cachedResult = await eslint.lintFiles([badFile, goodFile]); - assert.deepStrictEqual(result, cachedResult, "result is the same with or without cache"); + assert.deepStrictEqual(result, cachedResult, "result should be the same with or without cache"); }); it("should not contain in the cache a file that was deleted", async () => { - const cacheLocation = getFixturePath(".eslintcache"); - - doDelete(cacheLocation); + cacheFilePath = getFixturePath(".eslintcache"); + doDelete(cacheFilePath); + assert(!shell.test("-f", cacheFilePath), "the cache file already exists and wasn't successfully deleted"); eslint = new FlatESLint({ cwd: path.join(fixtureDir, ".."), @@ -2537,7 +2588,7 @@ describe("FlatESLint", () => { // specifying cache true the cache will be created cache: true, - cacheLocation, + cacheLocation: cacheFilePath, overrideConfig: { rules: { "no-console": 0, @@ -2550,10 +2601,10 @@ describe("FlatESLint", () => { const toBeDeletedFile = fs.realpathSync(getFixturePath("cache/src", "file-to-delete.js")); await eslint.lintFiles([badFile, goodFile, toBeDeletedFile]); - const fileCache = fCache.createFromFile(cacheLocation); + const fileCache = fCache.createFromFile(cacheFilePath); let { cache } = fileCache; - assert.strictEqual(typeof cache.getKey(toBeDeletedFile), "object", "the entry for the file to be deleted is in the cache"); + assert.strictEqual(typeof cache.getKey(toBeDeletedFile), "object", "the entry for the file to be deleted should have been in the cache"); // delete the file from the file system fs.unlinkSync(toBeDeletedFile); @@ -2564,15 +2615,19 @@ describe("FlatESLint", () => { */ await eslint.lintFiles([badFile, goodFile]); - cache = JSON.parse(fs.readFileSync(cacheLocation)); + cache = JSON.parse(fs.readFileSync(cacheFilePath)); + + assert.strictEqual(typeof cache[0][toBeDeletedFile], "undefined", "the entry for the file to be deleted should not have been in the cache"); - assert.strictEqual(typeof cache[toBeDeletedFile], "undefined", "the entry for the file to be deleted is not in the cache"); + // make sure that the previos assertion checks the right place + assert.notStrictEqual(typeof cache[0][badFile], "undefined", "the entry for the bad file should have been in the cache"); + assert.notStrictEqual(typeof cache[0][goodFile], "undefined", "the entry for the good file should have been in the cache"); }); it("should contain files that were not visited in the cache provided they still exist", async () => { - const cacheLocation = getFixturePath(".eslintcache"); - - doDelete(cacheLocation); + cacheFilePath = getFixturePath(".eslintcache"); + doDelete(cacheFilePath); + assert(!shell.test("-f", cacheFilePath), "the cache file already exists and wasn't successfully deleted"); eslint = new FlatESLint({ cwd: path.join(fixtureDir, ".."), @@ -2580,7 +2635,7 @@ describe("FlatESLint", () => { // specifying cache true the cache will be created cache: true, - cacheLocation, + cacheLocation: cacheFilePath, overrideConfig: { rules: { "no-console": 0, @@ -2594,31 +2649,35 @@ describe("FlatESLint", () => { await eslint.lintFiles([badFile, goodFile, testFile2]); - let fileCache = fCache.createFromFile(cacheLocation); + let fileCache = fCache.createFromFile(cacheFilePath); let { cache } = fileCache; - assert.strictEqual(typeof cache.getKey(testFile2), "object", "the entry for the test-file2 is in the cache"); + assert.strictEqual(typeof cache.getKey(testFile2), "object", "the entry for the test-file2 should have been in the cache"); /* - * we pass a different set of files minus test-file2 + * we pass a different set of files (minus test-file2) * previous version of file-entry-cache would remove the non visited * entries. 2.0.0 version will keep them unless they don't exist */ await eslint.lintFiles([badFile, goodFile]); - fileCache = fCache.createFromFile(cacheLocation); + fileCache = fCache.createFromFile(cacheFilePath); cache = fileCache.cache; - assert.strictEqual(typeof cache.getKey(testFile2), "object", "the entry for the test-file2 is in the cache"); + assert.strictEqual(typeof cache.getKey(testFile2), "object", "the entry for the test-file2 should have been in the cache"); }); it("should not delete cache when executing on text", async () => { - const cacheLocation = getFixturePath(".eslintcache"); + cacheFilePath = getFixturePath(".eslintcache"); + doDelete(cacheFilePath); + assert(!shell.test("-f", cacheFilePath), "the cache file already exists and wasn't successfully deleted"); + + fs.writeFileSync(cacheFilePath, "[]"); // intenationally invalid to additionally make sure it isn't used eslint = new FlatESLint({ cwd: path.join(fixtureDir, ".."), overrideConfigFile: true, - cacheLocation, + cacheLocation: cacheFilePath, overrideConfig: { rules: { "no-console": 0, @@ -2627,20 +2686,24 @@ describe("FlatESLint", () => { } }); - assert(shell.test("-f", cacheLocation), "the cache for eslint exists"); + assert(shell.test("-f", cacheFilePath), "the cache for eslint should exist"); await eslint.lintText("var foo = 'bar';"); - assert(shell.test("-f", cacheLocation), "the cache for eslint still exists"); + assert(shell.test("-f", cacheFilePath), "the cache for eslint should still exist"); }); it("should not delete cache when executing on text with a provided filename", async () => { - const cacheLocation = getFixturePath(".eslintcache"); + cacheFilePath = getFixturePath(".eslintcache"); + doDelete(cacheFilePath); + assert(!shell.test("-f", cacheFilePath), "the cache file already exists and wasn't successfully deleted"); + + fs.writeFileSync(cacheFilePath, "[]"); // intenationally invalid to additionally make sure it isn't used eslint = new FlatESLint({ cwd: path.join(fixtureDir, ".."), overrideConfigFile: true, - cacheLocation, + cacheLocation: cacheFilePath, overrideConfig: { rules: { "no-console": 0, @@ -2649,21 +2712,25 @@ describe("FlatESLint", () => { } }); - assert(shell.test("-f", cacheLocation), "the cache for eslint exists"); + assert(shell.test("-f", cacheFilePath), "the cache for eslint should exist"); await eslint.lintText("var bar = foo;", { filePath: "fixtures/passing.js" }); - assert(shell.test("-f", cacheLocation), "the cache for eslint still exists"); + assert(shell.test("-f", cacheFilePath), "the cache for eslint should still exist"); }); it("should not delete cache when executing on files with --cache flag", async () => { - const cacheLocation = getFixturePath(".eslintcache"); + cacheFilePath = getFixturePath(".eslintcache"); + doDelete(cacheFilePath); + assert(!shell.test("-f", cacheFilePath), "the cache file already exists and wasn't successfully deleted"); + + fs.writeFileSync(cacheFilePath, ""); eslint = new FlatESLint({ cwd: path.join(fixtureDir, ".."), overrideConfigFile: true, cache: true, - cacheLocation, + cacheLocation: cacheFilePath, overrideConfig: { rules: { "no-console": 0, @@ -2673,82 +2740,84 @@ describe("FlatESLint", () => { }); const file = getFixturePath("cli-engine", "console.js"); - assert(shell.test("-f", cacheLocation), "the cache for eslint exists"); + assert(shell.test("-f", cacheFilePath), "the cache for eslint should exist"); await eslint.lintFiles([file]); - assert(shell.test("-f", cacheLocation), "the cache for eslint still exists"); + assert(shell.test("-f", cacheFilePath), "the cache for eslint should still exist"); }); it("should delete cache when executing on files without --cache flag", async () => { - const cacheLocation = getFixturePath(".eslintcache"); + cacheFilePath = getFixturePath(".eslintcache"); + doDelete(cacheFilePath); + assert(!shell.test("-f", cacheFilePath), "the cache file already exists and wasn't successfully deleted"); + + fs.writeFileSync(cacheFilePath, "[]"); // intenationally invalid to additionally make sure it isn't used eslint = new FlatESLint({ cwd: path.join(fixtureDir, ".."), overrideConfigFile: true, - cacheLocation, + cacheLocation: cacheFilePath, overrideConfig: { rules: { "no-console": 0, "no-unused-vars": 2 } } - }); const file = getFixturePath("cli-engine", "console.js"); - assert(shell.test("-f", cacheLocation), "the cache for eslint exists"); + assert(shell.test("-f", cacheFilePath), "the cache for eslint should exist"); await eslint.lintFiles([file]); - assert(!shell.test("-f", cacheLocation), "the cache for eslint has been deleted"); + assert(!shell.test("-f", cacheFilePath), "the cache for eslint should have been deleted"); }); - describe("cacheFile", () => { - it("should use the specified cache file", async () => { - const customCacheFile = path.resolve(".cache/custom-cache"); + it("should use the specified cache file", async () => { + cacheFilePath = path.resolve(".cache/custom-cache"); + doDelete(cacheFilePath); + assert(!shell.test("-f", cacheFilePath), "the cache file already exists and wasn't successfully deleted"); - assert(!shell.test("-f", customCacheFile), "the cache for eslint does not exist"); + eslint = new FlatESLint({ + overrideConfigFile: true, - eslint = new FlatESLint({ - overrideConfigFile: true, + // specify a custom cache file + cacheLocation: cacheFilePath, - // specify a custom cache file - cacheLocation: customCacheFile, + // specifying cache true the cache will be created + cache: true, + overrideConfig: { + rules: { + "no-console": 0, + "no-unused-vars": 2 + } + }, - // specifying cache true the cache will be created - cache: true, - overrideConfig: { - rules: { - "no-console": 0, - "no-unused-vars": 2 - } - }, + cwd: path.join(fixtureDir, "..") + }); + const badFile = fs.realpathSync(getFixturePath("cache/src", "fail-file.js")); + const goodFile = fs.realpathSync(getFixturePath("cache/src", "test-file.js")); + const result = await eslint.lintFiles([badFile, goodFile]); - cwd: path.join(fixtureDir, "..") - }); - const badFile = fs.realpathSync(getFixturePath("cache/src", "fail-file.js")); - const goodFile = fs.realpathSync(getFixturePath("cache/src", "test-file.js")); - const result = await eslint.lintFiles([badFile, goodFile]); + assert(shell.test("-f", cacheFilePath), "the cache for eslint should have been created"); - assert(shell.test("-f", customCacheFile), "the cache for eslint was created"); - const fileCache = fCache.createFromFile(customCacheFile); - const { cache } = fileCache; + const fileCache = fCache.createFromFile(cacheFilePath); + const { cache } = fileCache; - assert(typeof cache.getKey(goodFile) === "object", "the entry for the good file is in the cache"); + assert(typeof cache.getKey(goodFile) === "object", "the entry for the good file should have been in the cache"); + assert(typeof cache.getKey(badFile) === "object", "the entry for the bad file should have been in the cache"); - assert(typeof cache.getKey(badFile) === "object", "the entry for the bad file is in the cache"); - const cachedResult = await eslint.lintFiles([badFile, goodFile]); + const cachedResult = await eslint.lintFiles([badFile, goodFile]); - assert.deepStrictEqual(result, cachedResult, "result is the same with or without cache"); - }); + assert.deepStrictEqual(result, cachedResult, "result should be the same with or without cache"); }); describe("cacheStrategy", () => { it("should detect changes using a file's modification time when set to 'metadata'", async () => { - const cacheLocation = getFixturePath(".eslintcache"); - - doDelete(cacheLocation); + cacheFilePath = getFixturePath(".eslintcache"); + doDelete(cacheFilePath); + assert(!shell.test("-f", cacheFilePath), "the cache file already exists and wasn't successfully deleted"); eslint = new FlatESLint({ cwd: path.join(fixtureDir, ".."), @@ -2756,7 +2825,7 @@ describe("FlatESLint", () => { // specifying cache true the cache will be created cache: true, - cacheLocation, + cacheLocation: cacheFilePath, cacheStrategy: "metadata", overrideConfig: { rules: { @@ -2770,24 +2839,24 @@ describe("FlatESLint", () => { const goodFile = fs.realpathSync(getFixturePath("cache/src", "test-file.js")); await eslint.lintFiles([badFile, goodFile]); - let fileCache = fCache.createFromFile(cacheLocation); + let fileCache = fCache.createFromFile(cacheFilePath); const entries = fileCache.normalizeEntries([badFile, goodFile]); entries.forEach(entry => { - assert(entry.changed === false, `the entry for ${entry.key} is initially unchanged`); + assert(entry.changed === false, `the entry for ${entry.key} should have been initially unchanged`); }); // this should result in a changed entry shell.touch(goodFile); - fileCache = fCache.createFromFile(cacheLocation); - assert(fileCache.getFileDescriptor(badFile).changed === false, `the entry for ${badFile} is unchanged`); - assert(fileCache.getFileDescriptor(goodFile).changed === true, `the entry for ${goodFile} is changed`); + fileCache = fCache.createFromFile(cacheFilePath); + assert(fileCache.getFileDescriptor(badFile).changed === false, `the entry for ${badFile} should have been unchanged`); + assert(fileCache.getFileDescriptor(goodFile).changed === true, `the entry for ${goodFile} should have been changed`); }); it("should not detect changes using a file's modification time when set to 'content'", async () => { - const cacheLocation = getFixturePath(".eslintcache"); - - doDelete(cacheLocation); + cacheFilePath = getFixturePath(".eslintcache"); + doDelete(cacheFilePath); + assert(!shell.test("-f", cacheFilePath), "the cache file already exists and wasn't successfully deleted"); eslint = new FlatESLint({ cwd: path.join(fixtureDir, ".."), @@ -2795,7 +2864,7 @@ describe("FlatESLint", () => { // specifying cache true the cache will be created cache: true, - cacheLocation, + cacheLocation: cacheFilePath, cacheStrategy: "content", overrideConfig: { rules: { @@ -2809,26 +2878,26 @@ describe("FlatESLint", () => { const goodFile = fs.realpathSync(getFixturePath("cache/src", "test-file.js")); await eslint.lintFiles([badFile, goodFile]); - let fileCache = fCache.createFromFile(cacheLocation, true); + let fileCache = fCache.createFromFile(cacheFilePath, true); let entries = fileCache.normalizeEntries([badFile, goodFile]); entries.forEach(entry => { - assert(entry.changed === false, `the entry for ${entry.key} is initially unchanged`); + assert(entry.changed === false, `the entry for ${entry.key} should have been initially unchanged`); }); // this should NOT result in a changed entry shell.touch(goodFile); - fileCache = fCache.createFromFile(cacheLocation, true); + fileCache = fCache.createFromFile(cacheFilePath, true); entries = fileCache.normalizeEntries([badFile, goodFile]); entries.forEach(entry => { - assert(entry.changed === false, `the entry for ${entry.key} remains unchanged`); + assert(entry.changed === false, `the entry for ${entry.key} should have remained unchanged`); }); }); it("should detect changes using a file's contents when set to 'content'", async () => { - const cacheLocation = getFixturePath(".eslintcache"); - - doDelete(cacheLocation); + cacheFilePath = getFixturePath(".eslintcache"); + doDelete(cacheFilePath); + assert(!shell.test("-f", cacheFilePath), "the cache file already exists and wasn't successfully deleted"); eslint = new FlatESLint({ cwd: path.join(fixtureDir, ".."), @@ -2836,7 +2905,7 @@ describe("FlatESLint", () => { // specifying cache true the cache will be created cache: true, - cacheLocation, + cacheLocation: cacheFilePath, cacheStrategy: "content", overrideConfig: { rules: { @@ -2853,18 +2922,18 @@ describe("FlatESLint", () => { shell.cp(goodFile, goodFileCopy); await eslint.lintFiles([badFile, goodFileCopy]); - let fileCache = fCache.createFromFile(cacheLocation, true); + let fileCache = fCache.createFromFile(cacheFilePath, true); const entries = fileCache.normalizeEntries([badFile, goodFileCopy]); entries.forEach(entry => { - assert(entry.changed === false, `the entry for ${entry.key} is initially unchanged`); + assert(entry.changed === false, `the entry for ${entry.key} should have been initially unchanged`); }); // this should result in a changed entry shell.sed("-i", "abc", "xzy", goodFileCopy); - fileCache = fCache.createFromFile(cacheLocation, true); - assert(fileCache.getFileDescriptor(badFile).changed === false, `the entry for ${badFile} is unchanged`); - assert(fileCache.getFileDescriptor(goodFileCopy).changed === true, `the entry for ${goodFileCopy} is changed`); + fileCache = fCache.createFromFile(cacheFilePath, true); + assert(fileCache.getFileDescriptor(badFile).changed === false, `the entry for ${badFile} should have been unchanged`); + assert(fileCache.getFileDescriptor(goodFileCopy).changed === true, `the entry for ${goodFileCopy} should have been changed`); }); }); }); From 5de9637fc925729a83d5a5e9e868a41792a184e3 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Fri, 20 Oct 2023 13:00:16 -0400 Subject: [PATCH 19/24] fix: Ensure shared references in rule configs are separated (#17666) * fix: Ensure shared references in rule configs are separated. In eslint.config.js files, it's possible for two rule configs to contain references to the same object. That object may be modified during validation, thus affecting all configs, and may create validation errors. This clones rule configs before validation to ensure that each rule is using unique references to manage its configs. Fixes #12592 * Update tests/lib/config/flat-config-array.js Co-authored-by: Milos Djermanovic * Update tests/lib/config/flat-config-array.js Co-authored-by: Milos Djermanovic * Update lib/config/flat-config-schema.js Co-authored-by: Milos Djermanovic * Update lib/config/flat-config-schema.js Co-authored-by: Milos Djermanovic * Upgrade config-array and update tests --------- Co-authored-by: Milos Djermanovic --- lib/config/flat-config-schema.js | 91 ++++++++++++++++----------- package.json | 3 +- tests/lib/config/flat-config-array.js | 67 ++++++++++++++++++++ 3 files changed, 124 insertions(+), 37 deletions(-) diff --git a/lib/config/flat-config-schema.js b/lib/config/flat-config-schema.js index df850995d87f..911d159d93b8 100644 --- a/lib/config/flat-config-schema.js +++ b/lib/config/flat-config-schema.js @@ -5,6 +5,16 @@ "use strict"; +//----------------------------------------------------------------------------- +// Requirements +//----------------------------------------------------------------------------- + +/* + * Note: This can be removed in ESLint v9 because structuredClone is available globally + * starting in Node.js v17. + */ +const structuredClone = require("@ungap/structured-clone").default; + //----------------------------------------------------------------------------- // Type Definitions //----------------------------------------------------------------------------- @@ -119,7 +129,7 @@ function normalizeRuleOptions(ruleOptions) { : [ruleOptions]; finalOptions[0] = ruleSeverities.get(finalOptions[0]); - return finalOptions; + return structuredClone(finalOptions); } //----------------------------------------------------------------------------- @@ -378,48 +388,57 @@ const rulesSchema = { ...second }; - for (const ruleId of Object.keys(result)) { - - // avoid hairy edge case - if (ruleId === "__proto__") { - - /* eslint-disable-next-line no-proto -- Though deprecated, may still be present */ - delete result.__proto__; - continue; - } - - result[ruleId] = normalizeRuleOptions(result[ruleId]); - - /* - * If either rule config is missing, then the correct - * config is already present and we just need to normalize - * the severity. - */ - if (!(ruleId in first) || !(ruleId in second)) { - continue; - } - const firstRuleOptions = normalizeRuleOptions(first[ruleId]); - const secondRuleOptions = normalizeRuleOptions(second[ruleId]); + for (const ruleId of Object.keys(result)) { - /* - * If the second rule config only has a severity (length of 1), - * then use that severity and keep the rest of the options from - * the first rule config. - */ - if (secondRuleOptions.length === 1) { - result[ruleId] = [secondRuleOptions[0], ...firstRuleOptions.slice(1)]; - continue; + try { + + // avoid hairy edge case + if (ruleId === "__proto__") { + + /* eslint-disable-next-line no-proto -- Though deprecated, may still be present */ + delete result.__proto__; + continue; + } + + result[ruleId] = normalizeRuleOptions(result[ruleId]); + + /* + * If either rule config is missing, then the correct + * config is already present and we just need to normalize + * the severity. + */ + if (!(ruleId in first) || !(ruleId in second)) { + continue; + } + + const firstRuleOptions = normalizeRuleOptions(first[ruleId]); + const secondRuleOptions = normalizeRuleOptions(second[ruleId]); + + /* + * If the second rule config only has a severity (length of 1), + * then use that severity and keep the rest of the options from + * the first rule config. + */ + if (secondRuleOptions.length === 1) { + result[ruleId] = [secondRuleOptions[0], ...firstRuleOptions.slice(1)]; + continue; + } + + /* + * In any other situation, then the second rule config takes + * precedence. That means the value at `result[ruleId]` is + * already correct and no further work is necessary. + */ + } catch (ex) { + throw new Error(`Key "${ruleId}": ${ex.message}`, { cause: ex }); } - /* - * In any other situation, then the second rule config takes - * precedence. That means the value at `result[ruleId]` is - * already correct and no further work is necessary. - */ } return result; + + }, validate(value) { diff --git a/package.json b/package.json index ece3957419ee..8f4a112e3cdb 100644 --- a/package.json +++ b/package.json @@ -64,9 +64,10 @@ "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", "@eslint/js": "8.51.0", - "@humanwhocodes/config-array": "^0.11.11", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", diff --git a/tests/lib/config/flat-config-array.js b/tests/lib/config/flat-config-array.js index 728b3e93785c..b0dbfec93f7f 100644 --- a/tests/lib/config/flat-config-array.js +++ b/tests/lib/config/flat-config-array.js @@ -1987,4 +1987,71 @@ describe("FlatConfigArray", () => { }); }); + + // https://github.com/eslint/eslint/issues/12592 + describe("Shared references between rule configs", () => { + + it("shared rule config should not cause a rule validation error", () => { + + const ruleConfig = ["error", {}]; + + const configs = new FlatConfigArray([{ + rules: { + camelcase: ruleConfig, + "default-case": ruleConfig + } + }]); + + configs.normalizeSync(); + + const config = configs.getConfig("foo.js"); + + assert.deepStrictEqual(config.rules, { + camelcase: [2, { + ignoreDestructuring: false, + ignoreGlobals: false, + ignoreImports: false + }], + "default-case": [2, {}] + }); + + }); + + + it("should throw rule validation error for camelcase", async () => { + + const ruleConfig = ["error", {}]; + + const configs = new FlatConfigArray([ + { + rules: { + camelcase: ruleConfig + } + }, + { + rules: { + "default-case": ruleConfig, + + + camelcase: [ + "error", + { + ignoreDestructuring: Date + } + + ] + } + } + ]); + + configs.normalizeSync(); + + // exact error may differ based on structuredClone implementation so just test prefix + assert.throws(() => { + configs.getConfig("foo.js"); + }, /Key "rules": Key "camelcase":/u); + + }); + + }); }); From 476d58a584d5d2db003c4c22ffee90e63566164d Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Fri, 20 Oct 2023 13:19:22 -0400 Subject: [PATCH 20/24] docs: Add note about invalid CLI flags when using flat config. (#17664) * fix: Add note about invalid CLI flags when using flat config. Fixes #17652 * Update docs/src/use/command-line-interface.md Co-authored-by: Milos Djermanovic * Upgrade config-array * Move error message --------- Co-authored-by: Milos Djermanovic --- docs/src/use/command-line-interface.md | 10 +++++----- lib/cli.js | 9 ++++++++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/docs/src/use/command-line-interface.md b/docs/src/use/command-line-interface.md index 6087aae4fcc6..4749b7c19ec6 100644 --- a/docs/src/use/command-line-interface.md +++ b/docs/src/use/command-line-interface.md @@ -121,7 +121,7 @@ Miscellaneous: #### `--no-eslintrc` -Disables use of configuration from `.eslintrc.*` and `package.json` files. +**eslintrc Mode Only.** Disables use of configuration from `.eslintrc.*` and `package.json` files. For flat config mode, use `--no-config-lookup` instead. * **Argument Type**: No argument. @@ -150,7 +150,7 @@ If `.eslintrc.*` and/or `package.json` files are also used for configuration (i. #### `--env` -This option enables specific environments. +**eslintrc Mode Only.** This option enables specific environments. * **Argument Type**: String. One of the available environments. * **Multiple Arguments**: Yes @@ -166,7 +166,7 @@ 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. +**eslintrc Mode Only.** 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 @@ -232,7 +232,7 @@ echo '3 ** 4' | npx eslint --stdin --parser-options ecmaVersion:7 # succeeds, ya #### `--resolve-plugins-relative-to` -Changes the directory where plugins are resolved from. +**eslintrc Mode Only.** Changes the directory where plugins are resolved from. * **Argument Type**: String. Path to directory. * **Multiple Arguments**: No @@ -374,7 +374,7 @@ npx eslint --fix --fix-type suggestion,layout . #### `--ignore-path` -This option allows you to specify the file to use as your `.eslintignore`. +**eslintrc Mode Only.** This option allows you to specify the file to use as your `.eslintignore`. * **Argument Type**: String. Path to file. * **Multiple Arguments**: No diff --git a/lib/cli.js b/lib/cli.js index 807d28a0d1bc..f472659c20f9 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -318,7 +318,14 @@ const cli = { options = CLIOptions.parse(args); } catch (error) { debug("Error parsing CLI options:", error.message); - log.error(error.message); + + let errorMessage = error.message; + + if (usingFlatConfig) { + errorMessage += "\nYou're using eslint.config.js, some command line flags are no longer available. Please see https://eslint.org/docs/latest/use/command-line-interface for details."; + } + + log.error(errorMessage); return 2; } From d63d4fe0942e6747ab60e758aa36076f43041a30 Mon Sep 17 00:00:00 2001 From: ESLint Jenkins Date: Fri, 20 Oct 2023 16:25:39 -0400 Subject: [PATCH 21/24] chore: package.json update for @eslint/js release --- packages/js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/js/package.json b/packages/js/package.json index 7e43db7f2e9a..f9d8a1c66925 100644 --- a/packages/js/package.json +++ b/packages/js/package.json @@ -1,6 +1,6 @@ { "name": "@eslint/js", - "version": "8.51.0", + "version": "8.52.0", "description": "ESLint JavaScript language implementation", "main": "./src/index.js", "scripts": {}, From 6d1f0c2da0309c06c21149b8d71a8f439a70d7e8 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Fri, 20 Oct 2023 22:44:39 +0200 Subject: [PATCH 22/24] chore: upgrade @eslint/js@8.52.0 (#17671) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8f4a112e3cdb..14f86b846cfc 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.51.0", + "@eslint/js": "8.52.0", "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", From 7dc28ed1615169c68c08808fa445172cc0cf37e0 Mon Sep 17 00:00:00 2001 From: ESLint Jenkins Date: Fri, 20 Oct 2023 17:00:03 -0400 Subject: [PATCH 23/24] Build: changelog update for 8.52.0 --- CHANGELOG.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61aa641c59f3..7cbca458d6c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,28 @@ +v8.52.0 - October 20, 2023 + +* [`6d1f0c2`](https://github.com/eslint/eslint/commit/6d1f0c2da0309c06c21149b8d71a8f439a70d7e8) chore: upgrade @eslint/js@8.52.0 (#17671) (Milos Djermanovic) +* [`d63d4fe`](https://github.com/eslint/eslint/commit/d63d4fe0942e6747ab60e758aa36076f43041a30) chore: package.json update for @eslint/js release (ESLint Jenkins) +* [`476d58a`](https://github.com/eslint/eslint/commit/476d58a584d5d2db003c4c22ffee90e63566164d) docs: Add note about invalid CLI flags when using flat config. (#17664) (Nicholas C. Zakas) +* [`5de9637`](https://github.com/eslint/eslint/commit/5de9637fc925729a83d5a5e9e868a41792a184e3) fix: Ensure shared references in rule configs are separated (#17666) (Nicholas C. Zakas) +* [`f30cefe`](https://github.com/eslint/eslint/commit/f30cefee6bda2789ede18e1664b84c2638ea1bb5) test: fix FlatESLint tests for caching (#17658) (Milos Djermanovic) +* [`ef650cb`](https://github.com/eslint/eslint/commit/ef650cb612510bcfa1379c1f0af56dd563b3a705) test: update tests for no-promise-executor-return (#17661) (Milos Djermanovic) +* [`70648ee`](https://github.com/eslint/eslint/commit/70648ee49c07f7b533d09f6bf8a5291e5a5a8601) feat: report-unused-disable-directive to report unused eslint-enable (#17611) (Yosuke Ota) +* [`dcfe573`](https://github.com/eslint/eslint/commit/dcfe5739c374c9d7ed21f14027870ec0fd453661) fix: add preceding semicolon in suggestions of `no-object-constructor` (#17649) (Francesco Trotta) +* [`660ed3a`](https://github.com/eslint/eslint/commit/660ed3afd128ad529234a855345629982caf1bc7) docs: Plugin flat config migration guide (#17640) (Nicholas C. Zakas) +* [`a58aa20`](https://github.com/eslint/eslint/commit/a58aa200fccedae7e2e9b6129246f2cedab14f8d) docs: fix examples for several rules (#17645) (Milos Djermanovic) +* [`179929b`](https://github.com/eslint/eslint/commit/179929bd46892f18f2aef0c159d5cc361cb69987) docs: Remove trailing newline from the code of Playground links (#17641) (Francesco Trotta) +* [`f8e5c30`](https://github.com/eslint/eslint/commit/f8e5c30636450d4a8baf51f0e227685e6d77ac64) docs: Update README (GitHub Actions Bot) +* [`b7ef2f3`](https://github.com/eslint/eslint/commit/b7ef2f34fe12b68a366e1b4bf5f64d7332c6e72e) docs: Enable pretty code formatter output (#17635) (Nicholas C. Zakas) +* [`0bcb9a8`](https://github.com/eslint/eslint/commit/0bcb9a8db608a3d0bd2645f99e0707b9a9bbaaf0) docs: Fix syntax errors in rule examples (#17633) (Francesco Trotta) +* [`61b9083`](https://github.com/eslint/eslint/commit/61b90839633ef300ac7707a651f65f532e65f42d) docs: Make no-continue example code work (#17643) (Zhongyuan Zhou) +* [`9fafe45`](https://github.com/eslint/eslint/commit/9fafe450c31ed9b6bdd9dcd6c115255943b8c1c2) docs: upgrade to 11ty 2.0 (#17632) (Percy Ma) +* [`ff8e4bf`](https://github.com/eslint/eslint/commit/ff8e4bf327b5c92b0623b0fc5f8f101954f785db) docs: Update README (GitHub Actions Bot) +* [`fab249a`](https://github.com/eslint/eslint/commit/fab249ae6addac2ee18cd81cee80916010bb469e) docs: Update README (GitHub Actions Bot) +* [`392305b`](https://github.com/eslint/eslint/commit/392305bf4797e3ebc696dfca48bd874741fca845) docs: Update `no-irregular-whitespace` and fix examples (#17626) (Francesco Trotta) +* [`6b8acfb`](https://github.com/eslint/eslint/commit/6b8acfb770589f3941df41c3910d3b8ffc3e1e45) docs: Add real whitespace to `no-trailing-spaces` examples (#17630) (Francesco Trotta) +* [`1000187`](https://github.com/eslint/eslint/commit/1000187e00949332babcee4d37d46c96a6a554a8) docs: Fix examples in `unicode-bom` (#17631) (Francesco Trotta) +* [`000290c`](https://github.com/eslint/eslint/commit/000290c4c923cc1473e21b4bdbdc0c42765ef7dd) docs: Update README (GitHub Actions Bot) + v8.51.0 - October 6, 2023 * [`1ef39ea`](https://github.com/eslint/eslint/commit/1ef39ea5b884453be717ebc929155d7eb584dcbf) chore: upgrade @eslint/js@8.51.0 (#17624) (Milos Djermanovic) From 331cf62024b6c7ad4067c14c593f116576c3c861 Mon Sep 17 00:00:00 2001 From: ESLint Jenkins Date: Fri, 20 Oct 2023 17:00:04 -0400 Subject: [PATCH 24/24] 8.52.0 --- docs/package.json | 2 +- .../formatters/html-formatter-example.html | 2 +- docs/src/use/formatters/index.md | 757 +++++++++++++++++- package.json | 2 +- 4 files changed, 751 insertions(+), 12 deletions(-) diff --git a/docs/package.json b/docs/package.json index d24e203338c3..fa9d7101dd4a 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,7 +1,7 @@ { "name": "docs-eslint", "private": true, - "version": "8.51.0", + "version": "8.52.0", "description": "", "main": "index.js", "keywords": [], diff --git a/docs/src/use/formatters/html-formatter-example.html b/docs/src/use/formatters/html-formatter-example.html index 2981958fab76..05cbe6e08b39 100644 --- a/docs/src/use/formatters/html-formatter-example.html +++ b/docs/src/use/formatters/html-formatter-example.html @@ -118,7 +118,7 @@

ESLint Report

- 9 problems (5 errors, 4 warnings) - Generated on Fri Oct 06 2023 16:14:35 GMT-0400 (Eastern Daylight Time) + 9 problems (5 errors, 4 warnings) - Generated on Fri Oct 20 2023 17:00:05 GMT-0400 (Eastern Daylight Time)
diff --git a/docs/src/use/formatters/index.md b/docs/src/use/formatters/index.md index ec6ce537ed71..95a930aa3f36 100644 --- a/docs/src/use/formatters/index.md +++ b/docs/src/use/formatters/index.md @@ -71,7 +71,7 @@ Outputs results to the [Checkstyle](https://checkstyle.sourceforge.io/) format. Example output: -```text +```xml ``` @@ -109,7 +109,7 @@ Outputs results to format compatible with the [JSLint Jenkins plugin](https://pl Example output: -```text +```xml ``` @@ -119,10 +119,595 @@ Outputs JSON-serialized results. The `json-with-metadata` provides the same lint Alternatively, you can use the [ESLint Node.js API](../../integrate/nodejs-api) to programmatically use ESLint. -Example output: +Example output (formatted for easier reading): -```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 +{ + "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 @@ -131,10 +716,164 @@ Outputs JSON-serialized results. The `json` formatter is useful when you want to Alternatively, you can use the [ESLint Node.js API](../../integrate/nodejs-api) to programmatically use ESLint. -Example output: +Example output (formatted for easier reading): -```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};"}] +```json +[ + { + "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 @@ -143,7 +882,7 @@ Outputs results to format compatible with the [JUnit Jenkins plugin](https://plu Example output: -```text +```xml diff --git a/package.json b/package.json index 14f86b846cfc..45a42d1bf2c5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint", - "version": "8.51.0", + "version": "8.52.0", "author": "Nicholas C. Zakas ", "description": "An AST-based pattern checker for JavaScript.", "bin": {