diff --git a/.github/ISSUE_TEMPLATE/new-rule.yml b/.github/ISSUE_TEMPLATE/new-rule.yml index 9ef139fbb23..4c4463466ed 100644 --- a/.github/ISSUE_TEMPLATE/new-rule.yml +++ b/.github/ISSUE_TEMPLATE/new-rule.yml @@ -26,7 +26,6 @@ body: options: - Warns about a potential problem - Suggests an alternate way of doing something - - Enforces a formatting/stylistic preference validations: required: true - type: textarea diff --git a/.github/ISSUE_TEMPLATE/rule-change.yml b/.github/ISSUE_TEMPLATE/rule-change.yml index 86758cba555..2706a1180ca 100644 --- a/.github/ISSUE_TEMPLATE/rule-change.yml +++ b/.github/ISSUE_TEMPLATE/rule-change.yml @@ -15,7 +15,7 @@ body: required: true - type: dropdown attributes: - label: What change to do you want to make? + label: What change do you want to make? options: - Generate more warnings - Generate fewer warnings diff --git a/.github/renovate.json5 b/.github/renovate.json5 new file mode 100644 index 00000000000..8163f03867c --- /dev/null +++ b/.github/renovate.json5 @@ -0,0 +1,42 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended", + ":approveMajorUpdates", + ":semanticCommitScopeDisabled" + ], + "ignorePresets": [":semanticPrefixFixDepsChoreOthers"], + "labels": ["dependencies"], + + // Wait well over npm's three day window for any new package as a precaution against malicious publishes + // https://docs.npmjs.com/policies/unpublish/#packages-published-less-than-72-hours-ago + "minimumReleaseAge": "7 days", + + "packageRules": [ + { + "description": "Use the deps:actions label for github-action manager updates (this means Renovate's github-action manager).", + "addLabels": ["deps:actions"], + "matchManagers": ["github-actions"] + }, + { + "description": "Use the deps:npm label for npm manager packages (this means Renovate's npm manager).", + "addLabels": ["deps:npm"], + "matchManagers": ["npm"] + }, + { + "description": "Group Babel packages into a single PR.", + "groupName": "babel", + "matchPackagePrefixes": ["@babel", "babel-"] + }, + { + "description": "Group wdio packages into a single PR.", + "groupName": "wdio", + "matchPackagePrefixes": ["@wdio"] + }, + { + "description": "Group metascraper packages into a single PR.", + "groupName": "metascraper", + "matchPackagePrefixes": ["metascraper"] + } + ] +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c2ee74329c5..4dbe1532dff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,6 +33,8 @@ jobs: run: npm run lint:scss - name: Lint Docs JS Files run: node Makefile lintDocsJS + - name: Check Rule Examples + run: node Makefile checkRuleExamples - name: Build Docs Website working-directory: docs run: npm run build @@ -45,7 +47,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - node: [21.x, 20.x, 19.x, 18.x, 17.x, 16.x, 14.x, 12.x, "12.22.0"] + node: ["21.2.0", 20.x, 19.x, 18.x, 17.x, 16.x, 14.x, 12.x, "12.22.0"] include: - os: windows-latest node: "lts/*" diff --git a/CHANGELOG.md b/CHANGELOG.md index cb64e16b2c4..f8b0969f950 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,43 @@ +v8.55.0 - December 1, 2023 + +* [`eb8950c`](https://github.com/eslint/eslint/commit/eb8950c3b811c9163b9aae23af8b6266ad98b295) chore: upgrade @eslint/js@8.55.0 (#17811) (Milos Djermanovic) +* [`93df384`](https://github.com/eslint/eslint/commit/93df3849a7a25ebe0502000bf0bfb80a6613a5ae) chore: package.json update for @eslint/js release (Jenkins) +* [`fe4b954`](https://github.com/eslint/eslint/commit/fe4b9545a83e9aca7ba4bb77bc9c868d57de777f) chore: upgrade @eslint/eslintrc@2.1.4 (#17799) (Milos Djermanovic) +* [`8c9e6c1`](https://github.com/eslint/eslint/commit/8c9e6c100a6eb69da292463293b3b48cff911a01) feat: importNamePattern option in no-restricted-imports (#17721) (Tanuj Kanti) +* [`83ece2a`](https://github.com/eslint/eslint/commit/83ece2afc2dc6c49efe82678663fe4cba590c0e5) docs: fix typo `--rules` -> `--rule` (#17806) (OKURA Masafumi) +* [`bd8911d`](https://github.com/eslint/eslint/commit/bd8911db85c7a1127543c9212c8cea47a5cb687d) ci: pin Node.js 21.2.0 (#17809) (Milos Djermanovic) +* [`b29a16b`](https://github.com/eslint/eslint/commit/b29a16b22f234f6134475efb6c7be5ac946556ee) chore: fix several `cli` tests to run in the intended flat config mode (#17797) (Milos Djermanovic) +* [`fffca5c`](https://github.com/eslint/eslint/commit/fffca5c362bcd205dbf79d1bb52834f8a98fc6bd) docs: remove "Open in Playground" buttons for removed rules (#17791) (Francesco Trotta) +* [`a6d9442`](https://github.com/eslint/eslint/commit/a6d9442a9ab34d5d19f78d8c8fd0767a1237bfe3) docs: fix correct/incorrect examples of rules (#17789) (Tanuj Kanti) +* [`383e999`](https://github.com/eslint/eslint/commit/383e99928d7ce649ec9030c9856b03fbac0c3501) docs: update and fix examples for `no-unused-vars` (#17788) (Tanuj Kanti) +* [`5a8efd5`](https://github.com/eslint/eslint/commit/5a8efd5b7ad13eb320a1f468d1d4ab3c8ab99214) docs: add specific stylistic rule for each deprecated rule (#17778) (Etienne) +* [`de165c1`](https://github.com/eslint/eslint/commit/de165c108203c6703516ac651f5b4cac5b241804) chore: remove unused config-extends fixtures (#17781) (Milos Djermanovic) +* [`d4304b8`](https://github.com/eslint/eslint/commit/d4304b8b66eac870ffbf4840d84add8a123b25fc) chore: remove formatting/stylistic rules from new rule templates (#17780) (Francesco Trotta) +* [`21024fe`](https://github.com/eslint/eslint/commit/21024fe2029420b413bed11d23761c87e9a02a1a) chore: check rule examples for syntax errors (#17718) (Francesco Trotta) + +v8.54.0 - November 17, 2023 + +* [`d644de9`](https://github.com/eslint/eslint/commit/d644de9a4b593b565617303a095bc9aa69e7b768) chore: upgrade @eslint/js@8.54.0 (#17773) (Milos Djermanovic) +* [`1e6e314`](https://github.com/eslint/eslint/commit/1e6e31415cc429a3a9fc64b2ec03df0e0ec0c91b) chore: package.json update for @eslint/js release (Jenkins) +* [`98926e6`](https://github.com/eslint/eslint/commit/98926e6e7323e5dd12a9f016cb558144296665af) fix: Ensure that extra data is not accidentally stored in the cache file (#17760) (Milos Djermanovic) +* [`a7a883b`](https://github.com/eslint/eslint/commit/a7a883bd6ba4f140b60cbbb2be5b53d750f6c8db) feat: for-direction rule add check for condition in reverse order (#17755) (Angelo Annunziata) +* [`1452dc9`](https://github.com/eslint/eslint/commit/1452dc9f12c45c05d7c569f737221f0d988ecef1) feat: Add suggestions to no-console (#17680) (Joel Mathew Koshy) +* [`6fb8805`](https://github.com/eslint/eslint/commit/6fb8805310afe7476d6c404f172177a6d15fcf11) chore: Fixed grammar in issue_templates/rule_change (#17770) (Joel Mathew Koshy) +* [`becfdd3`](https://github.com/eslint/eslint/commit/becfdd39b25d795e56c9a13eb3e77af6b9c86e8a) docs: Make clear when rules are removed (#17728) (Nicholas C. Zakas) +* [`e8cf9f6`](https://github.com/eslint/eslint/commit/e8cf9f6a524332293f8b2c90a2db4a532e47d919) fix: Make dark scroll bar in dark theme (#17753) (Pavel) +* [`85db724`](https://github.com/eslint/eslint/commit/85db7243ddb8706ed60ab64a7ddf604d0d7de493) chore: upgrade `markdownlint` to 0.31.1 (#17754) (Nitin Kumar) +* [`21ebf8a`](https://github.com/eslint/eslint/commit/21ebf8a811be9f4b009cf70a10be5062d4fdc736) feat: update `no-array-constructor` rule (#17711) (Francesco Trotta) +* [`05d6e99`](https://github.com/eslint/eslint/commit/05d6e99153ed6d94eb30f46c57609371918a41f3) docs: update "Submit a Pull Request" page (#17712) (Francesco Trotta) +* [`eb2279e`](https://github.com/eslint/eslint/commit/eb2279e5148cee8fdea7dae614f4f8af7a2d06c3) docs: display info about deprecated rules (#17749) (Percy Ma) +* [`6d470d2`](https://github.com/eslint/eslint/commit/6d470d2e74535761bd56dcb1c021b463ef9e8a9c) chore: update dependency recast to ^0.23.0 (#17736) (renovate[bot]) +* [`b7121b5`](https://github.com/eslint/eslint/commit/b7121b590d578c9c9b38ee481313317f30e54817) chore: update dependency markdownlint-cli to ^0.37.0 (#17735) (renovate[bot]) +* [`633b9a1`](https://github.com/eslint/eslint/commit/633b9a19752b6a22ab4d6c824f27a75ac0e4151b) chore: update dependency regenerator-runtime to ^0.14.0 (#17739) (renovate[bot]) +* [`acac16f`](https://github.com/eslint/eslint/commit/acac16fdf8540f7ba86cf637e3c1b253bd35a268) chore: update dependency vite-plugin-commonjs to ^0.10.0 (#17740) (renovate[bot]) +* [`ba8ca7e`](https://github.com/eslint/eslint/commit/ba8ca7e3debcba68ee7015b9221cf5acd7870206) chore: add .github/renovate.json5 (#17567) (Josh Goldberg ✨) +* [`3cbeaad`](https://github.com/eslint/eslint/commit/3cbeaad7b943c153937ce34365cec2c406f2b98b) fix: Use `cwd` constructor option as config `basePath` in Linter (#17705) (Milos Djermanovic) +* [`d245326`](https://github.com/eslint/eslint/commit/d24532601e64714ac5d08507e05aa5c14ecd1d5a) docs: Correct working in migrating plugin docs (#17722) (Filip Tammergård) +* [`5454c22`](https://github.com/eslint/eslint/commit/5454c22b24f39be2dac7f28cfcfdb6c753faaf4e) Revert "chore: remove metascraper (#17707)" (#17708) (Milos Djermanovic) + v8.53.0 - November 3, 2023 * [`ba4d4d5`](https://github.com/eslint/eslint/commit/ba4d4d567a82554250dd8c7933322824e6a73944) chore: remove metascraper (#17707) (Milos Djermanovic) diff --git a/Makefile.js b/Makefile.js index 24accfb6103..692168ad7dc 100644 --- a/Makefile.js +++ b/Makefile.js @@ -16,7 +16,6 @@ const checker = require("npm-license"), glob = require("glob"), marked = require("marked"), matter = require("gray-matter"), - markdownlint = require("markdownlint"), os = require("os"), path = require("path"), semver = require("semver"), @@ -216,7 +215,9 @@ function generateRuleIndexPage() { if (rule.meta.deprecated) { ruleTypesData.deprecated.push({ name: basename, - replacedBy: rule.meta.replacedBy || [] + replacedBy: rule.meta.replacedBy || [], + fixable: !!rule.meta.fixable, + hasSuggestions: !!rule.meta.hasSuggestions }); } else { const output = { @@ -431,6 +432,7 @@ function getFirstVersionOfDeletion(filePath) { * @private */ function lintMarkdown(files) { + const markdownlint = require("markdownlint"); const config = yaml.load(fs.readFileSync(path.join(__dirname, "./.markdownlint.yml"), "utf8")), result = markdownlint.sync({ files, @@ -865,6 +867,17 @@ target.checkRuleFiles = function() { }; +target.checkRuleExamples = function() { + const { execFileSync } = require("child_process"); + + // We don't need the stack trace of execFileSync if the command fails. + try { + execFileSync(process.execPath, ["tools/check-rule-examples.js", "docs/src/rules/*.md"], { stdio: "inherit" }); + } catch { + exit(1); + } +}; + target.checkLicenses = function() { /** diff --git a/docs/.eleventy.js b/docs/.eleventy.js index 75a372d3d5e..01b9c96aaba 100644 --- a/docs/.eleventy.js +++ b/docs/.eleventy.js @@ -14,6 +14,8 @@ const { highlighter, lineNumberPlugin } = require("./src/_plugins/md-syntax-high const { DateTime } = require("luxon"); +const markdownIt = require("markdown-it"); +const markdownItRuleExample = require("./tools/markdown-it-rule-example"); module.exports = function(eleventyConfig) { @@ -113,7 +115,7 @@ module.exports = function(eleventyConfig) { * Source: https://github.com/11ty/eleventy/issues/658 */ eleventyConfig.addFilter("markdown", value => { - const markdown = require("markdown-it")({ + const markdown = markdownIt({ html: true }); @@ -191,57 +193,44 @@ module.exports = function(eleventyConfig) { return btoa(unescape(encodeURIComponent(text))); } - /** - * Creates markdownItContainer settings for a playground-linked codeblock. - * @param {string} name Plugin name and class name to add to the code block. - * @returns {[string, object]} Plugin name and options for markdown-it. - */ - function withPlaygroundRender(name) { - return [ - name, - { - render(tokens, index) { - if (tokens[index].nesting !== 1) { - return ""; - } - - // 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)) }; - - // 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 }, - text: content - }) - ); - const prefix = process.env.CONTEXT && process.env.CONTEXT !== "deploy-preview" - ? "" - : "https://eslint.org"; - - return ` -
+ // markdown-it plugin options for playground-linked code blocks in rule examples. + const ruleExampleOptions = markdownItRuleExample({ + open({ type, code, parserOptions, env }) { + const isRuleRemoved = !Object.prototype.hasOwnProperty.call(env.rules_meta, env.title); + + if (isRuleRemoved) { + return `
`; + } + + // See https://github.com/eslint/eslint.org/blob/ac38ab41f99b89a8798d374f74e2cce01171be8b/src/playground/App.js#L44 + const state = encodeToBase64( + JSON.stringify({ + options: { parserOptions }, + text: code + }) + ); + const prefix = process.env.CONTEXT && process.env.CONTEXT !== "deploy-preview" + ? "" + : "https://eslint.org"; + + return ` +
Open in Playground - `.trim(); - } - } - ]; - } + `.trim(); + }, + close() { + return "
"; + } + }); - const markdownIt = require("markdown-it"); const md = markdownIt({ html: true, linkify: true, typographer: true, highlight: (str, lang) => highlighter(md, str, lang) }) .use(markdownItAnchor, { slugify: s => slug(s) }) .use(markdownItContainer, "img-container", {}) - .use(markdownItContainer, ...withPlaygroundRender("correct")) - .use(markdownItContainer, ...withPlaygroundRender("incorrect")) + .use(markdownItContainer, "rule-example", ruleExampleOptions) .use(markdownItContainer, "warning", { render(tokens, idx) { return generateAlertMarkup("warning", tokens, idx); diff --git a/docs/package.json b/docs/package.json index 0619d4d5b8f..c79c756bf18 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,7 +1,7 @@ { "name": "docs-eslint", "private": true, - "version": "8.53.0", + "version": "8.55.0", "description": "", "main": "index.js", "keywords": [], diff --git a/docs/src/_data/rules.json b/docs/src/_data/rules.json index 33915152ad6..3fe9ddcc3d5 100644 --- a/docs/src/_data/rules.json +++ b/docs/src/_data/rules.json @@ -659,7 +659,7 @@ "description": "Disallow `Array` constructors", "recommended": false, "fixable": false, - "hasSuggestions": false + "hasSuggestions": true }, { "name": "no-bitwise", @@ -687,7 +687,7 @@ "description": "Disallow the use of `console`", "recommended": false, "fixable": false, - "hasSuggestions": false + "hasSuggestions": true }, { "name": "no-continue", @@ -1403,391 +1403,575 @@ "deprecated": [ { "name": "array-bracket-newline", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "array-bracket-spacing", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "array-element-newline", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "arrow-parens", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "arrow-spacing", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "block-spacing", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "brace-style", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "callback-return", - "replacedBy": [] + "replacedBy": [], + "fixable": false, + "hasSuggestions": false }, { "name": "comma-dangle", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "comma-spacing", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "comma-style", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "computed-property-spacing", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "dot-location", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "eol-last", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "func-call-spacing", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "function-call-argument-newline", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "function-paren-newline", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "generator-star-spacing", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "global-require", - "replacedBy": [] + "replacedBy": [], + "fixable": false, + "hasSuggestions": false }, { "name": "handle-callback-err", - "replacedBy": [] + "replacedBy": [], + "fixable": false, + "hasSuggestions": false }, { "name": "id-blacklist", "replacedBy": [ "id-denylist" - ] + ], + "fixable": false, + "hasSuggestions": false }, { "name": "implicit-arrow-linebreak", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "indent", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "indent-legacy", "replacedBy": [ "indent" - ] + ], + "fixable": true, + "hasSuggestions": false }, { "name": "jsx-quotes", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "key-spacing", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "keyword-spacing", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "linebreak-style", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "lines-around-comment", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "lines-around-directive", "replacedBy": [ "padding-line-between-statements" - ] + ], + "fixable": true, + "hasSuggestions": false }, { "name": "lines-between-class-members", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "max-len", - "replacedBy": [] + "replacedBy": [], + "fixable": false, + "hasSuggestions": false }, { "name": "max-statements-per-line", - "replacedBy": [] + "replacedBy": [], + "fixable": false, + "hasSuggestions": false }, { "name": "multiline-ternary", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "new-parens", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "newline-after-var", "replacedBy": [ "padding-line-between-statements" - ] + ], + "fixable": true, + "hasSuggestions": false }, { "name": "newline-before-return", "replacedBy": [ "padding-line-between-statements" - ] + ], + "fixable": true, + "hasSuggestions": false }, { "name": "newline-per-chained-call", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "no-buffer-constructor", - "replacedBy": [] + "replacedBy": [], + "fixable": false, + "hasSuggestions": false }, { "name": "no-catch-shadow", "replacedBy": [ "no-shadow" - ] + ], + "fixable": false, + "hasSuggestions": false }, { "name": "no-confusing-arrow", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "no-extra-parens", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "no-extra-semi", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "no-floating-decimal", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "no-mixed-operators", - "replacedBy": [] + "replacedBy": [], + "fixable": false, + "hasSuggestions": false }, { "name": "no-mixed-requires", - "replacedBy": [] + "replacedBy": [], + "fixable": false, + "hasSuggestions": false }, { "name": "no-mixed-spaces-and-tabs", - "replacedBy": [] + "replacedBy": [], + "fixable": false, + "hasSuggestions": false }, { "name": "no-multi-spaces", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "no-multiple-empty-lines", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "no-native-reassign", "replacedBy": [ "no-global-assign" - ] + ], + "fixable": false, + "hasSuggestions": false }, { "name": "no-negated-in-lhs", "replacedBy": [ "no-unsafe-negation" - ] + ], + "fixable": false, + "hasSuggestions": false }, { "name": "no-new-object", "replacedBy": [ "no-object-constructor" - ] + ], + "fixable": false, + "hasSuggestions": false }, { "name": "no-new-require", - "replacedBy": [] + "replacedBy": [], + "fixable": false, + "hasSuggestions": false }, { "name": "no-path-concat", - "replacedBy": [] + "replacedBy": [], + "fixable": false, + "hasSuggestions": false }, { "name": "no-process-env", - "replacedBy": [] + "replacedBy": [], + "fixable": false, + "hasSuggestions": false }, { "name": "no-process-exit", - "replacedBy": [] + "replacedBy": [], + "fixable": false, + "hasSuggestions": false }, { "name": "no-restricted-modules", - "replacedBy": [] + "replacedBy": [], + "fixable": false, + "hasSuggestions": false }, { "name": "no-return-await", - "replacedBy": [] + "replacedBy": [], + "fixable": false, + "hasSuggestions": true }, { "name": "no-spaced-func", "replacedBy": [ "func-call-spacing" - ] + ], + "fixable": true, + "hasSuggestions": false }, { "name": "no-sync", - "replacedBy": [] + "replacedBy": [], + "fixable": false, + "hasSuggestions": false }, { "name": "no-tabs", - "replacedBy": [] + "replacedBy": [], + "fixable": false, + "hasSuggestions": false }, { "name": "no-trailing-spaces", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "no-whitespace-before-property", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "nonblock-statement-body-position", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "object-curly-newline", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "object-curly-spacing", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "object-property-newline", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "one-var-declaration-per-line", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "operator-linebreak", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "padded-blocks", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "padding-line-between-statements", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "prefer-reflect", - "replacedBy": [] + "replacedBy": [], + "fixable": false, + "hasSuggestions": false }, { "name": "quote-props", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "quotes", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "require-jsdoc", - "replacedBy": [] + "replacedBy": [], + "fixable": false, + "hasSuggestions": false }, { "name": "rest-spread-spacing", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "semi", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "semi-spacing", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "semi-style", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "space-before-blocks", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "space-before-function-paren", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "space-in-parens", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "space-infix-ops", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "space-unary-ops", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "spaced-comment", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "switch-colon-spacing", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "template-curly-spacing", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "template-tag-spacing", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "valid-jsdoc", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "wrap-iife", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "wrap-regex", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false }, { "name": "yield-star-spacing", - "replacedBy": [] + "replacedBy": [], + "fixable": true, + "hasSuggestions": false } ], "removed": [ diff --git a/docs/src/_data/rules_meta.json b/docs/src/_data/rules_meta.json index a00b86c7066..06db19be509 100644 --- a/docs/src/_data/rules_meta.json +++ b/docs/src/_data/rules_meta.json @@ -758,7 +758,8 @@ "description": "Disallow `Array` constructors", "recommended": false, "url": "https://eslint.org/docs/latest/rules/no-array-constructor" - } + }, + "hasSuggestions": true }, "no-async-promise-executor": { "type": "problem", @@ -865,7 +866,8 @@ "description": "Disallow the use of `console`", "recommended": false, "url": "https://eslint.org/docs/latest/rules/no-console" - } + }, + "hasSuggestions": true }, "no-const-assign": { "type": "problem", diff --git a/docs/src/_includes/components/rule.macro.html b/docs/src/_includes/components/rule.macro.html index e4cf876d0d9..cd5d61b0386 100644 --- a/docs/src/_includes/components/rule.macro.html +++ b/docs/src/_includes/components/rule.macro.html @@ -26,22 +26,24 @@

{{ params.description }}

{%- endif -%}
+ {%- if params.removed == undefined -%}
Categories: - {%- if (params.deprecated) or (params.removed) -%} + {%- if params.deprecated -%}

{%- else -%} -

+

{%- endif -%} -

+

-

+

+ {%- endif -%} {%- endmacro -%} diff --git a/docs/src/assets/scss/docs.scss b/docs/src/assets/scss/docs.scss index a59742475da..e981d8cc6af 100644 --- a/docs/src/assets/scss/docs.scss +++ b/docs/src/assets/scss/docs.scss @@ -113,7 +113,8 @@ div.incorrect { offset-block-start: -22px; } - pre.line-numbers-mode { + // Add space to the bottom if there is a Playground button. + .c-btn.c-btn--playground ~ pre.line-numbers-mode { padding-bottom: 4.5rem; } } diff --git a/docs/src/assets/scss/tokens/themes.scss b/docs/src/assets/scss/tokens/themes.scss index de956b821ad..a8104a5b346 100644 --- a/docs/src/assets/scss/tokens/themes.scss +++ b/docs/src/assets/scss/tokens/themes.scss @@ -135,6 +135,8 @@ html[data-theme="light"] { } html[data-theme="dark"] { + color-scheme: dark; + --body-background-color: var(--color-neutral-900); --body-text-color: var(--color-neutral-300); --headings-color: #fff; diff --git a/docs/src/contribute/pull-requests.md b/docs/src/contribute/pull-requests.md index 44f2378d8dc..57811860375 100644 --- a/docs/src/contribute/pull-requests.md +++ b/docs/src/contribute/pull-requests.md @@ -63,7 +63,7 @@ Longer description here if necessary Fixes #1234 ``` -The first line of the commit message (the summary) must have a specific format. This format is checked by our build tools. +The first line of the commit message (the summary) must have a specific format. This format is checked by our build tools. Although the commit message is not checked directly, it will be used to generate the title of a pull request, which will be checked when the pull request is submitted. The `tag` is one of the following: @@ -91,8 +91,6 @@ fix: Semi rule incorrectly flagging extra semicolon chore: Upgrade Esprima to 1.2, switch to using comment attachment ``` -The commit message format is important because these messages are used to create a changelog for each release. The tag and issue number help to create more consistent and useful changelogs. - ### Step 3: Rebase onto upstream Before you send the pull request, be sure to rebase onto the upstream source. This ensures your code is running on the latest available code. @@ -116,8 +114,6 @@ If there are any failing tests, update your code until all tests pass. With your code ready to go, this is a good time to double-check your submission to make sure it follows our conventions. Here are the things to check: -* Make sure your commit is formatted correctly. -* The pull request must have a description. The description should explain what you did and how its effects can be seen. * The commit message is properly formatted. * The change introduces no functional regression. Be sure to run `npm test` to verify your changes before submitting a pull request. * Make separate pull requests for unrelated changes. Large pull requests with multiple unrelated changes may be closed without merging. @@ -145,27 +141,24 @@ Now you're ready to send the pull request. Go to your ESLint fork and then follo In order to submit code or documentation to an ESLint project, you’ll be asked to sign our CLA when you send your first pull request. (Read more about the Open JS Foundation CLA process at .) +The pull request title is autogenerated from the summary of the first commit, but it can be edited before the pull request is submitted. + +The description of a pull request should explain what you did and how its effects can be seen. + +When a pull request is merged, its commits will be squashed into one single commit. The first line of the squashed commit message will contain the title of the pull request and the pull request number. +The pull request title format is important because the titles are used to create a changelog for each release. The tag and the issue number help to create more consistent and useful changelogs. + ## Following Up Once your pull request is sent, it's time for the team to review it. As such, please make sure to: -1. Monitor the status of the Travis CI build for your pull request. If it fails, please investigate why. We cannot merge pull requests that fail Travis for any reason. +1. Monitor the status of the GitHub Actions CI build for your pull request. If it fails, please investigate why. We cannot merge pull requests that fail the CI build for any reason. 1. Respond to comments left on the pull request from team members. Remember, we want to help you land your code, so please be receptive to our feedback. 1. We may ask you to make changes, rebase, or squash your commits. -### Updating the Commit Message - -If your commit message is in the incorrect format, you'll be asked to update it. You can do so via: - -```shell -git commit --amend -``` - -This will open up your editor so you can make changes. After that, you'll need to do a forced push to your branch: +### Updating the Pull Request Title -```shell -git push origin issue1234 -f -``` +If your pull request title is in the incorrect format, you'll be asked to update it. You can do so via the GitHub user interface. ### Updating the Code diff --git a/docs/src/extend/plugin-migration-flat-config.md b/docs/src/extend/plugin-migration-flat-config.md index 6c277596fc4..135e039c305 100644 --- a/docs/src/extend/plugin-migration-flat-config.md +++ b/docs/src/extend/plugin-migration-flat-config.md @@ -199,7 +199,7 @@ export default [ ]; ``` -You should update our documentation so your plugin users know how to reference the exported configs. +You should update your documentation so your plugin users know how to reference the exported configs. ## Migrating Environments for Flat Config diff --git a/docs/src/library/link-card.md b/docs/src/library/link-card.md index db400f31d68..d21291b1a60 100644 --- a/docs/src/library/link-card.md +++ b/docs/src/library/link-card.md @@ -10,6 +10,7 @@ Links can be rendered as cards by using the `link` shortcode. The only required ## Examples + {% link "https://blog.izs.me/2010/12/an-open-letter-to-javascript-leaders-regarding/" %} - + {% link "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get" %} diff --git a/docs/src/pages/rules.md b/docs/src/pages/rules.md index 9d801cf5126..0b475b868fd 100644 --- a/docs/src/pages/rules.md +++ b/docs/src/pages/rules.md @@ -60,11 +60,19 @@ Rules in ESLint are grouped by type to help you understand their purpose. Each r {%- for the_rule in rules.deprecated -%} {%- set name_value = the_rule.name -%} {%- set isReplacedBy = the_rule.replacedBy -%} + {%- set isRecommended = the_rule.recommended -%} + {%- set isFixable = the_rule.fixable -%} + {%- set isHasSuggestions = the_rule.hasSuggestions -%} {{ rule({ name: name_value, deprecated: true, - replacedBy: isReplacedBy + replacedBy: isReplacedBy, + categories: { + recommended: isRecommended, + fixable: isFixable, + hasSuggestions: isHasSuggestions + } }) }} {%- endfor -%} {%- endif -%} diff --git a/docs/src/rules/array-bracket-newline.md b/docs/src/rules/array-bracket-newline.md index 2ccb13dddf9..900fea16fb0 100644 --- a/docs/src/rules/array-bracket-newline.md +++ b/docs/src/rules/array-bracket-newline.md @@ -5,7 +5,7 @@ related_rules: - array-bracket-spacing --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/array-bracket-newline) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). A number of style guides require or disallow line breaks inside of array brackets. diff --git a/docs/src/rules/array-bracket-spacing.md b/docs/src/rules/array-bracket-spacing.md index 0fdc8310747..53fa82cf562 100644 --- a/docs/src/rules/array-bracket-spacing.md +++ b/docs/src/rules/array-bracket-spacing.md @@ -7,7 +7,7 @@ related_rules: - computed-property-spacing --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/array-bracket-spacing) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). A number of style guides require or disallow spaces between array brackets and other tokens. This rule applies to both array literals and destructuring assignments (ECMAScript 6). diff --git a/docs/src/rules/array-element-newline.md b/docs/src/rules/array-element-newline.md index 0a8bc39b9bc..b3aa11bd2a2 100644 --- a/docs/src/rules/array-element-newline.md +++ b/docs/src/rules/array-element-newline.md @@ -12,7 +12,7 @@ related_rules: - brace-style --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/array-element-newline) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). A number of style guides require or disallow line breaks between array elements. diff --git a/docs/src/rules/arrow-parens.md b/docs/src/rules/arrow-parens.md index 4bfa819f87b..d84e1999db8 100644 --- a/docs/src/rules/arrow-parens.md +++ b/docs/src/rules/arrow-parens.md @@ -5,7 +5,7 @@ further_reading: - https://github.com/airbnb/javascript#arrows--one-arg-parens --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/arrow-parens) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Arrow functions can omit parentheses when they have exactly one parameter. In all other cases the parameter(s) must be wrapped in parentheses. This rule enforces the consistent use of parentheses in arrow functions. diff --git a/docs/src/rules/arrow-spacing.md b/docs/src/rules/arrow-spacing.md index 3975e9f82cd..c0e4c3e1e13 100644 --- a/docs/src/rules/arrow-spacing.md +++ b/docs/src/rules/arrow-spacing.md @@ -3,7 +3,7 @@ title: arrow-spacing rule_type: layout --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/arrow-spacing) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). This rule normalize style of spacing before/after an arrow function's arrow(`=>`). diff --git a/docs/src/rules/block-spacing.md b/docs/src/rules/block-spacing.md index 831916b55e7..02aec62a652 100644 --- a/docs/src/rules/block-spacing.md +++ b/docs/src/rules/block-spacing.md @@ -6,7 +6,7 @@ related_rules: - brace-style --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/block-spacing) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). ## Rule Details diff --git a/docs/src/rules/brace-style.md b/docs/src/rules/brace-style.md index 8fb982328a6..4d3932e3ca1 100644 --- a/docs/src/rules/brace-style.md +++ b/docs/src/rules/brace-style.md @@ -8,7 +8,7 @@ further_reading: - https://en.wikipedia.org/wiki/Indent_style --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/brace-style) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Brace style is closely related to [indent style](https://en.wikipedia.org/wiki/Indent_style) in programming and describes the placement of braces relative to their control statement and body. There are probably a dozen, if not more, brace styles in the world. diff --git a/docs/src/rules/capitalized-comments.md b/docs/src/rules/capitalized-comments.md index 66d03d779eb..d42fc201166 100644 --- a/docs/src/rules/capitalized-comments.md +++ b/docs/src/rules/capitalized-comments.md @@ -216,10 +216,12 @@ Examples of **correct** code with `ignoreConsecutiveComments` set to `true`: ```js /* eslint capitalized-comments: ["error", "always", { "ignoreConsecutiveComments": true }] */ +foo(); // This comment is valid since it has the correct capitalization. // this comment is ignored since it follows another comment, // and this one as well because it follows yet another comment. +bar(); /* Here is a block comment which has the correct capitalization, */ /* but this one is ignored due to being consecutive; */ /* @@ -236,6 +238,7 @@ Examples of **incorrect** code with `ignoreConsecutiveComments` set to `true`: ```js /* eslint capitalized-comments: ["error", "always", { "ignoreConsecutiveComments": true }] */ +foo(); // this comment is invalid, but only on this line. // this comment does NOT get reported, since it is a consecutive comment. ``` diff --git a/docs/src/rules/comma-dangle.md b/docs/src/rules/comma-dangle.md index 17685a08f3d..3b4e888a095 100644 --- a/docs/src/rules/comma-dangle.md +++ b/docs/src/rules/comma-dangle.md @@ -3,7 +3,7 @@ title: comma-dangle rule_type: layout --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/comma-dangle) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Trailing commas in object literals are valid according to the ECMAScript 5 (and ECMAScript 3!) spec. However, IE8 (when not in IE8 document mode) and below will throw an error when it encounters trailing commas in JavaScript. diff --git a/docs/src/rules/comma-spacing.md b/docs/src/rules/comma-spacing.md index e4d430997be..ffc85f27de3 100644 --- a/docs/src/rules/comma-spacing.md +++ b/docs/src/rules/comma-spacing.md @@ -16,7 +16,7 @@ further_reading: - https://dojotoolkit.org/reference-guide/1.9/developer/styleguide.html --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/comma-spacing) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Spacing around commas improves readability of a list of items. Although most of the style guidelines for languages prescribe adding a space after a comma and not before it, it is subjective to the preferences of a project. diff --git a/docs/src/rules/comma-style.md b/docs/src/rules/comma-style.md index 5859710ee89..ee24383761a 100644 --- a/docs/src/rules/comma-style.md +++ b/docs/src/rules/comma-style.md @@ -7,7 +7,7 @@ further_reading: - https://gist.github.com/isaacs/357981 --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/comma-style) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). The Comma Style rule enforces styles for comma-separated lists. There are two comma styles primarily used in JavaScript: diff --git a/docs/src/rules/computed-property-spacing.md b/docs/src/rules/computed-property-spacing.md index 424e97cce63..8e8b2d5abc0 100644 --- a/docs/src/rules/computed-property-spacing.md +++ b/docs/src/rules/computed-property-spacing.md @@ -7,7 +7,7 @@ related_rules: - space-in-parens --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/computed-property-spacing) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). While formatting preferences are very personal, a number of style guides require or disallow spaces between computed properties in the following situations: diff --git a/docs/src/rules/dot-location.md b/docs/src/rules/dot-location.md index 8abb47708f4..5abbd9cb010 100644 --- a/docs/src/rules/dot-location.md +++ b/docs/src/rules/dot-location.md @@ -6,7 +6,7 @@ related_rules: - dot-notation --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/dot-location) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). JavaScript allows you to place newlines before or after a dot in a member expression. diff --git a/docs/src/rules/dot-notation.md b/docs/src/rules/dot-notation.md index 7514a1fdad2..7aa8810516b 100644 --- a/docs/src/rules/dot-notation.md +++ b/docs/src/rules/dot-notation.md @@ -84,22 +84,27 @@ class C { For example, when preparing data to be sent to an external API, it is often required to use property names that include underscores. If the `camelcase` rule is in effect, these [snake case](https://en.wikipedia.org/wiki/Snake_case) properties would not be allowed. By providing an `allowPattern` to the `dot-notation` rule, these snake case properties can be accessed with bracket notation. -Examples of **correct** code for the sample `{ "allowPattern": "^[a-z]+(_[a-z]+)+$" }` option: +Examples of **incorrect** code for the sample `{ "allowPattern": "^[a-z]+(_[a-z]+)+$" }` (pattern to find snake case named properties) option: -:::correct +:::incorrect ```js -/*eslint camelcase: "error"*/ /*eslint dot-notation: ["error", { "allowPattern": "^[a-z]+(_[a-z]+)+$" }]*/ -var data = {}; -data.foo_bar = 42; - var data = {}; data["fooBar"] = 42; +``` + +::: +Examples of **correct** code for the sample `{ "allowPattern": "^[a-z]+(_[a-z]+)+$" }` (pattern to find snake case named properties) option: + +:::correct + +```js +/*eslint dot-notation: ["error", { "allowPattern": "^[a-z]+(_[a-z]+)+$" }]*/ var data = {}; -data["foo_bar"] = 42; // no warning +data["foo_bar"] = 42; ``` ::: diff --git a/docs/src/rules/eol-last.md b/docs/src/rules/eol-last.md index c4c0dc991f0..afcd150507e 100644 --- a/docs/src/rules/eol-last.md +++ b/docs/src/rules/eol-last.md @@ -3,7 +3,7 @@ title: eol-last rule_type: layout --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/eol-last) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Trailing newlines in non-empty files are a common UNIX idiom. Benefits of trailing newlines include the ability to concatenate or append to files as well diff --git a/docs/src/rules/for-direction.md b/docs/src/rules/for-direction.md index 45759eb48f9..aa09cb181e3 100644 --- a/docs/src/rules/for-direction.md +++ b/docs/src/rules/for-direction.md @@ -24,6 +24,9 @@ for (var i = 10; i >= 0; i++) { for (var i = 0; i > 10; i++) { } +for (var i = 0; 10 > i; i--) { +} + const n = -2; for (let i = 0; i < 10; i += n) { } @@ -40,6 +43,9 @@ Examples of **correct** code for this rule: for (var i = 0; i < 10; i++) { } +for (var i = 0; 10 > i; i++) { // with counter "i" on the right +} + for (let i = 10; i >= 0; i += this.step) { // direction unknown } diff --git a/docs/src/rules/func-call-spacing.md b/docs/src/rules/func-call-spacing.md index 2821630fdbf..16033ef7d5c 100644 --- a/docs/src/rules/func-call-spacing.md +++ b/docs/src/rules/func-call-spacing.md @@ -5,7 +5,7 @@ related_rules: - no-spaced-func --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/function-call-spacing) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). When calling a function, developers may insert optional whitespace between the function's name and the parentheses that invoke it. The following pairs of function calls are equivalent: diff --git a/docs/src/rules/function-call-argument-newline.md b/docs/src/rules/function-call-argument-newline.md index 73adf30c59f..9c20a28313e 100644 --- a/docs/src/rules/function-call-argument-newline.md +++ b/docs/src/rules/function-call-argument-newline.md @@ -8,7 +8,7 @@ related_rules: - array-element-newline --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/function-call-argument-newline) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). A number of style guides require or disallow line breaks between arguments of a function call. diff --git a/docs/src/rules/function-paren-newline.md b/docs/src/rules/function-paren-newline.md index 116737118e9..09d3ca973e1 100644 --- a/docs/src/rules/function-paren-newline.md +++ b/docs/src/rules/function-paren-newline.md @@ -3,7 +3,7 @@ title: function-paren-newline rule_type: layout --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/function-paren-newline) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Many style guides require or disallow newlines inside of function parentheses. diff --git a/docs/src/rules/generator-star-spacing.md b/docs/src/rules/generator-star-spacing.md index a8b3c6c9b17..2157da18fe8 100644 --- a/docs/src/rules/generator-star-spacing.md +++ b/docs/src/rules/generator-star-spacing.md @@ -5,7 +5,7 @@ further_reading: - https://leanpub.com/understandinges6/read/#leanpub-auto-generators --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/generator-star-spacing) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Generators are a new type of function in ECMAScript 6 that can return multiple values over time. These special functions are indicated by placing an `*` after the `function` keyword. diff --git a/docs/src/rules/generator-star.md b/docs/src/rules/generator-star.md index c2ddb18f05d..4a79edd1820 100644 --- a/docs/src/rules/generator-star.md +++ b/docs/src/rules/generator-star.md @@ -6,7 +6,9 @@ further_reading: Enforces consistent spacing around the asterisk in generator functions. -(removed) This rule was **removed** in ESLint v1.0 and **replaced** by the [generator-star-spacing](generator-star-spacing) rule. +::: important +This rule was removed in ESLint v1.0.0 and replaced by the [generator-star-spacing](generator-star-spacing) rule. +::: Generators are a new type of function in ECMAScript 6 that can return multiple values over time. These special functions are indicated by placing an `*` after the `function` keyword. diff --git a/docs/src/rules/global-strict.md b/docs/src/rules/global-strict.md index 80cbf9a0aa0..5f39d6461ac 100644 --- a/docs/src/rules/global-strict.md +++ b/docs/src/rules/global-strict.md @@ -5,7 +5,9 @@ title: global-strict Requires or disallows strict mode directives in the global scope. -(removed) This rule was **removed** in ESLint v1.0 and **replaced** by the [strict](strict) rule. The `"global"` option in the new rule is most similar to the removed rule. +::: important +This rule was removed in ESLint v1.0.0 and replaced by the [strict](strict) rule. The `"global"` option in the new rule is most similar to the removed rule. +::: Strict mode is enabled by using the following pragma in your code: diff --git a/docs/src/rules/implicit-arrow-linebreak.md b/docs/src/rules/implicit-arrow-linebreak.md index 25f5bc97d76..5914b9d440d 100644 --- a/docs/src/rules/implicit-arrow-linebreak.md +++ b/docs/src/rules/implicit-arrow-linebreak.md @@ -5,7 +5,7 @@ related_rules: - brace-style --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/implicit-arrow-linebreak) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). An arrow function body can contain an implicit return as an expression instead of a block body. It can be useful to enforce a consistent location for the implicitly returned expression. diff --git a/docs/src/rules/indent.md b/docs/src/rules/indent.md index 6cd25b73aec..768c1b18a4b 100644 --- a/docs/src/rules/indent.md +++ b/docs/src/rules/indent.md @@ -3,7 +3,7 @@ title: indent rule_type: layout --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/indent) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). There are several common guidelines which require specific indentation of nested blocks and statements, like: diff --git a/docs/src/rules/jsx-quotes.md b/docs/src/rules/jsx-quotes.md index b26450a9bc4..25ea1295dc6 100644 --- a/docs/src/rules/jsx-quotes.md +++ b/docs/src/rules/jsx-quotes.md @@ -5,7 +5,7 @@ related_rules: - quotes --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/jsx-quotes) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). JSX attribute values can contain string literals, which are delimited with single or double quotes. diff --git a/docs/src/rules/key-spacing.md b/docs/src/rules/key-spacing.md index 234b0de1b21..c572be1c53e 100644 --- a/docs/src/rules/key-spacing.md +++ b/docs/src/rules/key-spacing.md @@ -3,7 +3,7 @@ title: key-spacing rule_type: layout --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/key-spacing) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). This rule enforces spacing around the colon in object literal properties. It can verify each property individually, or it can ensure horizontal alignment of adjacent properties in an object literal. diff --git a/docs/src/rules/keyword-spacing.md b/docs/src/rules/keyword-spacing.md index 7510378dea0..cd4ab2e6007 100644 --- a/docs/src/rules/keyword-spacing.md +++ b/docs/src/rules/keyword-spacing.md @@ -3,7 +3,7 @@ title: keyword-spacing rule_type: layout --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/keyword-spacing) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Keywords are syntax elements of JavaScript, such as `try` and `if`. These keywords have special meaning to the language and so often appear in a different color in code editors. diff --git a/docs/src/rules/linebreak-style.md b/docs/src/rules/linebreak-style.md index c4a764c9deb..d4dd0f5cf27 100644 --- a/docs/src/rules/linebreak-style.md +++ b/docs/src/rules/linebreak-style.md @@ -3,7 +3,7 @@ title: linebreak-style rule_type: layout --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/linebreak-style) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). When developing with a lot of people all having different editors, VCS applications and operating systems it may occur that different line endings are written by either of the mentioned (might especially happen when using the windows and mac versions of SourceTree together). diff --git a/docs/src/rules/lines-around-comment.md b/docs/src/rules/lines-around-comment.md index 56ea775ef44..146224fa9af 100644 --- a/docs/src/rules/lines-around-comment.md +++ b/docs/src/rules/lines-around-comment.md @@ -6,7 +6,7 @@ related_rules: - spaced-comment --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/lines-around-comment) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Many style guides require empty lines before or after comments. The primary goal of these rules is to make the comments easier to read and improve readability of the code. diff --git a/docs/src/rules/lines-between-class-members.md b/docs/src/rules/lines-between-class-members.md index 9c9d7e0cbad..91134402289 100644 --- a/docs/src/rules/lines-between-class-members.md +++ b/docs/src/rules/lines-between-class-members.md @@ -6,7 +6,7 @@ related_rules: - padding-line-between-statements --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/lines-between-class-members) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). This rule improves readability by enforcing lines between class members. It will not check empty lines before the first member and after the last member, since that is already taken care of by padded-blocks. diff --git a/docs/src/rules/max-len.md b/docs/src/rules/max-len.md index 7f7a0d006c0..1d236013104 100644 --- a/docs/src/rules/max-len.md +++ b/docs/src/rules/max-len.md @@ -9,7 +9,7 @@ related_rules: - max-statements --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/max-len) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Very long lines of code in any language can be difficult to read. In order to aid in readability and maintainability many coders have developed a convention to limit lines of code to X number of characters (traditionally 80 characters). diff --git a/docs/src/rules/max-lines-per-function.md b/docs/src/rules/max-lines-per-function.md index 45b8a62720f..0bceb71a198 100644 --- a/docs/src/rules/max-lines-per-function.md +++ b/docs/src/rules/max-lines-per-function.md @@ -72,7 +72,7 @@ is equivalent to ### code -Examples of **incorrect** code for this rule with a max value of `2`: +Examples of **incorrect** code for this rule with a particular max value: ::: incorrect @@ -88,7 +88,7 @@ function foo() { ::: incorrect ```js -/*eslint max-lines-per-function: ["error", 2]*/ +/*eslint max-lines-per-function: ["error", 3]*/ function foo() { // a comment var x = 0; @@ -100,7 +100,7 @@ function foo() { ::: incorrect ```js -/*eslint max-lines-per-function: ["error", 2]*/ +/*eslint max-lines-per-function: ["error", 4]*/ function foo() { // a comment followed by a blank line @@ -110,7 +110,7 @@ function foo() { ::: -Examples of **correct** code for this rule with a max value of `3`: +Examples of **correct** code for this rule with a particular max value: ::: correct @@ -126,7 +126,7 @@ function foo() { ::: correct ```js -/*eslint max-lines-per-function: ["error", 3]*/ +/*eslint max-lines-per-function: ["error", 4]*/ function foo() { // a comment var x = 0; @@ -138,7 +138,7 @@ function foo() { ::: correct ```js -/*eslint max-lines-per-function: ["error", 3]*/ +/*eslint max-lines-per-function: ["error", 5]*/ function foo() { // a comment followed by a blank line diff --git a/docs/src/rules/max-statements-per-line.md b/docs/src/rules/max-statements-per-line.md index 1a579add6fb..d2c2e693ca5 100644 --- a/docs/src/rules/max-statements-per-line.md +++ b/docs/src/rules/max-statements-per-line.md @@ -11,7 +11,7 @@ related_rules: - max-statements --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/max-statements-per-line) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). A line of code containing too many statements can be difficult to read. Code is generally read from the top down, especially when scanning, so limiting the number of statements allowed on a single line can be very beneficial for readability and maintainability. diff --git a/docs/src/rules/multiline-ternary.md b/docs/src/rules/multiline-ternary.md index 12ed8e176b5..84c1a80039a 100644 --- a/docs/src/rules/multiline-ternary.md +++ b/docs/src/rules/multiline-ternary.md @@ -5,7 +5,7 @@ related_rules: - operator-linebreak --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/multiline-ternary) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). JavaScript allows operands of ternary expressions to be separated by newlines, which can improve the readability of your program. diff --git a/docs/src/rules/new-parens.md b/docs/src/rules/new-parens.md index 0f652c2eb34..781a430e5bf 100644 --- a/docs/src/rules/new-parens.md +++ b/docs/src/rules/new-parens.md @@ -3,7 +3,7 @@ title: new-parens rule_type: layout --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/new-parens) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). JavaScript allows the omission of parentheses when invoking a function via the `new` keyword and the constructor has no arguments. However, some coders believe that omitting the parentheses is inconsistent with the rest of the language and thus makes code less clear. diff --git a/docs/src/rules/newline-per-chained-call.md b/docs/src/rules/newline-per-chained-call.md index 34eddb31338..e74ac95e78d 100644 --- a/docs/src/rules/newline-per-chained-call.md +++ b/docs/src/rules/newline-per-chained-call.md @@ -3,7 +3,7 @@ title: newline-per-chained-call rule_type: layout --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/newline-per-chained-call) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Chained method calls on a single line without line breaks are harder to read, so some developers place a newline character after each method call in the chain to make it more readable and easy to maintain. diff --git a/docs/src/rules/no-array-constructor.md b/docs/src/rules/no-array-constructor.md index aa7c079baa2..eff97dee776 100644 --- a/docs/src/rules/no-array-constructor.md +++ b/docs/src/rules/no-array-constructor.md @@ -24,9 +24,13 @@ Examples of **incorrect** code for this rule: ```js /*eslint no-array-constructor: "error"*/ -Array(0, 1, 2) +Array(); -new Array(0, 1, 2) +Array(0, 1, 2); + +new Array(0, 1, 2); + +Array(...args); ``` ::: @@ -38,11 +42,13 @@ Examples of **correct** code for this rule: ```js /*eslint no-array-constructor: "error"*/ -Array(500) +Array(500); + +new Array(someOtherArray.length); -new Array(someOtherArray.length) +[0, 1, 2]; -[0, 1, 2] +const createArray = Array => new Array(); ``` ::: diff --git a/docs/src/rules/no-arrow-condition.md b/docs/src/rules/no-arrow-condition.md index 5882b3fb0de..c2a52a030fd 100644 --- a/docs/src/rules/no-arrow-condition.md +++ b/docs/src/rules/no-arrow-condition.md @@ -9,7 +9,9 @@ related_rules: Disallows arrow functions where test conditions are expected. -(removed) This rule was **removed** in ESLint v2.0 and **replaced** by a combination of the [no-confusing-arrow](no-confusing-arrow) and [no-constant-condition](no-constant-condition) rules. +::: important +This rule was removed in ESLint v2.0.0 and replaced by a combination of the [no-confusing-arrow](no-confusing-arrow) and [no-constant-condition](no-constant-condition) rules. +::: Arrow functions (`=>`) are similar in syntax to some comparison operators (`>`, `<`, `<=`, and `>=`). This rule warns against using the arrow function syntax in places where a condition is expected. Even if the arguments of the arrow function are wrapped with parens, this rule still warns about it. diff --git a/docs/src/rules/no-async-promise-executor.md b/docs/src/rules/no-async-promise-executor.md index 784c5ea5396..768f3459f25 100644 --- a/docs/src/rules/no-async-promise-executor.md +++ b/docs/src/rules/no-async-promise-executor.md @@ -33,6 +33,8 @@ Examples of **incorrect** code for this rule: ::: incorrect ```js +/*eslint no-async-promise-executor: "error"*/ + const foo = new Promise(async (resolve, reject) => { readFile('foo.txt', function(err, result) { if (err) { @@ -55,6 +57,8 @@ Examples of **correct** code for this rule: ::: correct ```js +/*eslint no-async-promise-executor: "error"*/ + const foo = new Promise((resolve, reject) => { readFile('foo.txt', function(err, result) { if (err) { diff --git a/docs/src/rules/no-comma-dangle.md b/docs/src/rules/no-comma-dangle.md index c1815bc5a0f..20c0b6866cd 100644 --- a/docs/src/rules/no-comma-dangle.md +++ b/docs/src/rules/no-comma-dangle.md @@ -5,7 +5,9 @@ title: no-comma-dangle Disallows trailing commas in object and array literals. -(removed) This rule was **removed** in ESLint v1.0 and **replaced** by the [comma-dangle](comma-dangle) rule. +::: important +This rule was removed in ESLint v1.0.0 and replaced by the [comma-dangle](comma-dangle) rule. +::: Trailing commas in object literals are valid according to the ECMAScript 5 (and ECMAScript 3!) spec, however IE8 (when not in IE8 document mode) and below will throw an error when it encounters trailing commas in JavaScript. diff --git a/docs/src/rules/no-confusing-arrow.md b/docs/src/rules/no-confusing-arrow.md index b51140aa75f..349984587b8 100644 --- a/docs/src/rules/no-confusing-arrow.md +++ b/docs/src/rules/no-confusing-arrow.md @@ -6,7 +6,7 @@ related_rules: - arrow-parens --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/no-confusing-arrow) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Arrow functions (`=>`) are similar in syntax to some comparison operators (`>`, `<`, `<=`, and `>=`). This rule warns against using the arrow function syntax in places where it could be confused with a comparison operator. diff --git a/docs/src/rules/no-else-return.md b/docs/src/rules/no-else-return.md index 79b4fe5fb01..379de922b32 100644 --- a/docs/src/rules/no-else-return.md +++ b/docs/src/rules/no-else-return.md @@ -28,7 +28,7 @@ This rule has an object option: * `allowElseIf: true` (default) allows `else if` blocks after a return * `allowElseIf: false` disallows `else if` blocks after a return -### `allowElseIf: true` +### allowElseIf: true Examples of **incorrect** code for this rule: @@ -137,7 +137,7 @@ function foo4() { ::: -### `allowElseIf: false` +### allowElseIf: false Examples of **incorrect** code for this rule: diff --git a/docs/src/rules/no-empty-class.md b/docs/src/rules/no-empty-class.md index 5a6760f7dac..b34bf5acdfc 100644 --- a/docs/src/rules/no-empty-class.md +++ b/docs/src/rules/no-empty-class.md @@ -5,7 +5,9 @@ title: no-empty-class Disallows empty character classes in regular expressions. -(removed) This rule was **removed** in ESLint v1.0 and **replaced** by the [no-empty-character-class](no-empty-character-class) rule. +::: important +This rule was removed in ESLint v1.0.0 and replaced by the [no-empty-character-class](no-empty-character-class) rule. +::: Empty character classes in regular expressions do not match anything and can result in code that may not work as intended. diff --git a/docs/src/rules/no-empty-label.md b/docs/src/rules/no-empty-label.md index 9fd7da473e3..4bce8ff7dcc 100644 --- a/docs/src/rules/no-empty-label.md +++ b/docs/src/rules/no-empty-label.md @@ -9,7 +9,9 @@ related_rules: Disallows labels for anything other than loops and switches. -(removed) This rule was **removed** in ESLint v2.0 and **replaced** by the [no-labels](no-labels) rule. +::: important +This rule was removed in ESLint v2.0.0 and replaced by the [no-labels](no-labels) rule. +::: Labeled statements are only used in conjunction with labeled break and continue statements. ECMAScript has no goto statement. diff --git a/docs/src/rules/no-eval.md b/docs/src/rules/no-eval.md index 662df5d3acd..64f7c78b3d6 100644 --- a/docs/src/rules/no-eval.md +++ b/docs/src/rules/no-eval.md @@ -104,6 +104,8 @@ class A { ## Options +### allowIndirect + This rule has an option to allow indirect calls to `eval`. Indirect calls to `eval` are less dangerous than direct calls to `eval` because they cannot dynamically change the scope. Because of this, they also will not negatively impact performance to the degree of direct `eval`. @@ -118,7 +120,7 @@ Example of **incorrect** code for this rule with the `{"allowIndirect": true}` o ::: incorrect ```js -/*eslint no-eval: "error"*/ +/*eslint no-eval: ["error", {"allowIndirect": true} ]*/ var obj = { x: "foo" }, key = "x", @@ -129,10 +131,10 @@ var obj = { x: "foo" }, Examples of **correct** code for this rule with the `{"allowIndirect": true}` option: -::: correct +::: correct { "sourceType": "script" } ```js -/*eslint no-eval: "error"*/ +/*eslint no-eval: ["error", {"allowIndirect": true} ]*/ (0, eval)("var a = 0"); @@ -147,7 +149,7 @@ this.eval("var a = 0"); ::: correct ```js -/*eslint no-eval: "error"*/ +/*eslint no-eval: ["error", {"allowIndirect": true} ]*/ /*eslint-env browser*/ window.eval("var a = 0"); @@ -158,7 +160,7 @@ window.eval("var a = 0"); ::: correct ```js -/*eslint no-eval: "error"*/ +/*eslint no-eval: ["error", {"allowIndirect": true} ]*/ /*eslint-env node*/ global.eval("var a = 0"); diff --git a/docs/src/rules/no-extra-parens.md b/docs/src/rules/no-extra-parens.md index ab5655b2b0a..a9b5a5ae518 100644 --- a/docs/src/rules/no-extra-parens.md +++ b/docs/src/rules/no-extra-parens.md @@ -9,7 +9,7 @@ further_reading: - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/no-extra-parens) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). This rule restricts the use of parentheses to only where they are necessary. diff --git a/docs/src/rules/no-extra-semi.md b/docs/src/rules/no-extra-semi.md index 1e9ee0a611f..3f28e45e7a2 100644 --- a/docs/src/rules/no-extra-semi.md +++ b/docs/src/rules/no-extra-semi.md @@ -6,7 +6,7 @@ related_rules: - semi-spacing --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/no-extra-semi) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Typing mistakes and misunderstandings about where semicolons are required can lead to semicolons that are unnecessary. While not technically an error, extra semicolons can cause confusion when reading code. diff --git a/docs/src/rules/no-extra-strict.md b/docs/src/rules/no-extra-strict.md index db0b8da4ff3..e98ddcd13e5 100644 --- a/docs/src/rules/no-extra-strict.md +++ b/docs/src/rules/no-extra-strict.md @@ -7,7 +7,9 @@ further_reading: Disallows strict mode directives when already in strict mode. -(removed) This rule was **removed** in ESLint v1.0 and **replaced** by the [strict](strict) rule. The `"global"` or `"function"` options in the new rule are similar to the removed rule. +::: important +This rule was removed in ESLint v1.0.0 and replaced by the [strict](strict) rule. The `"global"` or `"function"` options in the new rule are similar to the removed rule. +::: The `"use strict";` directive applies to the scope in which it appears and all inner scopes contained within that scope. Therefore, using the `"use strict";` directive in one of these inner scopes is unnecessary. diff --git a/docs/src/rules/no-floating-decimal.md b/docs/src/rules/no-floating-decimal.md index 8ba7a799150..e2f5e2755fc 100644 --- a/docs/src/rules/no-floating-decimal.md +++ b/docs/src/rules/no-floating-decimal.md @@ -3,7 +3,7 @@ title: no-floating-decimal rule_type: suggestion --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/no-floating-decimal) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Float values in JavaScript contain a decimal point, and there is no requirement that the decimal point be preceded or followed by a number. For example, the following are all valid JavaScript numbers: diff --git a/docs/src/rules/no-implicit-globals.md b/docs/src/rules/no-implicit-globals.md index 6a479a0a765..24ed498928d 100644 --- a/docs/src/rules/no-implicit-globals.md +++ b/docs/src/rules/no-implicit-globals.md @@ -79,7 +79,7 @@ window.bar = function() {}; Examples of **correct** code for this rule with `"parserOptions": { "sourceType": "module" }` in the ESLint configuration: -::: correct { "sourceType": "script" } +::: correct { "sourceType": "module" } ```js /*eslint no-implicit-globals: "error"*/ diff --git a/docs/src/rules/no-implied-eval.md b/docs/src/rules/no-implied-eval.md index 542e39a2cef..cfd067769cc 100644 --- a/docs/src/rules/no-implied-eval.md +++ b/docs/src/rules/no-implied-eval.md @@ -35,6 +35,7 @@ Examples of **incorrect** code for this rule: ```js /*eslint no-implied-eval: "error"*/ +/*eslint-env browser*/ setTimeout("alert('Hi!');", 100); diff --git a/docs/src/rules/no-loop-func.md b/docs/src/rules/no-loop-func.md index 659fd3e62da..8fed2d6d909 100644 --- a/docs/src/rules/no-loop-func.md +++ b/docs/src/rules/no-loop-func.md @@ -48,15 +48,21 @@ for (var i=10; i; i--) { (function() { return i; })(); } -while(i) { +var i = 0; +while(i < 5) { var a = function() { return i; }; a(); + + i++; } +var i = 0; do { function a() { return i; }; a(); -} while (i); + + i++ +} while (i < 5); let foo = 0; for (let i = 0; i < 10; ++i) { diff --git a/docs/src/rules/no-mixed-operators.md b/docs/src/rules/no-mixed-operators.md index d8bb908540b..d4a8a5d77c1 100644 --- a/docs/src/rules/no-mixed-operators.md +++ b/docs/src/rules/no-mixed-operators.md @@ -5,7 +5,7 @@ related_rules: - no-extra-parens --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/no-mixed-operators) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Enclosing complex expressions by parentheses clarifies the developer's intention, which makes the code more readable. This rule warns when different operators are used consecutively without parentheses in an expression. diff --git a/docs/src/rules/no-mixed-spaces-and-tabs.md b/docs/src/rules/no-mixed-spaces-and-tabs.md index b13223cf585..ee67a115159 100644 --- a/docs/src/rules/no-mixed-spaces-and-tabs.md +++ b/docs/src/rules/no-mixed-spaces-and-tabs.md @@ -5,7 +5,7 @@ further_reading: - https://www.emacswiki.org/emacs/SmartTabs --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/no-mixed-spaces-and-tabs) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Most code conventions require either tabs or spaces be used for indentation. As such, it's usually an error if a single line of code is indented with both tabs and spaces. diff --git a/docs/src/rules/no-multi-spaces.md b/docs/src/rules/no-multi-spaces.md index ca7e873ab0b..1cf99efe45f 100644 --- a/docs/src/rules/no-multi-spaces.md +++ b/docs/src/rules/no-multi-spaces.md @@ -11,7 +11,7 @@ related_rules: - space-return-throw-case --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/no-multi-spaces) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Multiple spaces in a row that are not used for indentation are typically mistakes. For example: diff --git a/docs/src/rules/no-multiple-empty-lines.md b/docs/src/rules/no-multiple-empty-lines.md index f6ccb3050e5..51724e60f51 100644 --- a/docs/src/rules/no-multiple-empty-lines.md +++ b/docs/src/rules/no-multiple-empty-lines.md @@ -3,7 +3,7 @@ title: no-multiple-empty-lines rule_type: layout --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/no-multiple-empty-lines) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Some developers prefer to have multiple blank lines removed, while others feel that it helps improve readability. Whitespace is useful for separating logical sections of code, but excess whitespace takes up more of the screen. diff --git a/docs/src/rules/no-redeclare.md b/docs/src/rules/no-redeclare.md index 009ba889fcc..e3ce497753e 100644 --- a/docs/src/rules/no-redeclare.md +++ b/docs/src/rules/no-redeclare.md @@ -77,7 +77,7 @@ The `"builtinGlobals"` option will check for redeclaration of built-in globals i Examples of **incorrect** code for the `{ "builtinGlobals": true }` option: -::: incorrect +::: incorrect { "sourceType": "script" } ```js /*eslint no-redeclare: ["error", { "builtinGlobals": true }]*/ @@ -89,7 +89,7 @@ var Object = 0; Examples of **incorrect** code for the `{ "builtinGlobals": true }` option and the `browser` environment: -::: incorrect +::: incorrect { "sourceType": "script" } ```js /*eslint no-redeclare: ["error", { "builtinGlobals": true }]*/ diff --git a/docs/src/rules/no-reserved-keys.md b/docs/src/rules/no-reserved-keys.md index bef6b376e1f..96f240e4cc6 100644 --- a/docs/src/rules/no-reserved-keys.md +++ b/docs/src/rules/no-reserved-keys.md @@ -7,7 +7,9 @@ further_reading: Disallows unquoted reserved words as property names in object literals. -(removed) This rule was **removed** in ESLint v1.0 and **replaced** by the [quote-props](quote-props) rule. +::: important +This rule was removed in ESLint v1.0.0 and replaced by the [quote-props](quote-props) rule. +::: ECMAScript 3 described as series of keywords and reserved words, such as `if` and `public`, that are used or intended to be used for a core language feature. The specification also indicated that these keywords and reserved words could not be used as object property names without being enclosed in strings. An error occurs in an ECMAScript 3 environment when you use a keyword or reserved word in an object literal. For example: diff --git a/docs/src/rules/no-restricted-imports.md b/docs/src/rules/no-restricted-imports.md index 72d97baf3e7..81f7ad4a6f9 100644 --- a/docs/src/rules/no-restricted-imports.md +++ b/docs/src/rules/no-restricted-imports.md @@ -118,6 +118,17 @@ Pattern matches can restrict specific import names only, similar to the `paths` }] ``` +Regex patterns can also be used to restrict specific import Name: + +```json +"no-restricted-imports": ["error", { + "patterns": [{ + "group": ["import-foo/*"], + "importNamePattern": "^foo", + }] +}] +``` + To restrict the use of all Node.js core imports (via ): ```json @@ -266,6 +277,48 @@ import { isEmpty } from 'utils/collection-utils'; ::: +::: incorrect { "sourceType": "module" } + +```js +/*eslint no-restricted-imports: ["error", { patterns: [{ + group: ["utils/*"], + importNamePattern: '^is', + message: "Use 'is*' functions from lodash instead." +}]}]*/ + +import { isEmpty } from 'utils/collection-utils'; +``` + +::: + +::: incorrect { "sourceType": "module" } + +```js +/*eslint no-restricted-imports: ["error", { patterns: [{ + group: ["foo/*"], + importNamePattern: '^(is|has)', + message: "Use 'is*' and 'has*' functions from baz/bar instead" +}]}]*/ + +import { isSomething, hasSomething } from 'foo/bar'; +``` + +::: + +::: incorrect { "sourceType": "module" } + +```js +/*eslint no-restricted-imports: ["error", { patterns: [{ + group: ["foo/*"], + importNames: ["bar"], + importNamePattern: '^baz', +}]}]*/ + +import { bar, bazQux } from 'foo/quux'; +``` + +::: + Examples of **correct** code for this rule: ::: correct { "sourceType": "module" } @@ -355,6 +408,20 @@ import { hasValues } from 'utils/collection-utils'; ::: +::: correct { "sourceType": "module" } + +```js +/*eslint no-restricted-imports: ["error", { patterns: [{ + group: ["utils/*"], + importNamePattern: '^is', + message: "Use 'is*' functions from lodash instead." +}]}]*/ + +import isEmpty, { hasValue } from 'utils/collection-utils'; +``` + +::: + ## When Not To Use It Don't use this rule or don't include a module in the list for this rule if you want to be able to import a module in your project without an ESLint error or warning. diff --git a/docs/src/rules/no-space-before-semi.md b/docs/src/rules/no-space-before-semi.md index 4c6650f0b2f..430c1688147 100644 --- a/docs/src/rules/no-space-before-semi.md +++ b/docs/src/rules/no-space-before-semi.md @@ -8,7 +8,9 @@ related_rules: Disallows spaces before semicolons. -(removed) This rule was **removed** in ESLint v1.0 and **replaced** by the [semi-spacing](semi-spacing) rule. +::: important +This rule was removed in ESLint v1.0.0 and replaced by the [semi-spacing](semi-spacing) rule. +::: JavaScript allows for placing unnecessary spaces between an expression and the closing semicolon. diff --git a/docs/src/rules/no-tabs.md b/docs/src/rules/no-tabs.md index fe999fa3c78..848ef34ebc3 100644 --- a/docs/src/rules/no-tabs.md +++ b/docs/src/rules/no-tabs.md @@ -3,7 +3,7 @@ title: no-tabs rule_type: layout --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/no-tabs) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Some style guides don't allow the use of tab characters at all, including within comments. diff --git a/docs/src/rules/no-trailing-spaces.md b/docs/src/rules/no-trailing-spaces.md index 71c50e41f44..17fb34dc790 100644 --- a/docs/src/rules/no-trailing-spaces.md +++ b/docs/src/rules/no-trailing-spaces.md @@ -3,7 +3,7 @@ title: no-trailing-spaces rule_type: layout --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/no-trailing-spaces) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Sometimes in the course of editing files, you can end up with extra whitespace at the end of lines. These whitespace differences can be picked up by source control systems and flagged as diffs, causing frustration for developers. While this extra whitespace causes no functional issues, many code conventions require that trailing spaces be removed before check-in. diff --git a/docs/src/rules/no-undef-init.md b/docs/src/rules/no-undef-init.md index f49ee8c7de4..f474562ca20 100644 --- a/docs/src/rules/no-undef-init.md +++ b/docs/src/rules/no-undef-init.md @@ -87,6 +87,8 @@ Example of **incorrect** code for this rule: ::: incorrect ```js +/*eslint no-undef-init: "error"*/ + for (i = 0; i < 10; i++) { var x = undefined; console.log(x); diff --git a/docs/src/rules/no-unmodified-loop-condition.md b/docs/src/rules/no-unmodified-loop-condition.md index 29932091697..86a8212d7d9 100644 --- a/docs/src/rules/no-unmodified-loop-condition.md +++ b/docs/src/rules/no-unmodified-loop-condition.md @@ -44,8 +44,8 @@ while (node) { } node = other; -for (var j = 0; j < items.length; ++i) { - doSomething(items[j]); +for (var j = 0; j < 5;) { + doSomething(j); } while (node !== root) { diff --git a/docs/src/rules/no-unused-expressions.md b/docs/src/rules/no-unused-expressions.md index 614ea5b11b7..52379726dce 100644 --- a/docs/src/rules/no-unused-expressions.md +++ b/docs/src/rules/no-unused-expressions.md @@ -79,7 +79,7 @@ Examples of **correct** code for the default `{ "allowShortCircuit": false, "all {} // In this context, this is a block statement, not an object literal -{myLabel: someVar} // In this context, this is a block statement with a label and expression, not an object literal +{ myLabel: foo() } // In this context, this is a block statement with a label and expression, not an object literal function namedFunctionDeclaration () {} diff --git a/docs/src/rules/no-unused-vars.md b/docs/src/rules/no-unused-vars.md index 1b3e59ce93b..f88b1ccb307 100644 --- a/docs/src/rules/no-unused-vars.md +++ b/docs/src/rules/no-unused-vars.md @@ -56,6 +56,7 @@ function fact(n) { function getY([x, y]) { return y; } +getY(["a", "b"]); ``` ::: @@ -89,6 +90,7 @@ myFunc = setTimeout(function() { function getY([, y]) { return y; } +getY(["a", "b"]); ``` ::: @@ -105,11 +107,18 @@ Note that `/* exported */` has no effect for any of the following: The line comment `// exported variableName` will not work as `exported` is not line-specific. -Examples of **correct** code for `/* exported variableName */` operation: +```js +/* exported global_var */ -::: correct +var global_var = 42; +``` + +Examples of **correct** code for `/* exported variableName */` operation with `no-unused-vars`: + +::: correct { "sourceType": "script" } ```js +/*eslint no-unused-vars: "error"*/ /* exported global_var */ var global_var = 42; @@ -386,11 +395,15 @@ Examples of **correct** code for the `{ "ignoreRestSiblings": true }` option: ```js /*eslint no-unused-vars: ["error", { "ignoreRestSiblings": true }]*/ + // 'foo' and 'bar' were ignored because they have a rest property sibling. -var { foo, ...coords } = data; +var { foo, ...rest } = data; +console.log(rest); + +// OR var bar; -({ bar, ...coords } = data); +({ bar, ...rest } = data); ``` ::: diff --git a/docs/src/rules/no-whitespace-before-property.md b/docs/src/rules/no-whitespace-before-property.md index a00864d491c..ddab906cf83 100644 --- a/docs/src/rules/no-whitespace-before-property.md +++ b/docs/src/rules/no-whitespace-before-property.md @@ -3,7 +3,7 @@ title: no-whitespace-before-property rule_type: layout --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/no-whitespace-before-property) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). JavaScript allows whitespace between objects and their properties. However, inconsistent spacing can make code harder to read and can lead to errors. diff --git a/docs/src/rules/no-wrap-func.md b/docs/src/rules/no-wrap-func.md index b0b64be8d14..abb078a372e 100644 --- a/docs/src/rules/no-wrap-func.md +++ b/docs/src/rules/no-wrap-func.md @@ -5,7 +5,9 @@ title: no-wrap-func Disallows unnecessary parentheses around function expressions. -(removed) This rule was **removed** in ESLint v1.0 and **replaced** by the [no-extra-parens](no-extra-parens) rule. The `"functions"` option in the new rule is equivalent to the removed rule. +::: important +This rule was removed in ESLint v1.0.0 and replaced by the [no-extra-parens](no-extra-parens) rule. The `"functions"` option in the new rule is equivalent to the removed rule. +::: Although it's possible to wrap functions in parentheses, this can be confusing when the code also contains immediately-invoked function expressions (IIFEs) since parentheses are often used to make this distinction. For example: diff --git a/docs/src/rules/nonblock-statement-body-position.md b/docs/src/rules/nonblock-statement-body-position.md index 1a2aae9122f..dee56c7b0a4 100644 --- a/docs/src/rules/nonblock-statement-body-position.md +++ b/docs/src/rules/nonblock-statement-body-position.md @@ -5,7 +5,7 @@ further_reading: - https://jscs-dev.github.io/rule/requireNewlineBeforeSingleStatementsInIf --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/nonblock-statement-body-position) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). When writing `if`, `else`, `while`, `do-while`, and `for` statements, the body can be a single statement instead of a block. It can be useful to enforce a consistent location for these single statements. diff --git a/docs/src/rules/object-curly-newline.md b/docs/src/rules/object-curly-newline.md index d33dd6433e8..fd990920c69 100644 --- a/docs/src/rules/object-curly-newline.md +++ b/docs/src/rules/object-curly-newline.md @@ -8,7 +8,7 @@ related_rules: - object-property-newline --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/object-curly-newline) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). A number of style guides require or disallow line breaks inside of object braces and other tokens. diff --git a/docs/src/rules/object-curly-spacing.md b/docs/src/rules/object-curly-spacing.md index 0484c436a4b..7288b63e229 100644 --- a/docs/src/rules/object-curly-spacing.md +++ b/docs/src/rules/object-curly-spacing.md @@ -8,7 +8,7 @@ related_rules: - space-in-parens --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/object-curly-spacing) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). While formatting preferences are very personal, a number of style guides require or disallow spaces between curly braces in the following situations: diff --git a/docs/src/rules/object-property-newline.md b/docs/src/rules/object-property-newline.md index e2bb161ea58..fde531a3c78 100644 --- a/docs/src/rules/object-property-newline.md +++ b/docs/src/rules/object-property-newline.md @@ -8,7 +8,7 @@ related_rules: - object-curly-spacing --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/object-property-newline) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). This rule permits you to restrict the locations of property specifications in object literals. You may prohibit any part of any property specification from appearing on the same line as any part of any other property specification. You may make this prohibition absolute, or, by invoking an object option, you may allow an exception, permitting an object literal to have all parts of all of its property specifications on a single line. diff --git a/docs/src/rules/object-shorthand.md b/docs/src/rules/object-shorthand.md index d694b57b029..299d46b9664 100644 --- a/docs/src/rules/object-shorthand.md +++ b/docs/src/rules/object-shorthand.md @@ -116,7 +116,7 @@ Additionally, the rule takes an optional object configuration: * `"methodsIgnorePattern"` (`string`) for methods whose names match this regex pattern, the method shorthand will not be enforced. Note that this option can only be used when the string option is set to `"always"` or `"methods"`. * `"avoidExplicitReturnArrows": true` indicates that methods are preferred over explicit-return arrow functions for function properties. (By default, the rule allows either of these.) Note that this option can only be enabled when the string option is set to `"always"` or `"methods"`. -### `avoidQuotes` +### avoidQuotes ```json { @@ -155,7 +155,7 @@ var foo = { ::: -### `ignoreConstructors` +### ignoreConstructors ```json { @@ -178,7 +178,7 @@ var foo = { ::: -### `methodsIgnorePattern` +### methodsIgnorePattern Example of **correct** code for this rule with the `"always", { "methodsIgnorePattern": "^bar$" }` option: @@ -194,7 +194,7 @@ var foo = { ::: -### `avoidExplicitReturnArrows` +### avoidExplicitReturnArrows ```json { diff --git a/docs/src/rules/one-var-declaration-per-line.md b/docs/src/rules/one-var-declaration-per-line.md index 742f52352fb..8f06275780f 100644 --- a/docs/src/rules/one-var-declaration-per-line.md +++ b/docs/src/rules/one-var-declaration-per-line.md @@ -5,7 +5,7 @@ related_rules: - one-var --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/one-var-declaration-per-line) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Some developers declare multiple var statements on the same line: diff --git a/docs/src/rules/one-var.md b/docs/src/rules/one-var.md index cb3bc09b955..0066757e1da 100644 --- a/docs/src/rules/one-var.md +++ b/docs/src/rules/one-var.md @@ -462,6 +462,9 @@ var bar = "bar"; ::: correct ```js +/*eslint one-var: ["error", { separateRequires: true, var: "always" }]*/ +/*eslint-env node*/ + var foo = require("foo"), bar = require("bar"); ``` diff --git a/docs/src/rules/operator-linebreak.md b/docs/src/rules/operator-linebreak.md index 0724797f3ee..8b2dacf1edb 100644 --- a/docs/src/rules/operator-linebreak.md +++ b/docs/src/rules/operator-linebreak.md @@ -5,7 +5,7 @@ related_rules: - comma-style --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/operator-linebreak) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). When a statement is too long to fit on a single line, line breaks are generally inserted next to the operators separating expressions. The first style coming to mind would be to place the operator at the end of the line, following the English punctuation rules. diff --git a/docs/src/rules/padded-blocks.md b/docs/src/rules/padded-blocks.md index 7d1a32042af..8d312920205 100644 --- a/docs/src/rules/padded-blocks.md +++ b/docs/src/rules/padded-blocks.md @@ -6,7 +6,7 @@ related_rules: - padding-line-between-statements --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/padded-blocks) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Some style guides require block statements to start and end with blank lines. The goal is to improve readability by visually separating the block content and the surrounding code. diff --git a/docs/src/rules/padding-line-between-statements.md b/docs/src/rules/padding-line-between-statements.md index af57ed48990..1311416fd08 100644 --- a/docs/src/rules/padding-line-between-statements.md +++ b/docs/src/rules/padding-line-between-statements.md @@ -3,7 +3,7 @@ title: padding-line-between-statements rule_type: layout --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/padding-line-between-statements) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). This rule requires or disallows blank lines between the given 2 kinds of statements. Properly blank lines help developers to understand the code. diff --git a/docs/src/rules/prefer-destructuring.md b/docs/src/rules/prefer-destructuring.md index 34b30c8de32..4a313922ed3 100644 --- a/docs/src/rules/prefer-destructuring.md +++ b/docs/src/rules/prefer-destructuring.md @@ -7,7 +7,7 @@ further_reading: --- - + With JavaScript ES6, a new syntax was added for creating variables from an array index or object property, called [destructuring](#further-reading). This rule enforces usage of destructuring instead of accessing a property through a member expression. ## Rule Details diff --git a/docs/src/rules/prefer-regex-literals.md b/docs/src/rules/prefer-regex-literals.md index 2159c977104..8468044c6be 100644 --- a/docs/src/rules/prefer-regex-literals.md +++ b/docs/src/rules/prefer-regex-literals.md @@ -110,12 +110,14 @@ This rule has an object option: * `disallowRedundantWrapping` set to `true` additionally checks for unnecessarily wrapped regex literals (Default `false`). -### `disallowRedundantWrapping` +### disallowRedundantWrapping By default, this rule doesn’t check when a regex literal is unnecessarily wrapped in a `RegExp` constructor call. When the option `disallowRedundantWrapping` is set to `true`, the rule will also disallow such unnecessary patterns. Examples of `incorrect` code for `{ "disallowRedundantWrapping": true }` +::: incorrect + ```js /*eslint prefer-regex-literals: ["error", {"disallowRedundantWrapping": true}]*/ @@ -124,8 +126,12 @@ new RegExp(/abc/); new RegExp(/abc/, 'u'); ``` +::: + Examples of `correct` code for `{ "disallowRedundantWrapping": true }` +::: correct + ```js /*eslint prefer-regex-literals: ["error", {"disallowRedundantWrapping": true}]*/ @@ -135,3 +141,5 @@ Examples of `correct` code for `{ "disallowRedundantWrapping": true }` new RegExp(/abc/, flags); ``` + +::: diff --git a/docs/src/rules/quote-props.md b/docs/src/rules/quote-props.md index 2e204dd0cb6..8a22c1a3868 100644 --- a/docs/src/rules/quote-props.md +++ b/docs/src/rules/quote-props.md @@ -6,7 +6,7 @@ further_reading: - https://mathiasbynens.be/notes/javascript-properties --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/quote-props) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Object literal property names can be defined in two ways: using literals or using strings. For example, these two objects are equivalent: diff --git a/docs/src/rules/quotes.md b/docs/src/rules/quotes.md index ea935d610a1..27dede284d6 100644 --- a/docs/src/rules/quotes.md +++ b/docs/src/rules/quotes.md @@ -3,7 +3,7 @@ title: quotes rule_type: layout --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/quotes) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). JavaScript allows you to define strings in one of three ways: double quotes, single quotes, and backticks (as of ECMAScript 6). For example: diff --git a/docs/src/rules/rest-spread-spacing.md b/docs/src/rules/rest-spread-spacing.md index 8a52856cad9..13b0e3704c8 100644 --- a/docs/src/rules/rest-spread-spacing.md +++ b/docs/src/rules/rest-spread-spacing.md @@ -5,7 +5,7 @@ further_reading: - https://github.com/tc39/proposal-object-rest-spread --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/rest-spread-spacing) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). ES2015 introduced the rest and spread operators, which expand an iterable structure into its individual parts. Some examples of their usage are as follows: diff --git a/docs/src/rules/semi-spacing.md b/docs/src/rules/semi-spacing.md index 5a27040f9b5..2c00517bfa3 100644 --- a/docs/src/rules/semi-spacing.md +++ b/docs/src/rules/semi-spacing.md @@ -9,7 +9,7 @@ related_rules: - space-in-parens --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/semi-spacing) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). JavaScript allows you to place unnecessary spaces before or after a semicolon. diff --git a/docs/src/rules/semi-style.md b/docs/src/rules/semi-style.md index 2979c188564..483ee44edae 100644 --- a/docs/src/rules/semi-style.md +++ b/docs/src/rules/semi-style.md @@ -7,7 +7,7 @@ related_rules: - semi-spacing --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/semi-style) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Generally, semicolons are at the end of lines. However, in semicolon-less style, semicolons are at the beginning of lines. This rule enforces that semicolons are at the configured location. diff --git a/docs/src/rules/semi.md b/docs/src/rules/semi.md index e118b4518f8..8a58ad76468 100644 --- a/docs/src/rules/semi.md +++ b/docs/src/rules/semi.md @@ -10,7 +10,7 @@ further_reading: - https://web.archive.org/web/20200420230322/http://inimino.org/~inimino/blog/javascript_semicolons --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/semi) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). JavaScript doesn't require semicolons at the end of each statement. In many cases, the JavaScript engine can determine that a semicolon should be in a certain spot and will automatically add it. This feature is known as **automatic semicolon insertion (ASI)** and is considered one of the more controversial features of JavaScript. For example, the following lines are both valid: diff --git a/docs/src/rules/space-after-function-name.md b/docs/src/rules/space-after-function-name.md index 65809c2c055..6607c3fd856 100644 --- a/docs/src/rules/space-after-function-name.md +++ b/docs/src/rules/space-after-function-name.md @@ -5,7 +5,9 @@ title: space-after-function-name Enforces consistent spacing after name in function definitions. -(removed) This rule was **removed** in ESLint v1.0 and **replaced** by the [space-before-function-paren](space-before-function-paren) rule. +::: important +This rule was removed in ESLint v1.0.0 and replaced by the [space-before-function-paren](space-before-function-paren) rule. +::: Whitespace between a function name and its parameter list is optional. diff --git a/docs/src/rules/space-after-keywords.md b/docs/src/rules/space-after-keywords.md index 7f5d63d9986..a554ca40437 100644 --- a/docs/src/rules/space-after-keywords.md +++ b/docs/src/rules/space-after-keywords.md @@ -5,9 +5,9 @@ title: space-after-keywords Enforces consistent spacing after keywords. -(removed) This rule was **removed** in ESLint v2.0 and replaced by the [keyword-spacing](keyword-spacing) rule. - -(fixable) The `--fix` option on the [command line](../use/command-line-interface#--fix) automatically fixed problems reported by this rule. +:::important +This rule was removed in ESLint v2.0.0 and replaced by the [keyword-spacing](keyword-spacing) rule. +::: Some style guides will require or disallow spaces following the certain keywords. diff --git a/docs/src/rules/space-before-blocks.md b/docs/src/rules/space-before-blocks.md index 42f02f99ebf..61c60eb51ad 100644 --- a/docs/src/rules/space-before-blocks.md +++ b/docs/src/rules/space-before-blocks.md @@ -9,7 +9,7 @@ related_rules: - brace-style --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/space-before-blocks) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Consistency is an important part of any style guide. While it is a personal preference where to put the opening brace of blocks, diff --git a/docs/src/rules/space-before-function-paren.md b/docs/src/rules/space-before-function-paren.md index 8b439dac5f1..1736ff44ef1 100644 --- a/docs/src/rules/space-before-function-paren.md +++ b/docs/src/rules/space-before-function-paren.md @@ -5,7 +5,7 @@ related_rules: - keyword-spacing --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/space-before-function-paren) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). When formatting a function, whitespace is allowed between the function name or `function` keyword and the opening paren. Named functions also require a space between the `function` keyword and the function name, but anonymous functions require no whitespace. For example: diff --git a/docs/src/rules/space-before-function-parentheses.md b/docs/src/rules/space-before-function-parentheses.md index 0b6b9b60d61..4d3e84fb139 100644 --- a/docs/src/rules/space-before-function-parentheses.md +++ b/docs/src/rules/space-before-function-parentheses.md @@ -8,7 +8,9 @@ related_rules: Enforces consistent spacing before opening parenthesis in function definitions. -(removed) This rule was **removed** in ESLint v1.0 and **replaced** by the [space-before-function-paren](space-before-function-paren) rule. The name of the rule changed from "parentheses" to "paren" for consistency with the names of other rules. +::: important +This rule was removed in ESLint v1.0.0 and replaced by the [space-before-function-paren](space-before-function-paren) rule. The name of the rule changed from "parentheses" to "paren" for consistency with the names of other rules. +::: When formatting a function, whitespace is allowed between the function name or `function` keyword and the opening paren. Named functions also require a space between the `function` keyword and the function name, but anonymous functions require no whitespace. For example: diff --git a/docs/src/rules/space-before-keywords.md b/docs/src/rules/space-before-keywords.md index 5eaa76db768..b49fe4b8c36 100644 --- a/docs/src/rules/space-before-keywords.md +++ b/docs/src/rules/space-before-keywords.md @@ -11,7 +11,9 @@ related_rules: Enforces consistent spacing before keywords. -(removed) This rule was **removed** in ESLint v2.0 and **replaced** by the [keyword-spacing](keyword-spacing) rule. +::: important +This rule was removed in ESLint v2.0.0 and replaced by the [keyword-spacing](keyword-spacing) rule. +::: (fixable) The `--fix` option on the [command line](../use/command-line-interface#--fix) automatically fixed problems reported by this rule. diff --git a/docs/src/rules/space-in-brackets.md b/docs/src/rules/space-in-brackets.md index d07023dc9ae..05b9ed88103 100644 --- a/docs/src/rules/space-in-brackets.md +++ b/docs/src/rules/space-in-brackets.md @@ -10,7 +10,9 @@ related_rules: Enforces consistent spacing inside braces of object literals and brackets of array literals. -(removed) This rule was **removed** in ESLint v1.0 and **replaced** by the [object-curly-spacing](object-curly-spacing) and [array-bracket-spacing](array-bracket-spacing) rules. +::: important +This rule was removed in ESLint v1.0.0 and replaced by the [object-curly-spacing](object-curly-spacing) and [array-bracket-spacing](array-bracket-spacing) rules. +::: While formatting preferences are very personal, a number of style guides require or disallow spaces between brackets: diff --git a/docs/src/rules/space-in-parens.md b/docs/src/rules/space-in-parens.md index 9f92cdc524a..16d0104fbd9 100644 --- a/docs/src/rules/space-in-parens.md +++ b/docs/src/rules/space-in-parens.md @@ -7,7 +7,7 @@ related_rules: - computed-property-spacing --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/space-in-parens) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Some style guides require or disallow spaces inside of parentheses: diff --git a/docs/src/rules/space-infix-ops.md b/docs/src/rules/space-infix-ops.md index 8a8c0c3dff7..821a6e276c0 100644 --- a/docs/src/rules/space-infix-ops.md +++ b/docs/src/rules/space-infix-ops.md @@ -3,7 +3,7 @@ title: space-infix-ops rule_type: layout --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/space-infix-ops) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). While formatting preferences are very personal, a number of style guides require spaces around operators, such as: diff --git a/docs/src/rules/space-return-throw-case.md b/docs/src/rules/space-return-throw-case.md index 8a9242280ab..3f6865d5a27 100644 --- a/docs/src/rules/space-return-throw-case.md +++ b/docs/src/rules/space-return-throw-case.md @@ -5,7 +5,9 @@ title: space-return-throw-case Requires spaces after `return`, `throw`, and `case` keywords. -(removed) This rule was **removed** in ESLint v2.0 and **replaced** by the [keyword-spacing](keyword-spacing) rule. +::: important +This rule was removed in ESLint v2.0.0 and replaced by the [keyword-spacing](keyword-spacing) rule. +::: (fixable) The `--fix` option on the [command line](../use/command-line-interface#--fix) automatically fixed problems reported by this rule. diff --git a/docs/src/rules/space-unary-ops.md b/docs/src/rules/space-unary-ops.md index 4e7f79bfce9..8379cfb7219 100644 --- a/docs/src/rules/space-unary-ops.md +++ b/docs/src/rules/space-unary-ops.md @@ -3,7 +3,7 @@ title: space-unary-ops rule_type: layout --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/space-unary-ops) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Some style guides require or disallow spaces before or after unary operators. This is mainly a stylistic issue, however, some JavaScript expressions can be written without spacing which makes it harder to read and maintain. diff --git a/docs/src/rules/space-unary-word-ops.md b/docs/src/rules/space-unary-word-ops.md index 4bb12622056..42ce2557133 100644 --- a/docs/src/rules/space-unary-word-ops.md +++ b/docs/src/rules/space-unary-word-ops.md @@ -5,9 +5,9 @@ title: space-unary-word-ops Requires spaces after unary word operators. -(removed) This rule was **removed** in ESLint v0.10.0 and **replaced** by the [space-unary-ops](space-unary-ops) rule. - -Require spaces following unary word operators. +:::important +This rule was removed in ESLint v0.10.0 and replaced by the [space-unary-ops](space-unary-ops) rule. +::: ## Rule Details diff --git a/docs/src/rules/spaced-comment.md b/docs/src/rules/spaced-comment.md index 3094c3cebed..6cdaba30779 100644 --- a/docs/src/rules/spaced-comment.md +++ b/docs/src/rules/spaced-comment.md @@ -5,7 +5,7 @@ related_rules: - spaced-line-comment --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/spaced-comment) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Some style guides require or disallow a whitespace immediately after the initial `//` or `/*` of a comment. Whitespace after the `//` or `/*` makes it easier to read text in comments. diff --git a/docs/src/rules/spaced-line-comment.md b/docs/src/rules/spaced-line-comment.md index 9ddc648221b..c536642dabd 100644 --- a/docs/src/rules/spaced-line-comment.md +++ b/docs/src/rules/spaced-line-comment.md @@ -7,7 +7,9 @@ related_rules: Enforces consistent spacing after `//` in line comments. -(removed) This rule was **removed** in ESLint v1.0 and **replaced** by the [spaced-comment](spaced-comment) rule. +::: important +This rule was removed in ESLint v1.0.0 and replaced by the [spaced-comment](spaced-comment) rule. +::: Some style guides require or disallow a whitespace immediately after the initial `//` of a line comment. Whitespace after the `//` makes it easier to read text in comments. diff --git a/docs/src/rules/switch-colon-spacing.md b/docs/src/rules/switch-colon-spacing.md index 7672c6275b7..63836a4222b 100644 --- a/docs/src/rules/switch-colon-spacing.md +++ b/docs/src/rules/switch-colon-spacing.md @@ -3,7 +3,7 @@ title: switch-colon-spacing rule_type: layout --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/switch-colon-spacing) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). Spacing around colons improves readability of `case`/`default` clauses. diff --git a/docs/src/rules/template-curly-spacing.md b/docs/src/rules/template-curly-spacing.md index 7a095cc38d8..4ac71420fbe 100644 --- a/docs/src/rules/template-curly-spacing.md +++ b/docs/src/rules/template-curly-spacing.md @@ -3,7 +3,7 @@ title: template-curly-spacing rule_type: layout --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/template-curly-spacing) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). We can embed expressions in template strings with using a pair of `${` and `}`. diff --git a/docs/src/rules/template-tag-spacing.md b/docs/src/rules/template-tag-spacing.md index 2adf4c76205..1c3bb0867a3 100644 --- a/docs/src/rules/template-tag-spacing.md +++ b/docs/src/rules/template-tag-spacing.md @@ -6,8 +6,8 @@ further_reading: - https://exploringjs.com/es6/ch_template-literals.html#_examples-of-using-tagged-template-literals --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). - +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/template-tag-spacing) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). + With ES6, it's possible to create functions called [tagged template literals](#further-reading) where the function parameters consist of a template literal's strings and expressions. When using tagged template literals, it's possible to insert whitespace between the tag function and the template literal. Since this whitespace is optional, the following lines are equivalent: diff --git a/docs/src/rules/wrap-iife.md b/docs/src/rules/wrap-iife.md index dd0048a8bb7..634d6acc593 100644 --- a/docs/src/rules/wrap-iife.md +++ b/docs/src/rules/wrap-iife.md @@ -3,7 +3,7 @@ title: wrap-iife rule_type: layout --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/wrap-iife) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). You can immediately invoke function expressions, but not function declarations. A common technique to create an immediately-invoked function expression (IIFE) is to wrap a function declaration in parentheses. The opening parentheses causes the contained function to be parsed as an expression, rather than a declaration. diff --git a/docs/src/rules/wrap-regex.md b/docs/src/rules/wrap-regex.md index 0a5daf0e1a0..39c6f4694b2 100644 --- a/docs/src/rules/wrap-regex.md +++ b/docs/src/rules/wrap-regex.md @@ -3,7 +3,7 @@ title: wrap-regex rule_type: layout --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/wrap-regex) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). When a regular expression is used in certain situations, it can end up looking like a division operator. For example: diff --git a/docs/src/rules/yield-star-spacing.md b/docs/src/rules/yield-star-spacing.md index aeeb0c73b2d..73b8dae0836 100644 --- a/docs/src/rules/yield-star-spacing.md +++ b/docs/src/rules/yield-star-spacing.md @@ -5,7 +5,7 @@ further_reading: - https://leanpub.com/understandinges6/read/#leanpub-auto-generators --- -This rule was **deprecated** in ESLint v8.53.0. Please use the corresponding rule in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). +This rule was **deprecated** in ESLint v8.53.0. Please use the [corresponding rule](https://eslint.style/rules/js/yield-star-spacing) in [`@stylistic/eslint-plugin-js`](https://eslint.style/packages/js). ## Rule Details diff --git a/docs/src/use/command-line-interface.md b/docs/src/use/command-line-interface.md index 9253e9c23f3..2788a44d344 100644 --- a/docs/src/use/command-line-interface.md +++ b/docs/src/use/command-line-interface.md @@ -280,7 +280,7 @@ This option specifies the rules to be used. These rules are merged with any rules specified with configuration files. If the rule is defined in a plugin, you have to prefix the rule ID with the plugin name and a `/`. -To ignore rules in `.eslintrc` configuration files and only run rules specified in the command line, use the `--rules` flag in combination with the [`--no-eslintrc`](#--no-eslintrc) flag. +To ignore rules in `.eslintrc` configuration files and only run rules specified in the command line, use the `--rule` flag in combination with the [`--no-eslintrc`](#--no-eslintrc) flag. ##### `--rule` example diff --git a/docs/src/use/formatters/html-formatter-example.html b/docs/src/use/formatters/html-formatter-example.html index 03dc7dcefef..6bbd626e114 100644 --- a/docs/src/use/formatters/html-formatter-example.html +++ b/docs/src/use/formatters/html-formatter-example.html @@ -118,14 +118,14 @@

ESLint Report

- 9 problems (5 errors, 4 warnings) - Generated on Fri Nov 03 2023 19:23:39 GMT-0400 (Eastern Daylight Time) + 9 problems (5 errors, 4 warnings) - Generated on Fri Dec 01 2023 21:46:40 GMT+0000 (Coordinated Universal Time)
diff --git a/docs/src/use/formatters/index.md b/docs/src/use/formatters/index.md index 6d853e16785..a78f34beaa0 100644 --- a/docs/src/use/formatters/index.md +++ b/docs/src/use/formatters/index.md @@ -72,7 +72,7 @@ Outputs results to the [Checkstyle](https://checkstyle.sourceforge.io/) format. Example output: ```xml - + ``` ### compact @@ -82,15 +82,15 @@ Human-readable output format. Mimics the default output of JSHint. Example output: ```text -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 1, col 10, Error - 'addOne' is defined but never used. (no-unused-vars) -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 2, col 9, Error - Use the isNaN function to compare with NaN. (use-isnan) -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 3, col 16, Error - Unexpected space before unary operator '++'. (space-unary-ops) -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 3, col 20, Warning - Missing semicolon. (semi) -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 4, col 12, Warning - Unnecessary 'else' after 'return'. (no-else-return) -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 5, col 1, Warning - Expected indentation of 8 spaces but found 6. (indent) -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 5, col 7, Error - Function 'addOne' expected a return value. (consistent-return) -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 5, col 13, Warning - Missing semicolon. (semi) -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 7, col 2, Error - Unnecessary semicolon. (no-extra-semi) +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js: line 1, col 10, Error - 'addOne' is defined but never used. (no-unused-vars) +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js: line 2, col 9, Error - Use the isNaN function to compare with NaN. (use-isnan) +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js: line 3, col 16, Error - Unexpected space before unary operator '++'. (space-unary-ops) +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js: line 3, col 20, Warning - Missing semicolon. (semi) +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js: line 4, col 12, Warning - Unnecessary 'else' after 'return'. (no-else-return) +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js: line 5, col 1, Warning - Expected indentation of 8 spaces but found 6. (indent) +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js: line 5, col 7, Error - Function 'addOne' expected a return value. (consistent-return) +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js: line 5, col 13, Warning - Missing semicolon. (semi) +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js: line 7, col 2, Error - Unnecessary semicolon. (no-extra-semi) 9 problems ``` @@ -110,7 +110,7 @@ Outputs results to format compatible with the [JSLint Jenkins plugin](https://pl Example output: ```xml - + ``` ### json-with-metadata @@ -125,7 +125,7 @@ Example output (formatted for easier reading): { "results": [ { - "filePath": "/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js", + "filePath": "/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js", "messages": [ { "ruleId": "no-unused-vars", @@ -727,7 +727,7 @@ Example output (formatted for easier reading): ```json [ { - "filePath": "/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js", + "filePath": "/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js", "messages": [ { "ruleId": "no-unused-vars", @@ -891,16 +891,16 @@ Example output: ```xml - - - - - - - - - - + + + + + + + + + + @@ -914,7 +914,7 @@ Example output: ```text -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js 1:10 error 'addOne' is defined but never used no-unused-vars 2:9 error Use the isNaN function to compare with NaN use-isnan 3:16 error Unexpected space before unary operator '++' space-unary-ops @@ -939,7 +939,7 @@ Example output: ```text TAP version 13 1..1 -not ok 1 - /var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js +not ok 1 - /var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js --- message: '''addOne'' is defined but never used.' severity: error @@ -1007,15 +1007,15 @@ Outputs results to a format similar to many commands in UNIX-like systems. Parsa Example output: ```text -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:1:10: 'addOne' is defined but never used. [Error/no-unused-vars] -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:2:9: Use the isNaN function to compare with NaN. [Error/use-isnan] -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:3:16: Unexpected space before unary operator '++'. [Error/space-unary-ops] -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:3:20: Missing semicolon. [Warning/semi] -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:4:12: Unnecessary 'else' after 'return'. [Warning/no-else-return] -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:5:1: Expected indentation of 8 spaces but found 6. [Warning/indent] -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:5:7: Function 'addOne' expected a return value. [Error/consistent-return] -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:5:13: Missing semicolon. [Warning/semi] -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:7:2: Unnecessary semicolon. [Error/no-extra-semi] +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js:1:10: 'addOne' is defined but never used. [Error/no-unused-vars] +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js:2:9: Use the isNaN function to compare with NaN. [Error/use-isnan] +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js:3:16: Unexpected space before unary operator '++'. [Error/space-unary-ops] +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js:3:20: Missing semicolon. [Warning/semi] +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js:4:12: Unnecessary 'else' after 'return'. [Warning/no-else-return] +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js:5:1: Expected indentation of 8 spaces but found 6. [Warning/indent] +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js:5:7: Function 'addOne' expected a return value. [Error/consistent-return] +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js:5:13: Missing semicolon. [Warning/semi] +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js:7:2: Unnecessary semicolon. [Error/no-extra-semi] 9 problems ``` @@ -1027,15 +1027,15 @@ Outputs results to format compatible with the integrated terminal of the [Visual Example output: ```text -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(1,10): error no-unused-vars : 'addOne' is defined but never used. -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(2,9): error use-isnan : Use the isNaN function to compare with NaN. -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(3,16): error space-unary-ops : Unexpected space before unary operator '++'. -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(3,20): warning semi : Missing semicolon. -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(4,12): warning no-else-return : Unnecessary 'else' after 'return'. -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(5,1): warning indent : Expected indentation of 8 spaces but found 6. -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(5,7): error consistent-return : Function 'addOne' expected a return value. -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(5,13): warning semi : Missing semicolon. -/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(7,2): error no-extra-semi : Unnecessary semicolon. +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js(1,10): error no-unused-vars : 'addOne' is defined but never used. +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js(2,9): error use-isnan : Use the isNaN function to compare with NaN. +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js(3,16): error space-unary-ops : Unexpected space before unary operator '++'. +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js(3,20): warning semi : Missing semicolon. +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js(4,12): warning no-else-return : Unnecessary 'else' after 'return'. +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js(5,1): warning indent : Expected indentation of 8 spaces but found 6. +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js(5,7): error consistent-return : Function 'addOne' expected a return value. +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js(5,13): warning semi : Missing semicolon. +/var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js(7,2): error no-extra-semi : Unnecessary semicolon. 9 problems ``` diff --git a/docs/tools/markdown-it-rule-example.js b/docs/tools/markdown-it-rule-example.js new file mode 100644 index 00000000000..efe8ab90529 --- /dev/null +++ b/docs/tools/markdown-it-rule-example.js @@ -0,0 +1,90 @@ +"use strict"; + +/** @typedef {import("../../lib/shared/types").ParserOptions} ParserOptions */ + +/** + * A callback function to handle the opening of container blocks. + * @callback OpenHandler + * @param {Object} data Callback data. + * @param {"correct" | "incorrect"} data.type The type of the example. + * @param {string} data.code The example code. + * @param {ParserOptions} data.parserOptions The parser options to be passed to the Playground. + * @param {Object} data.codeBlockToken The `markdown-it` token for the code block inside the container. + * @param {Object} data.env Additional Eleventy metadata, if available. + * @returns {string | undefined} If a text is returned, it will be appended to the rendered output + * of `markdown-it`. + */ + +/** + * A callback function to handle the closing of container blocks. + * @callback CloseHandler + * @returns {string | undefined} If a text is returned, it will be appended to the rendered output + * of `markdown-it`. + */ + +/** + * This is a utility to simplify the creation of `markdown-it-container` options to handle rule + * examples in the documentation. + * It is designed to automate the following common tasks: + * + * - Ensure that the plugin instance only matches container blocks tagged with 'correct' or + * 'incorrect'. + * - Parse the optional `parserOptions` after the correct/incorrect tag. + * - Apply common transformations to the code inside the code block, like stripping '⏎' at the end + * of a line or the last newline character. + * + * Additionally, the opening and closing of the container blocks are handled by two distinct + * callbacks, of which only the `open` callback is required. + * @param {Object} options The options object. + * @param {OpenHandler} options.open The open callback. + * @param {CloseHandler} [options.close] The close callback. + * @returns {Object} The `markdown-it-container` options. + * @example + * const markdownIt = require("markdown-it"); + * const markdownItContainer = require("markdown-it-container"); + * + * markdownIt() + * .use(markdownItContainer, "rule-example", markdownItRuleExample({ + * open({ type, code, parserOptions, codeBlockToken, env }) { + * // do something + * } + * close() { + * // do something + * } + * })) + * .render(text); + * + */ +function markdownItRuleExample({ open, close }) { + return { + validate(info) { + return /^\s*(?:in)?correct(?!\S)/u.test(info); + }, + render(tokens, index, options, env) { + const tagToken = tokens[index]; + + if (tagToken.nesting < 0) { + const text = close ? close() : void 0; + + // Return an empty string to avoid appending unexpected text to the output. + return typeof text === "string" ? text : ""; + } + + const { type, parserOptionsJSON } = /^\s*(?\S+)(\s+(?\S.*?))?\s*$/u.exec(tagToken.info).groups; + const parserOptions = { sourceType: "module", ...(parserOptionsJSON && JSON.parse(parserOptionsJSON)) }; + const codeBlockToken = tokens[index + 1]; + + // Remove trailing newline and presentational `⏎` characters (https://github.com/eslint/eslint/issues/17627): + const code = codeBlockToken.content + .replace(/\n$/u, "") + .replace(/⏎(?=\n)/gu, ""); + + const text = open({ type, code, parserOptions, codeBlockToken, env }); + + // Return an empty string to avoid appending unexpected text to the output. + return typeof text === "string" ? text : ""; + } + }; +} + +module.exports = markdownItRuleExample; diff --git a/lib/cli-engine/lint-result-cache.js b/lib/cli-engine/lint-result-cache.js index e36eb74bada..97d2ee40b39 100644 --- a/lib/cli-engine/lint-result-cache.js +++ b/lib/cli-engine/lint-result-cache.js @@ -128,16 +128,28 @@ class LintResultCache { return null; } + const cachedResults = fileDescriptor.meta.results; + + // Just in case, not sure if this can ever happen. + if (!cachedResults) { + return cachedResults; + } + + /* + * Shallow clone the object to ensure that any properties added or modified afterwards + * will not be accidentally stored in the cache file when `reconcile()` is called. + * https://github.com/eslint/eslint/issues/13507 + * All intentional changes to the cache file must be done through `setCachedLintResults()`. + */ + const results = { ...cachedResults }; + // If source is present but null, need to reread the file from the filesystem. - if ( - fileDescriptor.meta.results && - fileDescriptor.meta.results.source === null - ) { + if (results.source === null) { debug(`Rereading cached result source from filesystem: ${filePath}`); - fileDescriptor.meta.results.source = fs.readFileSync(filePath, "utf-8"); + results.source = fs.readFileSync(filePath, "utf-8"); } - return fileDescriptor.meta.results; + return results; } /** diff --git a/lib/linter/linter.js b/lib/linter/linter.js index ef51cf8b4c0..8c62ed22824 100644 --- a/lib/linter/linter.js +++ b/lib/linter/linter.js @@ -1432,7 +1432,7 @@ class Linter { verify(textOrSourceCode, config, filenameOrOptions) { debug("Verify"); - const { configType } = internalSlotsMap.get(this); + const { configType, cwd } = internalSlotsMap.get(this); const options = typeof filenameOrOptions === "string" ? { filename: filenameOrOptions } @@ -1451,7 +1451,7 @@ class Linter { let configArray = config; if (!Array.isArray(config) || typeof config.getConfig !== "function") { - configArray = new FlatConfigArray(config); + configArray = new FlatConfigArray(config, { basePath: cwd }); configArray.normalizeSync(); } diff --git a/lib/rules/for-direction.js b/lib/rules/for-direction.js index 3f2ad9df645..69198d11ad2 100644 --- a/lib/rules/for-direction.js +++ b/lib/rules/for-direction.js @@ -101,30 +101,37 @@ module.exports = { } return 0; } + return { ForStatement(node) { - if (node.test && node.test.type === "BinaryExpression" && node.test.left.type === "Identifier" && node.update) { - const counter = node.test.left.name; - const operator = node.test.operator; - const update = node.update; + if (node.test && node.test.type === "BinaryExpression" && node.update) { + for (const counterPosition of ["left", "right"]) { + if (node.test[counterPosition].type !== "Identifier") { + continue; + } - let wrongDirection; + const counter = node.test[counterPosition].name; + const operator = node.test.operator; + const update = node.update; - if (operator === "<" || operator === "<=") { - wrongDirection = -1; - } else if (operator === ">" || operator === ">=") { - wrongDirection = 1; - } else { - return; - } + let wrongDirection; + + if (operator === "<" || operator === "<=") { + wrongDirection = counterPosition === "left" ? -1 : 1; + } else if (operator === ">" || operator === ">=") { + wrongDirection = counterPosition === "left" ? 1 : -1; + } else { + return; + } - if (update.type === "UpdateExpression") { - if (getUpdateDirection(update, counter) === wrongDirection) { + if (update.type === "UpdateExpression") { + if (getUpdateDirection(update, counter) === wrongDirection) { + report(node); + } + } else if (update.type === "AssignmentExpression" && getAssignmentDirection(update, counter) === wrongDirection) { report(node); } - } else if (update.type === "AssignmentExpression" && getAssignmentDirection(update, counter) === wrongDirection) { - report(node); } } } diff --git a/lib/rules/no-array-constructor.js b/lib/rules/no-array-constructor.js index b5399264118..f56b6876674 100644 --- a/lib/rules/no-array-constructor.js +++ b/lib/rules/no-array-constructor.js @@ -5,6 +5,18 @@ "use strict"; +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const { + getVariableByName, + isClosingParenToken, + isOpeningParenToken, + isStartOfExpressionStatement, + needsPrecedingSemicolon +} = require("./utils/ast-utils"); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -20,15 +32,45 @@ module.exports = { url: "https://eslint.org/docs/latest/rules/no-array-constructor" }, + hasSuggestions: true, + schema: [], messages: { - preferLiteral: "The array literal notation [] is preferable." + preferLiteral: "The array literal notation [] is preferable.", + useLiteral: "Replace with an array literal.", + useLiteralAfterSemicolon: "Replace with an array literal, add preceding semicolon." } }, create(context) { + const sourceCode = context.sourceCode; + + /** + * Gets the text between the calling parentheses of a CallExpression or NewExpression. + * @param {ASTNode} node A CallExpression or NewExpression node. + * @returns {string} The text between the calling parentheses, or an empty string if there are none. + */ + function getArgumentsText(node) { + const lastToken = sourceCode.getLastToken(node); + + if (!isClosingParenToken(lastToken)) { + return ""; + } + + let firstToken = node.callee; + + do { + firstToken = sourceCode.getTokenAfter(firstToken); + if (!firstToken || firstToken === lastToken) { + return ""; + } + } while (!isOpeningParenToken(firstToken)); + + return sourceCode.text.slice(firstToken.range[1], lastToken.range[0]); + } + /** * Disallow construction of dense arrays using the Array constructor * @param {ASTNode} node node to evaluate @@ -37,11 +79,48 @@ module.exports = { */ function check(node) { if ( - node.arguments.length !== 1 && - node.callee.type === "Identifier" && - node.callee.name === "Array" - ) { - context.report({ node, messageId: "preferLiteral" }); + node.callee.type !== "Identifier" || + node.callee.name !== "Array" || + node.arguments.length === 1 && + node.arguments[0].type !== "SpreadElement") { + return; + } + + const variable = getVariableByName(sourceCode.getScope(node), "Array"); + + /* + * Check if `Array` is a predefined global variable: predefined globals have no declarations, + * meaning that the `identifiers` list of the variable object is empty. + */ + if (variable && variable.identifiers.length === 0) { + const argsText = getArgumentsText(node); + let fixText; + let messageId; + + /* + * Check if the suggested change should include a preceding semicolon or not. + * Due to JavaScript's ASI rules, a missing semicolon may be inserted automatically + * before an expression like `Array()` or `new Array()`, but not when the expression + * is changed into an array literal like `[]`. + */ + if (isStartOfExpressionStatement(node) && needsPrecedingSemicolon(sourceCode, node)) { + fixText = `;[${argsText}]`; + messageId = "useLiteralAfterSemicolon"; + } else { + fixText = `[${argsText}]`; + messageId = "useLiteral"; + } + + context.report({ + node, + messageId: "preferLiteral", + suggest: [ + { + messageId, + fix: fixer => fixer.replaceText(node, fixText) + } + ] + }); } } diff --git a/lib/rules/no-console.js b/lib/rules/no-console.js index f257098d38b..d20477c5d9a 100644 --- a/lib/rules/no-console.js +++ b/lib/rules/no-console.js @@ -43,8 +43,11 @@ module.exports = { } ], + hasSuggestions: true, + messages: { - unexpected: "Unexpected console statement." + unexpected: "Unexpected console statement.", + removeConsole: "Remove the console.{{ propertyName }}()." } }, @@ -94,6 +97,64 @@ module.exports = { ); } + /** + * Checks if removing the ExpressionStatement node will cause ASI to + * break. + * eg. + * foo() + * console.log(); + * [1, 2, 3].forEach(a => doSomething(a)) + * + * Removing the console.log(); statement should leave two statements, but + * here the two statements will become one because [ causes continuation after + * foo(). + * @param {ASTNode} node The ExpressionStatement node to check. + * @returns {boolean} `true` if ASI will break after removing the ExpressionStatement + * node. + */ + function maybeAsiHazard(node) { + const SAFE_TOKENS_BEFORE = /^[:;{]$/u; // One of :;{ + const UNSAFE_CHARS_AFTER = /^[-[(/+`]/u; // One of [(/+-` + + const tokenBefore = sourceCode.getTokenBefore(node); + const tokenAfter = sourceCode.getTokenAfter(node); + + return ( + Boolean(tokenAfter) && + UNSAFE_CHARS_AFTER.test(tokenAfter.value) && + tokenAfter.value !== "++" && + tokenAfter.value !== "--" && + Boolean(tokenBefore) && + !SAFE_TOKENS_BEFORE.test(tokenBefore.value) + ); + } + + /** + * Checks if the MemberExpression node's parent.parent.parent is a + * Program, BlockStatement, StaticBlock, or SwitchCase node. This check + * is necessary to avoid providing a suggestion that might cause a syntax error. + * + * eg. if (a) console.log(b), removing console.log() here will lead to a + * syntax error. + * if (a) { console.log(b) }, removing console.log() here is acceptable. + * + * Additionally, it checks if the callee of the CallExpression node is + * the node itself. + * + * eg. foo(console.log), cannot provide a suggestion here. + * @param {ASTNode} node The MemberExpression node to check. + * @returns {boolean} `true` if a suggestion can be provided for a node. + */ + function canProvideSuggestions(node) { + return ( + node.parent.type === "CallExpression" && + node.parent.callee === node && + node.parent.parent.type === "ExpressionStatement" && + astUtils.STATEMENT_LIST_PARENTS.has(node.parent.parent.parent.type) && + !maybeAsiHazard(node.parent.parent) + ); + } + /** * Reports the given reference as a violation. * @param {eslint-scope.Reference} reference The reference to report. @@ -102,10 +163,21 @@ module.exports = { function report(reference) { const node = reference.identifier.parent; + const propertyName = astUtils.getStaticPropertyName(node); + context.report({ node, loc: node.loc, - messageId: "unexpected" + messageId: "unexpected", + suggest: canProvideSuggestions(node) + ? [{ + messageId: "removeConsole", + data: { propertyName }, + fix(fixer) { + return fixer.remove(node.parent.parent); + } + }] + : [] }); } diff --git a/lib/rules/no-object-constructor.js b/lib/rules/no-object-constructor.js index e3ac2095734..8875ec2124b 100644 --- a/lib/rules/no-object-constructor.js +++ b/lib/rules/no-object-constructor.js @@ -9,67 +9,12 @@ // Requirements //------------------------------------------------------------------------------ -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, 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. - * @returns {boolean} Whether the node appears at the beginning of an ancestor ExpressionStatement node. - */ -function isStartOfExpressionStatement(node) { - const start = node.range[0]; - let ancestor = node; - - while ((ancestor = ancestor.parent) && ancestor.range[0] === start) { - if (ancestor.type === "ExpressionStatement") { - return true; - } - } - return false; -} +const { + getVariableByName, + isArrowToken, + isStartOfExpressionStatement, + needsPrecedingSemicolon +} = require("./utils/ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -120,50 +65,6 @@ 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. @@ -183,7 +84,7 @@ module.exports = { if (needsParentheses(node)) { replacement = "({})"; - if (needsSemicolon(node)) { + if (needsPrecedingSemicolon(sourceCode, node)) { fixText = ";({})"; messageId = "useLiteralAfterSemicolon"; } else { diff --git a/lib/rules/no-restricted-imports.js b/lib/rules/no-restricted-imports.js index 6abfcacae13..eb59f4c23a9 100644 --- a/lib/rules/no-restricted-imports.js +++ b/lib/rules/no-restricted-imports.js @@ -74,6 +74,9 @@ const arrayOfStringsOrObjectPatterns = { minItems: 1, uniqueItems: true }, + importNamePattern: { + type: "string" + }, message: { type: "string", minLength: 1 @@ -115,8 +118,12 @@ module.exports = { patternAndImportNameWithCustomMessage: "'{{importName}}' import from '{{importSource}}' is restricted from being used by a pattern. {{customMessage}}", patternAndEverything: "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted from being used by a pattern.", + + patternAndEverythingWithRegexImportName: "* import is invalid because import name matching '{{importNames}}' pattern from '{{importSource}}' is restricted from being used.", // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period patternAndEverythingWithCustomMessage: "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted from being used by a pattern. {{customMessage}}", + // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period + patternAndEverythingWithRegexImportNameAndCustomMessage: "* import is invalid because import name matching '{{importNames}}' pattern from '{{importSource}}' is restricted from being used. {{customMessage}}", everything: "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted.", // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period @@ -175,10 +182,11 @@ module.exports = { } // relative paths are supported for this rule - const restrictedPatternGroups = restrictedPatterns.map(({ group, message, caseSensitive, importNames }) => ({ + const restrictedPatternGroups = restrictedPatterns.map(({ group, message, caseSensitive, importNames, importNamePattern }) => ({ matcher: ignore({ allowRelativePaths: true, ignorecase: !caseSensitive }).add(group), customMessage: message, - importNames + importNames, + importNamePattern })); // if no imports are restricted we don't need to check @@ -262,12 +270,13 @@ module.exports = { const customMessage = group.customMessage; const restrictedImportNames = group.importNames; + const restrictedImportNamePattern = group.importNamePattern ? new RegExp(group.importNamePattern, "u") : null; /* * If we are not restricting to any specific import names and just the pattern itself, * report the error and move on */ - if (!restrictedImportNames) { + if (!restrictedImportNames && !restrictedImportNamePattern) { context.report({ node, messageId: customMessage ? "patternWithCustomMessage" : "patterns", @@ -279,40 +288,54 @@ module.exports = { return; } - if (importNames.has("*")) { - const specifierData = importNames.get("*")[0]; - - context.report({ - node, - messageId: customMessage ? "patternAndEverythingWithCustomMessage" : "patternAndEverything", - loc: specifierData.loc, - data: { - importSource, - importNames: restrictedImportNames, - customMessage + importNames.forEach((specifiers, importName) => { + if (importName === "*") { + const [specifier] = specifiers; + + if (restrictedImportNames) { + context.report({ + node, + messageId: customMessage ? "patternAndEverythingWithCustomMessage" : "patternAndEverything", + loc: specifier.loc, + data: { + importSource, + importNames: restrictedImportNames, + customMessage + } + }); + } else { + context.report({ + node, + messageId: customMessage ? "patternAndEverythingWithRegexImportNameAndCustomMessage" : "patternAndEverythingWithRegexImportName", + loc: specifier.loc, + data: { + importSource, + importNames: restrictedImportNamePattern, + customMessage + } + }); } - }); - } - restrictedImportNames.forEach(importName => { - if (!importNames.has(importName)) { return; } - const specifiers = importNames.get(importName); - - specifiers.forEach(specifier => { - context.report({ - node, - messageId: customMessage ? "patternAndImportNameWithCustomMessage" : "patternAndImportName", - loc: specifier.loc, - data: { - importSource, - customMessage, - importName - } + if ( + (restrictedImportNames && restrictedImportNames.includes(importName)) || + (restrictedImportNamePattern && restrictedImportNamePattern.test(importName)) + ) { + specifiers.forEach(specifier => { + context.report({ + node, + messageId: customMessage ? "patternAndImportNameWithCustomMessage" : "patternAndImportName", + loc: specifier.loc, + data: { + importSource, + customMessage, + importName + } + }); }); - }); + } }); } diff --git a/lib/rules/utils/ast-utils.js b/lib/rules/utils/ast-utils.js index bebb4d5168b..962bdde0af1 100644 --- a/lib/rules/utils/ast-utils.js +++ b/lib/rules/utils/ast-utils.js @@ -1015,6 +1015,114 @@ function isDirective(node) { return node.type === "ExpressionStatement" && typeof node.directive === "string"; } +/** + * Tests if a node appears at the beginning of an ancestor ExpressionStatement node. + * @param {ASTNode} node The node to check. + * @returns {boolean} Whether the node appears at the beginning of an ancestor ExpressionStatement node. + */ +function isStartOfExpressionStatement(node) { + const start = node.range[0]; + let ancestor = node; + + while ((ancestor = ancestor.parent) && ancestor.range[0] === start) { + if (ancestor.type === "ExpressionStatement") { + return true; + } + } + return false; +} + +/** + * Determines whether an opening parenthesis `(`, bracket `[` or backtick ``` ` ``` needs to be preceded by a semicolon. + * This opening parenthesis or bracket should be at the start of an `ExpressionStatement` or at the start of the body of an `ArrowFunctionExpression`. + * @type {(sourceCode: SourceCode, node: ASTNode) => boolean} + * @param {SourceCode} sourceCode The source code object. + * @param {ASTNode} node A node at the position where an opening parenthesis or bracket will be inserted. + * @returns {boolean} Whether a semicolon is required before the opening parenthesis or braket. + */ +let needsPrecedingSemicolon; + +{ + 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, 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" + ]); + + needsPrecedingSemicolon = + function(sourceCode, 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; + }; +} + //------------------------------------------------------------------------------ // Public Interface //------------------------------------------------------------------------------ @@ -2168,5 +2276,7 @@ module.exports = { getModuleExportName, isConstant, isTopLevelExpressionStatement, - isDirective + isDirective, + isStartOfExpressionStatement, + needsPrecedingSemicolon }; diff --git a/package.json b/package.json index 70c5241d15c..90158fad2b3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint", - "version": "8.53.0", + "version": "8.55.0", "author": "Nicholas C. Zakas ", "description": "An AST-based pattern checker for JavaScript.", "bin": { @@ -19,6 +19,7 @@ "build:readme": "node tools/update-readme.js", "lint": "node Makefile.js lint", "lint:docs:js": "node Makefile.js lintDocsJS", + "lint:docs:rule-examples": "node Makefile.js checkRuleExamples", "lint:fix": "node Makefile.js lint -- fix", "lint:fix:docs:js": "node Makefile.js lintDocsJS -- fix", "release:generate:alpha": "node Makefile.js generatePrerelease -- alpha", @@ -42,6 +43,7 @@ "git add packages/js/src/configs/eslint-all.js" ], "docs/src/rules/*.md": [ + "node tools/check-rule-examples.js", "node tools/fetch-docs-links.js", "git add docs/src/_data/further_reading_links.json" ], @@ -62,8 +64,8 @@ "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.3", - "@eslint/js": "8.53.0", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.55.0", "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -132,8 +134,10 @@ "gray-matter": "^4.0.3", "lint-staged": "^11.0.0", "load-perf": "^0.2.0", - "markdownlint": "^0.25.1", - "markdownlint-cli": "^0.31.1", + "markdown-it": "^12.2.0", + "markdown-it-container": "^3.0.0", + "markdownlint": "^0.31.1", + "markdownlint-cli": "^0.37.0", "marked": "^4.0.8", "memfs": "^3.0.1", "metascraper": "^5.25.7", @@ -149,13 +153,13 @@ "pirates": "^4.0.5", "progress": "^2.0.3", "proxyquire": "^2.0.1", - "recast": "^0.20.4", - "regenerator-runtime": "^0.13.2", + "recast": "^0.23.0", + "regenerator-runtime": "^0.14.0", "rollup-plugin-node-polyfills": "^0.2.1", "semver": "^7.5.3", "shelljs": "^0.8.2", "sinon": "^11.0.0", - "vite-plugin-commonjs": "^0.8.2", + "vite-plugin-commonjs": "^0.10.0", "webdriverio": "^8.14.6", "webpack": "^5.23.0", "webpack-cli": "^4.5.0", diff --git a/packages/js/package.json b/packages/js/package.json index 529c630dd99..2c7aacae88a 100644 --- a/packages/js/package.json +++ b/packages/js/package.json @@ -1,6 +1,6 @@ { "name": "@eslint/js", - "version": "8.53.0", + "version": "8.55.0", "description": "ESLint JavaScript language implementation", "main": "./src/index.js", "scripts": {}, diff --git a/templates/rule-proposal.md b/templates/rule-proposal.md index cc1b011361a..1e5d2a24fa3 100644 --- a/templates/rule-proposal.md +++ b/templates/rule-proposal.md @@ -6,7 +6,6 @@ [ ] Warns about a potential problem [ ] Suggests an alternate way of doing something -[ ] Enforces a formatting/stylistic preference **Please provide some example JavaScript code that this rule will warn about:** diff --git a/tests/fixtures/bad-examples.md b/tests/fixtures/bad-examples.md new file mode 100644 index 00000000000..a8f10c34c5d --- /dev/null +++ b/tests/fixtures/bad-examples.md @@ -0,0 +1,26 @@ +--- +title: Lorem Ipsum +--- + +This file contains rule example code with syntax errors. + + + +::: incorrect { "sourceType": "script" } + +``` +export default "foo"; +``` + +::: + + +:::correct + +````ts +const foo = "bar"; + +const foo = "baz"; +```` + +::: diff --git a/tests/fixtures/config-extends/.eslintrc b/tests/fixtures/config-extends/.eslintrc deleted file mode 100644 index 146ebff8926..00000000000 --- a/tests/fixtures/config-extends/.eslintrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "./subdir/.eslintrc", - - "rules": { - "quotes": [2, "double"], - "valid-jsdoc": 0 - }, - - "env": { - "browser": false - } -} diff --git a/tests/fixtures/config-extends/array/.eslintrc b/tests/fixtures/config-extends/array/.eslintrc deleted file mode 100644 index 6221f67061d..00000000000 --- a/tests/fixtures/config-extends/array/.eslintrc +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": [ - ".eslintrc1", - ".eslintrc2" - ], - - "rules": { - "no-empty": 1 - }, - - "env": { - "browser": false - } -} diff --git a/tests/fixtures/config-extends/array/.eslintrc1 b/tests/fixtures/config-extends/array/.eslintrc1 deleted file mode 100644 index 2ba38c72474..00000000000 --- a/tests/fixtures/config-extends/array/.eslintrc1 +++ /dev/null @@ -1,12 +0,0 @@ -{ - "rules": { - "comma-dangle": 1, - "no-console": 2, - "no-empty": 2 - }, - - "env": { - "browser": true, - "node": true - } -} diff --git a/tests/fixtures/config-extends/array/.eslintrc2 b/tests/fixtures/config-extends/array/.eslintrc2 deleted file mode 100644 index ef204852184..00000000000 --- a/tests/fixtures/config-extends/array/.eslintrc2 +++ /dev/null @@ -1,9 +0,0 @@ -{ - "rules": { - "comma-dangle": 2 - }, - - "env": { - "es6": true - } -} diff --git a/tests/fixtures/config-extends/deep.json b/tests/fixtures/config-extends/deep.json deleted file mode 100644 index c61c9728902..00000000000 --- a/tests/fixtures/config-extends/deep.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "rules": { - "yoda": 2 - }, - - "env": { - "browser": true - }, - - "extends": "./subdir/subsubdir/deeper.json" -} diff --git a/tests/fixtures/config-extends/error.json b/tests/fixtures/config-extends/error.json deleted file mode 100644 index 8b9a039b2e6..00000000000 --- a/tests/fixtures/config-extends/error.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./non-existent.json" -} diff --git a/tests/fixtures/config-extends/js/.eslintrc b/tests/fixtures/config-extends/js/.eslintrc deleted file mode 100644 index 5705d5a4add..00000000000 --- a/tests/fixtures/config-extends/js/.eslintrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "./foo.js", - - "rules": { - "quotes": [2, "double"], - "valid-jsdoc": 0 - }, - - "env": { - "browser": false - } -} diff --git a/tests/fixtures/config-extends/package.json b/tests/fixtures/config-extends/package.json deleted file mode 100644 index 08c1d676f68..00000000000 --- a/tests/fixtures/config-extends/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "test", - "version": "0.1.1", - "eslintConfig": { - "extends": "./subdir/.eslintrc" - } -} diff --git a/tests/fixtures/config-extends/package/.eslintrc b/tests/fixtures/config-extends/package/.eslintrc deleted file mode 100644 index b6e5a51461f..00000000000 --- a/tests/fixtures/config-extends/package/.eslintrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "eslint-config-foo", - - "rules": { - "quotes": [2, "double"], - "valid-jsdoc": 0 - }, - - "env": { - "browser": false - } -} diff --git a/tests/fixtures/config-extends/package2/.eslintrc b/tests/fixtures/config-extends/package2/.eslintrc deleted file mode 100644 index a8266993dbe..00000000000 --- a/tests/fixtures/config-extends/package2/.eslintrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "foo", - - "rules": { - "quotes": [2, "double"], - "valid-jsdoc": 0 - }, - - "env": { - "browser": false - } -} diff --git a/tests/fixtures/config-extends/package2/subdir/foo.js b/tests/fixtures/config-extends/package2/subdir/foo.js deleted file mode 100644 index f688910ec09..00000000000 --- a/tests/fixtures/config-extends/package2/subdir/foo.js +++ /dev/null @@ -1 +0,0 @@ -var a = 1; diff --git a/tests/fixtures/config-extends/package3/.eslintrc b/tests/fixtures/config-extends/package3/.eslintrc deleted file mode 100644 index 78acea99b19..00000000000 --- a/tests/fixtures/config-extends/package3/.eslintrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "foo/bar", - - "rules": { - "quotes": [2, "double"], - "valid-jsdoc": 0 - }, - - "env": { - "browser": false - } -} diff --git a/tests/fixtures/config-extends/package4/.eslintrc b/tests/fixtures/config-extends/package4/.eslintrc deleted file mode 100644 index f4716a43795..00000000000 --- a/tests/fixtures/config-extends/package4/.eslintrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "bar-eslint-config-foo", - - "rules": { - "quotes": [2, "double"], - "valid-jsdoc": 0 - }, - - "env": { - "browser": false - } -} diff --git a/tests/fixtures/config-extends/resolving-relatively/.eslintrc.json b/tests/fixtures/config-extends/resolving-relatively/.eslintrc.json deleted file mode 100644 index b77cef2af99..00000000000 --- a/tests/fixtures/config-extends/resolving-relatively/.eslintrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "a" -} diff --git a/tests/fixtures/config-extends/resolving-relatively/node_modules/a/index.js b/tests/fixtures/config-extends/resolving-relatively/node_modules/a/index.js deleted file mode 100644 index 95d0e983665..00000000000 --- a/tests/fixtures/config-extends/resolving-relatively/node_modules/a/index.js +++ /dev/null @@ -1,8 +0,0 @@ -"use strict"; - -module.exports = { - extends: "b", - rules: { - a: 2 - } -}; diff --git a/tests/fixtures/config-extends/resolving-relatively/node_modules/a/node_modules/b/index.js b/tests/fixtures/config-extends/resolving-relatively/node_modules/a/node_modules/b/index.js deleted file mode 100644 index 26a261343e3..00000000000 --- a/tests/fixtures/config-extends/resolving-relatively/node_modules/a/node_modules/b/index.js +++ /dev/null @@ -1,7 +0,0 @@ -"use strict"; - -module.exports = { - rules: { - b: 2 - } -}; diff --git a/tests/fixtures/config-extends/scoped-package/.eslintrc b/tests/fixtures/config-extends/scoped-package/.eslintrc deleted file mode 100644 index 8c7d034045c..00000000000 --- a/tests/fixtures/config-extends/scoped-package/.eslintrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "@scope/eslint-config-foo", - - "rules": { - "quotes": [2, "double"], - "valid-jsdoc": 0 - }, - - "env": { - "browser": false - } -} diff --git a/tests/fixtures/config-extends/scoped-package2/.eslintrc b/tests/fixtures/config-extends/scoped-package2/.eslintrc deleted file mode 100644 index 6bd8b24bfff..00000000000 --- a/tests/fixtures/config-extends/scoped-package2/.eslintrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "@scope/foo", - - "rules": { - "quotes": [2, "double"], - "valid-jsdoc": 0 - }, - - "env": { - "browser": false - } -} diff --git a/tests/fixtures/config-extends/scoped-package3/.eslintrc b/tests/fixtures/config-extends/scoped-package3/.eslintrc deleted file mode 100644 index c5a386d69ce..00000000000 --- a/tests/fixtures/config-extends/scoped-package3/.eslintrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "@scope/foo/bar", - - "rules": { - "quotes": [2, "double"], - "valid-jsdoc": 0 - }, - - "env": { - "browser": false - } -} diff --git a/tests/fixtures/config-extends/scoped-package3/foo.js b/tests/fixtures/config-extends/scoped-package3/foo.js deleted file mode 100644 index f688910ec09..00000000000 --- a/tests/fixtures/config-extends/scoped-package3/foo.js +++ /dev/null @@ -1 +0,0 @@ -var a = 1; diff --git a/tests/fixtures/config-extends/scoped-package4/.eslintrc b/tests/fixtures/config-extends/scoped-package4/.eslintrc deleted file mode 100644 index de61a98656b..00000000000 --- a/tests/fixtures/config-extends/scoped-package4/.eslintrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "@scope/eslint-config", - - "rules": { - "quotes": [2, "double"], - "valid-jsdoc": 0 - }, - - "env": { - "browser": false - } -} diff --git a/tests/fixtures/config-extends/scoped-package5/.eslintrc b/tests/fixtures/config-extends/scoped-package5/.eslintrc deleted file mode 100644 index 46a99024612..00000000000 --- a/tests/fixtures/config-extends/scoped-package5/.eslintrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "@scope/", - - "rules": { - "quotes": [2, "double"], - "valid-jsdoc": 0 - }, - - "env": { - "browser": false - } -} diff --git a/tests/fixtures/config-extends/scoped-package6/.eslintrc b/tests/fixtures/config-extends/scoped-package6/.eslintrc deleted file mode 100644 index 574a1a3fcd3..00000000000 --- a/tests/fixtures/config-extends/scoped-package6/.eslintrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "@scope", - - "rules": { - "quotes": [2, "double"], - "valid-jsdoc": 0 - }, - - "env": { - "browser": false - } -} diff --git a/tests/fixtures/config-extends/scoped-package7/.eslintrc b/tests/fixtures/config-extends/scoped-package7/.eslintrc deleted file mode 100644 index 24a951a71fa..00000000000 --- a/tests/fixtures/config-extends/scoped-package7/.eslintrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "@scope/eslint-configfoo", - - "rules": { - "quotes": [2, "double"], - "valid-jsdoc": 0 - }, - - "env": { - "browser": false - } -} diff --git a/tests/fixtures/config-extends/scoped-package8/.eslintrc b/tests/fixtures/config-extends/scoped-package8/.eslintrc deleted file mode 100644 index c410ed43176..00000000000 --- a/tests/fixtures/config-extends/scoped-package8/.eslintrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "@scope/bar-eslint-config-foo", - - "rules": { - "quotes": [2, "double"], - "valid-jsdoc": 0 - }, - - "env": { - "browser": false - } -} diff --git a/tests/fixtures/config-extends/scoped-package9/.eslintrc b/tests/fixtures/config-extends/scoped-package9/.eslintrc deleted file mode 100644 index ab840397fdd..00000000000 --- a/tests/fixtures/config-extends/scoped-package9/.eslintrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "@scope/eslint-config/foo", - - "rules": { - "quotes": [2, "double"], - "valid-jsdoc": 0 - }, - - "env": { - "browser": false - } -} diff --git a/tests/fixtures/config-extends/subdir/.eslintrc b/tests/fixtures/config-extends/subdir/.eslintrc deleted file mode 100644 index b98d291aa4e..00000000000 --- a/tests/fixtures/config-extends/subdir/.eslintrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "rules": { - "quotes": [1, "single"], - "yoda": 2 - }, - - "env": { - "browser": true - } -} diff --git a/tests/fixtures/config-extends/subdir/subsubdir/deeper.json b/tests/fixtures/config-extends/subdir/subsubdir/deeper.json deleted file mode 100644 index d904f4a5b51..00000000000 --- a/tests/fixtures/config-extends/subdir/subsubdir/deeper.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "rules": { - "semi": 2 - }, - - "env": { - "browser": false - }, - - "extends": "./subsubsubdir/deepest.json" -} diff --git a/tests/fixtures/config-extends/subdir/subsubdir/subsubsubdir/deepest.json b/tests/fixtures/config-extends/subdir/subsubdir/subsubsubdir/deepest.json deleted file mode 100644 index 70dc7eefb7f..00000000000 --- a/tests/fixtures/config-extends/subdir/subsubdir/subsubsubdir/deepest.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "rules": { - "semi": 1, - "valid-jsdoc": 0 - }, - - "env": { - "browser": true - } -} diff --git a/tests/fixtures/good-examples.md b/tests/fixtures/good-examples.md new file mode 100644 index 00000000000..c68dd09c907 --- /dev/null +++ b/tests/fixtures/good-examples.md @@ -0,0 +1,33 @@ +This file contains rule example code without syntax errors. + +::: incorrect + +```js +export default⏎ +"foo"; +``` + +::: + +::: correct { "ecmaFeatures": { "jsx": true } } + +```jsx +const foo = ; +``` + +::: + +A test with multiple spaces after 'correct': + +:::correct + +```js +``` + +::: + +The following code block is not a rule example, so it won't be checked: + +```js +!@#$%^&*() +``` diff --git a/tests/lib/cli.js b/tests/lib/cli.js index 33e7884d5ad..9a0dcdce69f 100644 --- a/tests/lib/cli.js +++ b/tests/lib/cli.js @@ -63,7 +63,7 @@ describe("cli", () => { const localCLI = proxyquire("../../lib/cli", { "./eslint": { ESLint: fakeESLint }, - "./flat-eslint": { FlatESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) }, + "./eslint/flat-eslint": { FlatESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(configType === "flat") }, "./shared/logging": log }); @@ -990,7 +990,7 @@ describe("cli", () => { localCLI = proxyquire("../../lib/cli", { "./eslint": { ESLint: fakeESLint }, - "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) }, + "./eslint/flat-eslint": { FlatESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(useFlatConfig) }, "./shared/logging": log }); @@ -1009,7 +1009,7 @@ describe("cli", () => { localCLI = proxyquire("../../lib/cli", { "./eslint": { ESLint: fakeESLint }, - "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) }, + "./eslint/flat-eslint": { FlatESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(useFlatConfig) }, "./shared/logging": log }); @@ -1040,7 +1040,7 @@ describe("cli", () => { localCLI = proxyquire("../../lib/cli", { "./eslint": { ESLint: fakeESLint }, - "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) }, + "./eslint/flat-eslint": { FlatESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(useFlatConfig) }, "./shared/logging": log }); @@ -1076,7 +1076,7 @@ describe("cli", () => { localCLI = proxyquire("../../lib/cli", { "./eslint": { ESLint: fakeESLint }, - "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) }, + "./eslint/flat-eslint": { FlatESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(useFlatConfig) }, "./shared/logging": log }); @@ -1113,7 +1113,7 @@ describe("cli", () => { localCLI = proxyquire("../../lib/cli", { "./eslint": { ESLint: fakeESLint }, - "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) }, + "./eslint/flat-eslint": { FlatESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(useFlatConfig) }, "./shared/logging": log }); @@ -1131,12 +1131,12 @@ describe("cli", () => { localCLI = proxyquire("../../lib/cli", { "./eslint": { ESLint: fakeESLint }, - "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) }, + "./eslint/flat-eslint": { FlatESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(useFlatConfig) }, "./shared/logging": log }); - const exitCode = await localCLI.execute("--fix .", "foo = bar;", null, useFlatConfig); + const exitCode = await localCLI.execute("--fix .", "foo = bar;", useFlatConfig); assert.strictEqual(exitCode, 2); }); @@ -1162,7 +1162,7 @@ describe("cli", () => { localCLI = proxyquire("../../lib/cli", { "./eslint": { ESLint: fakeESLint }, - "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) }, + "./eslint/flat-eslint": { FlatESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(useFlatConfig) }, "./shared/logging": log }); @@ -1190,7 +1190,7 @@ describe("cli", () => { localCLI = proxyquire("../../lib/cli", { "./eslint": { ESLint: fakeESLint }, - "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) }, + "./eslint/flat-eslint": { FlatESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(useFlatConfig) }, "./shared/logging": log }); @@ -1225,7 +1225,7 @@ describe("cli", () => { localCLI = proxyquire("../../lib/cli", { "./eslint": { ESLint: fakeESLint }, - "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) }, + "./eslint/flat-eslint": { FlatESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(useFlatConfig) }, "./shared/logging": log }); @@ -1262,7 +1262,7 @@ describe("cli", () => { localCLI = proxyquire("../../lib/cli", { "./eslint": { ESLint: fakeESLint }, - "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) }, + "./eslint/flat-eslint": { FlatESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(useFlatConfig) }, "./shared/logging": log }); @@ -1298,7 +1298,7 @@ describe("cli", () => { localCLI = proxyquire("../../lib/cli", { "./eslint": { ESLint: fakeESLint }, - "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) }, + "./eslint/flat-eslint": { FlatESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(useFlatConfig) }, "./shared/logging": log }); @@ -1315,7 +1315,7 @@ describe("cli", () => { localCLI = proxyquire("../../lib/cli", { "./eslint": { ESLint: fakeESLint }, - "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) }, + "./eslint/flat-eslint": { FlatESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(useFlatConfig) }, "./shared/logging": log }); diff --git a/tests/lib/eslint/eslint.js b/tests/lib/eslint/eslint.js index ecd121d3fc3..91dd6b1b5a4 100644 --- a/tests/lib/eslint/eslint.js +++ b/tests/lib/eslint/eslint.js @@ -2993,6 +2993,105 @@ describe("ESLint", () => { assert.deepStrictEqual(result, cachedResult, "result should be the same with or without cache"); }); + // https://github.com/eslint/eslint/issues/13507 + it("should not store `usedDeprecatedRules` in the cache file", async () => { + cacheFilePath = getFixturePath(".eslintcache"); + doDelete(cacheFilePath); + assert(!shell.test("-f", cacheFilePath), "the cache file already exists and wasn't successfully deleted"); + + const deprecatedRuleId = "space-in-parens"; + + eslint = new ESLint({ + cwd: path.join(fixtureDir, ".."), + useEslintrc: false, + + // specifying cache true the cache will be created + cache: true, + cacheLocation: cacheFilePath, + overrideConfig: { + rules: { + [deprecatedRuleId]: 2 + } + } + }); + + const filePath = fs.realpathSync(getFixturePath("cache/src", "test-file.js")); + + /* + * Run linting on the same file 3 times to cover multiple cases: + * Run 1: Lint result wasn't already cached. + * Run 2: Lint result was already cached. The cached lint result is used but the cache is reconciled before the run ends. + * Run 3: Lint result was already cached. The cached lint result was being used throughout the previous run, so possible + * mutations in the previous run that occured after the cache was reconciled may have side effects for this run. + */ + for (let i = 0; i < 3; i++) { + const [result] = await eslint.lintFiles([filePath]); + + assert( + result.usedDeprecatedRules && result.usedDeprecatedRules.some(rule => rule.ruleId === deprecatedRuleId), + "the deprecated rule should have been in result.usedDeprecatedRules" + ); + + assert(shell.test("-f", cacheFilePath), "the cache for eslint should have been created"); + + const fileCache = fCache.create(cacheFilePath); + const descriptor = fileCache.getFileDescriptor(filePath); + + assert(typeof descriptor === "object", "an entry for the file should have been in the cache file"); + assert(typeof descriptor.meta.results === "object", "lint result for the file should have been in its cache entry in the cache file"); + assert(typeof descriptor.meta.results.usedDeprecatedRules === "undefined", "lint result in the cache file contains `usedDeprecatedRules`"); + } + + }); + + // https://github.com/eslint/eslint/issues/13507 + it("should store `source` as `null` in the cache file if the lint result has `source` property", async () => { + cacheFilePath = getFixturePath(".eslintcache"); + doDelete(cacheFilePath); + assert(!shell.test("-f", cacheFilePath), "the cache file already exists and wasn't successfully deleted"); + + eslint = new ESLint({ + cwd: path.join(fixtureDir, ".."), + useEslintrc: false, + + // specifying cache true the cache will be created + cache: true, + cacheLocation: cacheFilePath, + overrideConfig: { + rules: { + "no-unused-vars": 2 + } + } + }); + + const filePath = fs.realpathSync(getFixturePath("cache/src", "fail-file.js")); + + /* + * Run linting on the same file 3 times to cover multiple cases: + * Run 1: Lint result wasn't already cached. + * Run 2: Lint result was already cached. The cached lint result is used but the cache is reconciled before the run ends. + * Run 3: Lint result was already cached. The cached lint result was being used throughout the previous run, so possible + * mutations in the previous run that occured after the cache was reconciled may have side effects for this run. + */ + for (let i = 0; i < 3; i++) { + const [result] = await eslint.lintFiles([filePath]); + + assert(typeof result.source === "string", "the result should have contained the `source` property"); + + assert(shell.test("-f", cacheFilePath), "the cache for eslint should have been created"); + + const fileCache = fCache.create(cacheFilePath); + const descriptor = fileCache.getFileDescriptor(filePath); + + assert(typeof descriptor === "object", "an entry for the file should have been in the cache file"); + assert(typeof descriptor.meta.results === "object", "lint result for the file should have been in its cache entry in the cache file"); + + // if the lint result contains `source`, it should be stored as `null` in the cache file + assert.strictEqual(descriptor.meta.results.source, null, "lint result in the cache file contains non-null `source`"); + } + + }); + describe("cacheStrategy", () => { it("should detect changes using a file's modification time when set to 'metadata'", async () => { cacheFilePath = getFixturePath(".eslintcache"); diff --git a/tests/lib/eslint/flat-eslint.js b/tests/lib/eslint/flat-eslint.js index 9ce0bb146f4..bfa420ccf11 100644 --- a/tests/lib/eslint/flat-eslint.js +++ b/tests/lib/eslint/flat-eslint.js @@ -2876,6 +2876,105 @@ describe("FlatESLint", () => { assert.deepStrictEqual(result, cachedResult, "result should be the same with or without cache"); }); + // https://github.com/eslint/eslint/issues/13507 + it("should not store `usedDeprecatedRules` in the cache file", async () => { + cacheFilePath = getFixturePath(".eslintcache"); + doDelete(cacheFilePath); + assert(!shell.test("-f", cacheFilePath), "the cache file already exists and wasn't successfully deleted"); + + const deprecatedRuleId = "space-in-parens"; + + eslint = new FlatESLint({ + cwd: path.join(fixtureDir, ".."), + overrideConfigFile: true, + + // specifying cache true the cache will be created + cache: true, + cacheLocation: cacheFilePath, + overrideConfig: { + rules: { + [deprecatedRuleId]: 2 + } + } + }); + + const filePath = fs.realpathSync(getFixturePath("cache/src", "test-file.js")); + + /* + * Run linting on the same file 3 times to cover multiple cases: + * Run 1: Lint result wasn't already cached. + * Run 2: Lint result was already cached. The cached lint result is used but the cache is reconciled before the run ends. + * Run 3: Lint result was already cached. The cached lint result was being used throughout the previous run, so possible + * mutations in the previous run that occured after the cache was reconciled may have side effects for this run. + */ + for (let i = 0; i < 3; i++) { + const [result] = await eslint.lintFiles([filePath]); + + assert( + result.usedDeprecatedRules && result.usedDeprecatedRules.some(rule => rule.ruleId === deprecatedRuleId), + "the deprecated rule should have been in result.usedDeprecatedRules" + ); + + assert(shell.test("-f", cacheFilePath), "the cache for eslint should have been created"); + + const fileCache = fCache.create(cacheFilePath); + const descriptor = fileCache.getFileDescriptor(filePath); + + assert(typeof descriptor === "object", "an entry for the file should have been in the cache file"); + assert(typeof descriptor.meta.results === "object", "lint result for the file should have been in its cache entry in the cache file"); + assert(typeof descriptor.meta.results.usedDeprecatedRules === "undefined", "lint result in the cache file contains `usedDeprecatedRules`"); + } + + }); + + // https://github.com/eslint/eslint/issues/13507 + it("should store `source` as `null` in the cache file if the lint result has `source` property", 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, ".."), + overrideConfigFile: true, + + // specifying cache true the cache will be created + cache: true, + cacheLocation: cacheFilePath, + overrideConfig: { + rules: { + "no-unused-vars": 2 + } + } + }); + + const filePath = fs.realpathSync(getFixturePath("cache/src", "fail-file.js")); + + /* + * Run linting on the same file 3 times to cover multiple cases: + * Run 1: Lint result wasn't already cached. + * Run 2: Lint result was already cached. The cached lint result is used but the cache is reconciled before the run ends. + * Run 3: Lint result was already cached. The cached lint result was being used throughout the previous run, so possible + * mutations in the previous run that occured after the cache was reconciled may have side effects for this run. + */ + for (let i = 0; i < 3; i++) { + const [result] = await eslint.lintFiles([filePath]); + + assert(typeof result.source === "string", "the result should have contained the `source` property"); + + assert(shell.test("-f", cacheFilePath), "the cache for eslint should have been created"); + + const fileCache = fCache.create(cacheFilePath); + const descriptor = fileCache.getFileDescriptor(filePath); + + assert(typeof descriptor === "object", "an entry for the file should have been in the cache file"); + assert(typeof descriptor.meta.results === "object", "lint result for the file should have been in its cache entry in the cache file"); + + // if the lint result contains `source`, it should be stored as `null` in the cache file + assert.strictEqual(descriptor.meta.results.source, null, "lint result in the cache file contains non-null `source`"); + } + + }); + describe("cacheStrategy", () => { it("should detect changes using a file's modification time when set to 'metadata'", async () => { cacheFilePath = getFixturePath(".eslintcache"); diff --git a/tests/lib/linter/linter.js b/tests/lib/linter/linter.js index d06b901a6c2..c472437ab02 100644 --- a/tests/lib/linter/linter.js +++ b/tests/lib/linter/linter.js @@ -9831,6 +9831,117 @@ describe("Linter with FlatConfigArray", () => { }); }); + // https://github.com/eslint/eslint/issues/17669 + it("should use `cwd` constructor option as config `basePath` when config is not an instance of FlatConfigArray", () => { + const rule = { + create(context) { + return { + Program(node) { + context.report({ node, message: "Bad program." }); + } + }; + } + }; + + const code = "foo"; + const config = [ + { + plugins: { + test: { + rules: { + "test-rule-1": rule, + "test-rule-2": rule, + "test-rule-3": rule + } + } + } + }, + { + rules: { + "test/test-rule-1": 2 + } + }, + { + files: ["**/*.ts"], + rules: { + "test/test-rule-2": 2 + } + }, + { + files: ["bar/file.ts"], + rules: { + "test/test-rule-3": 2 + } + } + ]; + + const linterWithOptions = new Linter({ + configType: "flat", + cwd: "/foo" + }); + + let messages; + + messages = linterWithOptions.verify(code, config, "/file.js"); + assert.strictEqual(messages.length, 1); + assert.deepStrictEqual(messages[0], { + ruleId: null, + severity: 1, + message: "No matching configuration found for /file.js.", + line: 0, + column: 0, + nodeType: null + }); + + messages = linterWithOptions.verify(code, config, "/file.ts"); + assert.strictEqual(messages.length, 1); + assert.deepStrictEqual(messages[0], { + ruleId: null, + severity: 1, + message: "No matching configuration found for /file.ts.", + line: 0, + column: 0, + nodeType: null + }); + + messages = linterWithOptions.verify(code, config, "/bar/foo/file.js"); + assert.strictEqual(messages.length, 1); + assert.deepStrictEqual(messages[0], { + ruleId: null, + severity: 1, + message: "No matching configuration found for /bar/foo/file.js.", + line: 0, + column: 0, + nodeType: null + }); + + messages = linterWithOptions.verify(code, config, "/bar/foo/file.ts"); + assert.strictEqual(messages.length, 1); + assert.deepStrictEqual(messages[0], { + ruleId: null, + severity: 1, + message: "No matching configuration found for /bar/foo/file.ts.", + line: 0, + column: 0, + nodeType: null + }); + + messages = linterWithOptions.verify(code, config, "/foo/file.js"); + assert.strictEqual(messages.length, 1); + assert.strictEqual(messages[0].ruleId, "test/test-rule-1"); + + messages = linterWithOptions.verify(code, config, "/foo/file.ts"); + assert.strictEqual(messages.length, 2); + assert.strictEqual(messages[0].ruleId, "test/test-rule-1"); + assert.strictEqual(messages[1].ruleId, "test/test-rule-2"); + + messages = linterWithOptions.verify(code, config, "/foo/bar/file.ts"); + assert.strictEqual(messages.length, 3); + assert.strictEqual(messages[0].ruleId, "test/test-rule-1"); + assert.strictEqual(messages[1].ruleId, "test/test-rule-2"); + assert.strictEqual(messages[2].ruleId, "test/test-rule-3"); + }); + describe("Plugins", () => { it("should not load rule definition when rule isn't used", () => { @@ -11976,7 +12087,7 @@ describe("Linter with FlatConfigArray", () => { ...baseConfig }; - linterWithOption.verify(code, config); + linterWithOption.verify(code, config, `${cwd}/file.js`); assert(spy && spy.calledOnce); }); @@ -12059,7 +12170,7 @@ describe("Linter with FlatConfigArray", () => { ...baseConfig }; - linterWithOption.verify(code, config); + linterWithOption.verify(code, config, `${cwd}/file.js`); assert(spy && spy.calledOnce); }); diff --git a/tests/lib/rules/for-direction.js b/tests/lib/rules/for-direction.js index 6e59f6bacf4..630f89df54d 100644 --- a/tests/lib/rules/for-direction.js +++ b/tests/lib/rules/for-direction.js @@ -28,6 +28,12 @@ ruleTester.run("for-direction", rule, { "for(var i = 10; i > 0; i--){}", "for(var i = 10; i >= 0; i--){}", + // test if '++', '--' with counter 'i' on the right side of test condition + "for(var i = 0; 10 > i; i++){}", + "for(var i = 0; 10 >= i; i++){}", + "for(var i = 10; 0 < i; i--){}", + "for(var i = 10; 0 <= i; i--){}", + // test if '+=', '-=', "for(var i = 0; i < 10; i+=1){}", "for(var i = 0; i <= 10; i+=1){}", @@ -44,6 +50,9 @@ ruleTester.run("for-direction", rule, { "for(var i = 0; i < MAX; i -= ~2);", "for(var i = 0, n = -1; i < MAX; i += -n);", + // test if '+=', '-=' with counter 'i' on the right side of test condition + "for(var i = 0; 10 > i; i+=1){}", + // test if no update. "for(var i = 10; i > 0;){}", "for(var i = 10; i >= 0;){}", @@ -82,6 +91,12 @@ ruleTester.run("for-direction", rule, { { code: "for(var i = 10; i > 10; i++){}", errors: [incorrectDirection] }, { code: "for(var i = 10; i >= 0; i++){}", errors: [incorrectDirection] }, + // test if '++', '--' with counter 'i' on the right side of test condition + { code: "for(var i = 0; 10 > i; i--){}", errors: [incorrectDirection] }, + { code: "for(var i = 0; 10 >= i; i--){}", errors: [incorrectDirection] }, + { code: "for(var i = 10; 10 < i; i++){}", errors: [incorrectDirection] }, + { code: "for(var i = 10; 0 <= i; i++){}", errors: [incorrectDirection] }, + // test if '+=', '-=' { code: "for(var i = 0; i < 10; i-=1){}", errors: [incorrectDirection] }, { code: "for(var i = 0; i <= 10; i-=1){}", errors: [incorrectDirection] }, @@ -96,6 +111,9 @@ ruleTester.run("for-direction", rule, { { code: "for(var i = MIN; i <= MAX; i-=true){}", errors: [incorrectDirection] }, { code: "for(var i = 0; i < 10; i-=+5e-7){}", errors: [incorrectDirection] }, { code: "for(var i = 0; i < MAX; i += (2 - 3));", errors: [incorrectDirection] }, - { code: "var n = -2; for(var i = 0; i < 10; i += n);", errors: [incorrectDirection] } + { code: "var n = -2; for(var i = 0; i < 10; i += n);", errors: [incorrectDirection] }, + + // test if '+=', '-=' with counter 'i' on the right side of test condition + { code: "for(var i = 0; 10 > i; i-=1){}", errors: [incorrectDirection] } ] }); diff --git a/tests/lib/rules/no-array-constructor.js b/tests/lib/rules/no-array-constructor.js index 70caeb8c844..07d0b650a69 100644 --- a/tests/lib/rules/no-array-constructor.js +++ b/tests/lib/rules/no-array-constructor.js @@ -16,7 +16,7 @@ const rule = require("../../../lib/rules/no-array-constructor"), // Tests //------------------------------------------------------------------------------ -const ruleTester = new RuleTester(); +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); ruleTester.run("no-array-constructor", rule, { valid: [ @@ -27,12 +27,383 @@ ruleTester.run("no-array-constructor", rule, { "new foo.Array()", "foo.Array()", "new Array.foo", - "Array.foo()" + "Array.foo()", + "new globalThis.Array", + "const createArray = Array => new Array()", + "var Array; new Array;", + { + code: "new Array()", + globals: { + Array: "off" + } + } ], invalid: [ - { code: "new Array()", errors: [{ messageId: "preferLiteral", type: "NewExpression" }] }, - { code: "new Array", errors: [{ messageId: "preferLiteral", type: "NewExpression" }] }, - { code: "new Array(x, y)", errors: [{ messageId: "preferLiteral", type: "NewExpression" }] }, - { code: "new Array(0, 1, 2)", errors: [{ messageId: "preferLiteral", type: "NewExpression" }] } + { + code: "new Array()", + errors: [{ + messageId: "preferLiteral", + type: "NewExpression", + suggestions: [{ + messageId: "useLiteral", + output: "[]" + }] + }] + }, + { + code: "new Array", + errors: + [{ + messageId: "preferLiteral", + type: "NewExpression", + suggestions: [{ + messageId: "useLiteral", + output: "[]" + }] + }] + }, + { + code: "new Array(x, y)", + errors: [{ + messageId: "preferLiteral", + type: "NewExpression", + suggestions: [{ + messageId: "useLiteral", + output: "[x, y]" + }] + }] + }, + { + code: "new Array(0, 1, 2)", + errors: [{ + messageId: "preferLiteral", + type: "NewExpression", + suggestions: [{ + messageId: "useLiteral", + output: "[0, 1, 2]" + }] + }] + }, + { + code: "const array = Array?.();", + errors: [{ + messageId: "preferLiteral", + type: "CallExpression", + suggestions: [{ + messageId: "useLiteral", + output: "const array = [];" + }] + }] + }, + { + code: ` + const array = (Array)( + /* foo */ a, + b = c() // bar + ); + `, + errors: [{ + messageId: "preferLiteral", + type: "CallExpression", + suggestions: [{ + messageId: "useLiteral", + output: ` + const array = [ + /* foo */ a, + b = c() // bar + ]; + ` + }] + }] + }, + { + code: "const array = Array(...args);", + errors: [{ + messageId: "preferLiteral", + type: "CallExpression", + suggestions: [{ + messageId: "useLiteral", + output: "const array = [...args];" + }] + }] + }, + { + code: "a = new (Array);", + errors: [{ + messageId: "preferLiteral", + type: "NewExpression", + suggestions: [{ + messageId: "useLiteral", + output: "a = [];" + }] + }] + }, + { + code: "a = new (Array) && (foo);", + errors: [{ + messageId: "preferLiteral", + type: "NewExpression", + suggestions: [{ + messageId: "useLiteral", + output: "a = [] && (foo);" + }] + }] + }, + + ...[ + + // Semicolon required before array literal to compensate for ASI + { + code: ` + foo + Array() + ` + }, + { + code: ` + foo() + Array(bar, baz) + ` + }, + { + code: ` + new foo + Array() + ` + }, + { + code: ` + (a++) + Array() + ` + }, + { + code: ` + ++a + Array() + ` + }, + { + code: ` + const foo = function() {} + Array() + ` + }, + { + code: ` + const foo = class {} + Array("a", "b", "c") + ` + }, + { + code: ` + foo = this.return + Array() + ` + }, + { + code: ` + var yield = bar.yield + Array() + ` + }, + { + code: ` + var foo = { bar: baz } + Array() + ` + }, + { + code: ` + + Array() + `, + parserOptions: { ecmaFeatures: { jsx: true } } + }, + { + code: ` + + Array() + `, + parserOptions: { ecmaFeatures: { jsx: true } } + } + ].map(props => ({ + ...props, + errors: [{ + messageId: "preferLiteral", + suggestions: [{ + desc: "Replace with an array literal, add preceding semicolon.", + messageId: "useLiteralAfterSemicolon", + output: props.code.replace(/(new )?Array\((?.*?)\)/su, ";[$]") + }] + }] + })), + + ...[ + + // No semicolon required before array literal because ASI does not occur + { code: "Array()" }, + { + code: ` + {} + Array() + ` + }, + { + code: ` + function foo() {} + Array() + ` + }, + { + code: ` + class Foo {} + Array() + ` + }, + { code: "foo: Array();" }, + { code: "foo();Array();" }, + { code: "{ Array(); }" }, + { code: "if (a) Array();" }, + { code: "if (a); else Array();" }, + { code: "while (a) Array();" }, + { + code: ` + do Array(); + while (a); + ` + }, + { code: "for (let i = 0; i < 10; i++) Array();" }, + { code: "for (const prop in obj) Array();" }, + { code: "for (const element of iterable) Array();" }, + { code: "with (obj) Array();" }, + + // No semicolon required before array literal because ASI still occurs + { + code: ` + const foo = () => {} + Array() + ` + }, + { + code: ` + a++ + Array() + ` + }, + { + code: ` + a-- + Array() + ` + }, + { + code: ` + function foo() { + return + Array(); + } + ` + }, + { + code: ` + function * foo() { + yield + Array(); + } + ` + }, + { + code: ` + do {} + while (a) + Array() + ` + }, + { + code: ` + debugger + Array() + ` + }, + { + code: ` + for (;;) { + break + Array() + } + ` + }, + { + code: ` + for (;;) { + continue + Array() + } + ` + }, + { + code: ` + foo: break foo + Array() + ` + }, + { + code: ` + foo: while (true) continue foo + Array() + ` + }, + { + code: ` + const foo = bar + export { foo } + Array() + `, + parserOptions: { sourceType: "module" } + }, + { + code: ` + export { foo } from 'bar' + Array() + `, + parserOptions: { sourceType: "module" } + }, + { + code: ` + export * as foo from 'bar' + Array() + `, + parserOptions: { sourceType: "module" } + }, + { + code: ` + import foo from 'bar' + Array() + `, + parserOptions: { sourceType: "module" } + }, + { + code: ` + var yield = 5; + + yield: while (foo) { + if (bar) + break yield + new Array(); + } + ` + } + ].map(props => ({ + ...props, + errors: [{ + messageId: "preferLiteral", + suggestions: [{ + desc: "Replace with an array literal.", + messageId: "useLiteral", + output: props.code.replace(/(new )?Array\((?.*?)\)/su, "[$]") + }] + }] + })) ] }); diff --git a/tests/lib/rules/no-console.js b/tests/lib/rules/no-console.js index d1c9176d0ff..d55cf5c2d58 100644 --- a/tests/lib/rules/no-console.js +++ b/tests/lib/rules/no-console.js @@ -40,24 +40,388 @@ ruleTester.run("no-console", rule, { invalid: [ // no options - { code: "console.log(foo)", errors: [{ messageId: "unexpected", type: "MemberExpression" }] }, - { code: "console.error(foo)", errors: [{ messageId: "unexpected", type: "MemberExpression" }] }, - { code: "console.info(foo)", errors: [{ messageId: "unexpected", type: "MemberExpression" }] }, - { code: "console.warn(foo)", errors: [{ messageId: "unexpected", type: "MemberExpression" }] }, + { + code: "if (a) console.warn(foo)", + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: null + }] + }, + { + code: "foo(console.log)", + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: null + }] + }, + { + code: "console.log(foo)", + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "log" }, + output: "" + }] + }] + }, + { + code: "console.error(foo)", + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "error" }, + output: "" + }] + }] + }, + { + code: "console.info(foo)", + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "info" }, + output: "" + }] + }] + }, + { + code: "console.warn(foo)", + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "warn" }, + output: "" + }] + }] + }, + { + code: "switch (a) { case 1: console.log(foo) }", + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "log" }, + output: "switch (a) { case 1: }" + }] + }] + }, + { + code: "if (a) { console.warn(foo) }", + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "warn" }, + output: "if (a) { }" + }] + }] + }, + { + code: "a();\nconsole.log(foo);\nb();", + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "log" }, + output: "a();\n\nb();" + }] + }] + }, + { + code: "class A { static { console.info(foo) } }", + parserOptions: { ecmaVersion: "latest" }, + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "info" }, + output: "class A { static { } }" + }] + }] + }, + { + code: "a()\nconsole.log(foo);\n[1, 2, 3].forEach(a => doSomething(a))", + parserOptions: { ecmaVersion: "latest" }, + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: null + }] + }, + { + code: "a++\nconsole.log();\n/b/", + parserOptions: { ecmaVersion: "latest" }, + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: null + }] + }, + { + code: "a();\nconsole.log(foo);\n[1, 2, 3].forEach(a => doSomething(a));", + parserOptions: { ecmaVersion: "latest" }, + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "log" }, + output: "a();\n\n[1, 2, 3].forEach(a => doSomething(a));" + }] + }] + }, // one option - { code: "console.log(foo)", options: [{ allow: ["error"] }], errors: [{ messageId: "unexpected", type: "MemberExpression" }] }, - { code: "console.error(foo)", options: [{ allow: ["warn"] }], errors: [{ messageId: "unexpected", type: "MemberExpression" }] }, - { code: "console.info(foo)", options: [{ allow: ["log"] }], errors: [{ messageId: "unexpected", type: "MemberExpression" }] }, - { code: "console.warn(foo)", options: [{ allow: ["error"] }], errors: [{ messageId: "unexpected", type: "MemberExpression" }] }, + { + code: "if (a) console.info(foo)", + options: [{ allow: ["warn"] }], + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: null + }] + }, + { + code: "foo(console.warn)", + options: [{ allow: ["log"] }], + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: null + }] + }, + { + code: "console.log(foo)", + options: [{ allow: ["error"] }], + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "log" }, + output: "" + }] + }] + }, + { + code: "console.error(foo)", + options: [{ allow: ["warn"] }], + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "error" }, + output: "" + }] + }] + }, + { + code: "console.info(foo)", + options: [{ allow: ["log"] }], + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "info" }, + output: "" + }] + }] + }, + { + code: "console.warn(foo)", + options: [{ allow: ["error"] }], + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "warn" }, + output: "" + }] + }] + }, + { + code: "switch (a) { case 1: console.log(foo) }", + options: [{ allow: ["error"] }], + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "log" }, + output: "switch (a) { case 1: }" + }] + }] + }, + { + code: "if (a) { console.info(foo) }", + options: [{ allow: ["warn"] }], + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "info" }, + output: "if (a) { }" + }] + }] + }, + { + code: "class A { static { console.error(foo) } }", + options: [{ allow: ["log"] }], + parserOptions: { ecmaVersion: "latest" }, + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "error" }, + output: "class A { static { } }" + }] + }] + }, // multiple options - { code: "console.log(foo)", options: [{ allow: ["warn", "info"] }], errors: [{ messageId: "unexpected", type: "MemberExpression" }] }, - { code: "console.error(foo)", options: [{ allow: ["warn", "info", "log"] }], errors: [{ messageId: "unexpected", type: "MemberExpression" }] }, - { code: "console.info(foo)", options: [{ allow: ["warn", "error", "log"] }], errors: [{ messageId: "unexpected", type: "MemberExpression" }] }, - { code: "console.warn(foo)", options: [{ allow: ["info", "log"] }], errors: [{ messageId: "unexpected", type: "MemberExpression" }] }, + { + code: "if (a) console.log(foo)", + options: [{ allow: ["warn", "error"] }], + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: null + }] + }, + { + code: "foo(console.info)", + options: [{ allow: ["warn", "error"] }], + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: null + }] + }, + { + code: "console.log(foo)", + options: [{ allow: ["warn", "info"] }], + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "log" }, + output: "" + }] + }] + }, + { + code: "console.error(foo)", + options: [{ allow: ["warn", "info", "log"] }], + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "error" }, + output: "" + }] + }] + }, + { + code: "console.info(foo)", + options: [{ allow: ["warn", "error", "log"] }], + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "info" }, + output: "" + }] + }] + }, + { + code: "console.warn(foo)", + options: [{ allow: ["info", "log"] }], + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "warn" }, + output: "" + }] + }] + }, + { + code: "switch (a) { case 1: console.error(foo) }", + options: [{ allow: ["info", "log"] }], + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "error" }, + output: "switch (a) { case 1: }" + }] + }] + }, + { + code: "if (a) { console.log(foo) }", + options: [{ allow: ["warn", "error"] }], + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "log" }, + output: "if (a) { }" + }] + }] + }, + { + code: "class A { static { console.info(foo) } }", + options: [{ allow: ["log", "error", "warn"] }], + parserOptions: { ecmaVersion: "latest" }, + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "info" }, + output: "class A { static { } }" + }] + }] + }, // In case that implicit global variable of 'console' exists - { code: "console.log(foo)", env: { node: true }, errors: [{ messageId: "unexpected", type: "MemberExpression" }] } + { + code: "console.log(foo)", + env: { node: true }, + errors: [{ + messageId: "unexpected", + type: "MemberExpression", + suggestions: [{ + messageId: "removeConsole", + data: { propertyName: "log" }, + output: "" + }] + }] + } ] }); diff --git a/tests/lib/rules/no-restricted-imports.js b/tests/lib/rules/no-restricted-imports.js index 5403812de36..b756770d686 100644 --- a/tests/lib/rules/no-restricted-imports.js +++ b/tests/lib/rules/no-restricted-imports.js @@ -282,6 +282,99 @@ ruleTester.run("no-restricted-imports", rule, { importNames: ["Foo"] }] }] + }, + { + code: "import Foo from 'foo';", + options: [{ + patterns: [{ + group: ["foo"], + importNamePattern: "^Foo" + }] + }] + }, + { + code: "import Foo from 'foo';", + options: [{ + patterns: [{ + importNames: ["Foo"], + group: ["foo"], + importNamePattern: "^Foo" + }] + }] + }, + { + code: "import Foo from '../../my/relative-module';", + options: [{ + patterns: [{ + group: ["**/my/relative-module"], + importNamePattern: "^Foo" + }] + }] + }, + { + code: "import { Bar } from '../../my/relative-module';", + options: [{ + patterns: [{ + group: ["**/my/relative-module"], + importNamePattern: "^Foo" + }] + }] + }, + { + code: "import { Bar as Foo } from '../../my/relative-module';", + options: [{ + patterns: [{ + group: ["**/my/relative-module"], + importNamePattern: "^Foo" + }] + }] + }, + { + code: "import { Bar as Foo } from '../../my/relative-module';", + options: [{ + patterns: [{ + importNames: ["Foo"], + group: ["**/my/relative-module"], + importNamePattern: "^Foo" + }] + }] + }, + { + code: "import Foo, { Baz as Bar } from '../../my/relative-module';", + options: [{ + patterns: [{ + group: ["**/my/relative-module"], + importNamePattern: "^(Foo|Bar)" + }] + }] + }, + { + code: "import Foo, { Baz as Bar } from '../../my/relative-module';", + options: [{ + patterns: [{ + importNames: ["Foo"], + group: ["**/my/relative-module"], + importNamePattern: "^Bar" + }] + }] + }, + { + code: "export { Bar } from 'foo';", + options: [{ + patterns: [{ + group: ["foo"], + importNamePattern: "^Foo" + }] + }] + }, + { + code: "export { Bar as Foo } from 'foo';", + options: [{ + patterns: [{ + group: ["foo"], + importNamePattern: "^Foo" + }] + }] } ], invalid: [{ @@ -1235,6 +1328,353 @@ ruleTester.run("no-restricted-imports", rule, { endColumn: 11, message: "'default' import from 'mod' is restricted from being used by a pattern." }] + }, + { + code: "import { Foo } from 'foo';", + options: [{ + patterns: [{ + group: ["foo"], + importNamePattern: "^Foo" + }] + }], + errors: [{ + type: "ImportDeclaration", + line: 1, + column: 10, + endColumn: 13, + message: "'Foo' import from 'foo' is restricted from being used by a pattern." + }] + }, + { + code: "import { Foo as Bar } from 'foo';", + options: [{ + patterns: [{ + group: ["foo"], + importNamePattern: "^Foo" + }] + }], + errors: [{ + type: "ImportDeclaration", + line: 1, + column: 10, + endColumn: 20, + message: "'Foo' import from 'foo' is restricted from being used by a pattern." + }] + }, + { + code: "import Foo, { Bar } from 'foo';", + options: [{ + patterns: [{ + group: ["foo"], + importNamePattern: "^(Foo|Bar)" + }] + }], + errors: [{ + type: "ImportDeclaration", + line: 1, + column: 15, + endColumn: 18, + message: "'Bar' import from 'foo' is restricted from being used by a pattern." + }] + }, + { + code: "import { Foo } from '../../my/relative-module';", + options: [{ + patterns: [{ + group: ["**/my/relative-module"], + importNamePattern: "^Foo" + }] + }], + errors: [{ + type: "ImportDeclaration", + line: 1, + column: 10, + endColumn: 13, + message: "'Foo' import from '../../my/relative-module' is restricted from being used by a pattern." + }] + }, + { + code: "import { FooBar } from '../../my/relative-module';", + options: [{ + patterns: [{ + group: ["**/my/relative-module"], + importNamePattern: "^Foo" + }] + }], + errors: [{ + type: "ImportDeclaration", + line: 1, + column: 10, + endColumn: 16, + message: "'FooBar' import from '../../my/relative-module' is restricted from being used by a pattern." + }] + }, + { + code: "import Foo, { Bar } from '../../my/relative-module';", + options: [{ + patterns: [{ + group: ["**/my/relative-module"], + importNamePattern: "^Foo|^Bar" + }] + }], + errors: [{ + type: "ImportDeclaration", + line: 1, + column: 15, + endColumn: 18, + message: "'Bar' import from '../../my/relative-module' is restricted from being used by a pattern." + }] + }, + { + code: "import { Foo, Bar } from '../../my/relative-module';", + options: [{ + patterns: [{ + group: ["**/my/relative-module"], + importNamePattern: "^(Foo|Bar)" + }] + }], + errors: [ + { + type: "ImportDeclaration", + line: 1, + column: 10, + endColumn: 13, + message: "'Foo' import from '../../my/relative-module' is restricted from being used by a pattern." + }, + { + type: "ImportDeclaration", + line: 1, + column: 15, + endColumn: 18, + message: "'Bar' import from '../../my/relative-module' is restricted from being used by a pattern." + } + ] + }, + { + code: "import * as Foo from 'foo';", + options: [{ + patterns: [{ + group: ["foo"], + importNamePattern: "^Foo" + }] + }], + errors: [{ + message: "* import is invalid because import name matching '/^Foo/u' pattern from 'foo' is restricted from being used.", + type: "ImportDeclaration", + line: 1, + column: 8, + endColumn: 16 + }] + }, + { + code: "import * as All from '../../my/relative-module';", + options: [{ + patterns: [{ + group: ["**/my/relative-module"], + importNamePattern: "^Foo" + }] + }], + errors: [{ + message: "* import is invalid because import name matching '/^Foo/u' pattern from '../../my/relative-module' is restricted from being used.", + type: "ImportDeclaration", + line: 1, + column: 8, + endColumn: 16 + }] + }, + { + code: "import * as AllWithCustomMessage from '../../my/relative-module';", + options: [{ + patterns: [{ + group: ["**/my/relative-module"], + importNamePattern: "^Foo", + message: "Import from @/utils instead." + }] + }], + errors: [{ + message: "* import is invalid because import name matching '/^Foo/u' pattern from '../../my/relative-module' is restricted from being used. Import from @/utils instead.", + type: "ImportDeclaration", + line: 1, + column: 8, + endColumn: 33 + }] + }, + { + code: "import * as AllWithCustomMessage from '../../my/relative-module';", + options: [{ + patterns: [{ + importNames: ["Foo"], + group: ["**/my/relative-module"], + importNamePattern: "^Foo", + message: "Import from @/utils instead." + }] + }], + errors: [{ + message: "* import is invalid because 'Foo' from '../../my/relative-module' is restricted from being used by a pattern. Import from @/utils instead.", + type: "ImportDeclaration", + line: 1, + column: 8, + endColumn: 33 + }] + }, + { + code: "import { Foo } from '../../my/relative-module';", + options: [{ + patterns: [{ + importNames: ["Foo"], + group: ["**/my/relative-module"], + importNamePattern: "^Foo" + }] + }], + errors: [{ + type: "ImportDeclaration", + line: 1, + column: 10, + endColumn: 13, + message: "'Foo' import from '../../my/relative-module' is restricted from being used by a pattern." + }] + }, + { + code: "import { Foo } from '../../my/relative-module';", + options: [{ + patterns: [{ + importNames: ["Foo", "Bar"], + group: ["**/my/relative-module"], + importNamePattern: "^Foo" + }] + }], + errors: [{ + type: "ImportDeclaration", + line: 1, + column: 10, + endColumn: 13, + message: "'Foo' import from '../../my/relative-module' is restricted from being used by a pattern." + }] + }, + { + code: "import { Foo } from '../../my/relative-module';", + options: [{ + patterns: [{ + importNames: ["Bar"], + group: ["**/my/relative-module"], + importNamePattern: "^Foo" + }] + }], + errors: [{ + type: "ImportDeclaration", + line: 1, + column: 10, + endColumn: 13, + message: "'Foo' import from '../../my/relative-module' is restricted from being used by a pattern." + }] + }, + { + code: "import { Foo } from '../../my/relative-module';", + options: [{ + patterns: [{ + importNames: ["Foo"], + group: ["**/my/relative-module"], + importNamePattern: "^Bar" + }] + }], + errors: [{ + type: "ImportDeclaration", + line: 1, + column: 10, + endColumn: 13, + message: "'Foo' import from '../../my/relative-module' is restricted from being used by a pattern." + }] + }, + { + code: "import { Foo, Bar } from '../../my/relative-module';", + options: [{ + patterns: [{ + importNames: ["Foo"], + group: ["**/my/relative-module"], + importNamePattern: "^Bar" + }] + }], + errors: [ + { + type: "ImportDeclaration", + line: 1, + column: 10, + endColumn: 13, + message: "'Foo' import from '../../my/relative-module' is restricted from being used by a pattern." + }, + { + type: "ImportDeclaration", + line: 1, + column: 15, + endColumn: 18, + message: "'Bar' import from '../../my/relative-module' is restricted from being used by a pattern." + } + ] + }, + { + code: "export { Foo } from 'foo';", + options: [{ + patterns: [{ + group: ["foo"], + importNamePattern: "^Foo" + }] + }], + errors: [{ + type: "ExportNamedDeclaration", + line: 1, + column: 10, + endColumn: 13, + message: "'Foo' import from 'foo' is restricted from being used by a pattern." + }] + }, + { + code: "export { Foo as Bar } from 'foo';", + options: [{ + patterns: [{ + group: ["foo"], + importNamePattern: "^Foo" + }] + }], + errors: [{ + type: "ExportNamedDeclaration", + line: 1, + column: 10, + endColumn: 20, + message: "'Foo' import from 'foo' is restricted from being used by a pattern." + }] + }, + { + code: "export { Foo } from 'foo';", + options: [{ + patterns: [{ + importNames: ["Bar"], + group: ["foo"], + importNamePattern: "^Foo" + }] + }], + errors: [{ + type: "ExportNamedDeclaration", + line: 1, + column: 10, + endColumn: 13, + message: "'Foo' import from 'foo' is restricted from being used by a pattern." + }] + }, + { + code: "export * from 'foo';", + options: [{ + patterns: [{ + group: ["foo"], + importNamePattern: "^Foo" + }] + }], + errors: [{ + type: "ExportAllDeclaration", + line: 1, + column: 8, + endColumn: 9, + message: "* import is invalid because import name matching '/^Foo/u' pattern from 'foo' is restricted from being used." + }] } ] }); diff --git a/tests/tools/check-rule-examples.js b/tests/tools/check-rule-examples.js new file mode 100644 index 00000000000..10741c3dd02 --- /dev/null +++ b/tests/tools/check-rule-examples.js @@ -0,0 +1,95 @@ +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const assert = require("assert"); +const { execFile } = require("child_process"); +const { promisify } = require("util"); + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +/** + * Runs check-rule-examples on the specified files. + * @param {...string} filenames Files to be passed to check-rule-examples. + * @returns {Promise} An object with properties `stdout` and `stderr` on success. + * @throws An object with properties `code`, `stdout` and `stderr` on success. + */ +async function runCheckRuleExamples(...filenames) { + return await promisify(execFile)( + process.execPath, + ["--no-deprecation", "tools/check-rule-examples.js", ...filenames], + { env: { FORCE_COLOR: "3" } } // 24-bit color mode + ); +} + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +describe("check-rule-examples", () => { + + it("succeeds when not passed any files", async () => { + const childProcess = await runCheckRuleExamples(); + + assert.strictEqual(childProcess.stdout, ""); + assert.strictEqual(childProcess.stderr, ""); + }); + + it("succeeds when passed a syntax error free file", async () => { + const childProcess = await runCheckRuleExamples("tests/fixtures/good-examples.md"); + + assert.strictEqual(childProcess.stdout, ""); + assert.strictEqual(childProcess.stderr, ""); + }); + + it("fails when passed a file with a syntax error", async () => { + const promise = runCheckRuleExamples("tests/fixtures/good-examples.md", "tests/fixtures/bad-examples.md"); + + await assert.rejects( + promise, + { + code: 1, + stdout: "", + stderr: + "\x1B[0m\x1B[0m\n" + + "\x1B[0m\x1B[4mtests/fixtures/bad-examples.md\x1B[24m\x1B[0m\n" + + "\x1B[0m \x1B[2m11:4\x1B[22m \x1B[31merror\x1B[39m Missing language tag: use one of 'javascript', 'js' or 'jsx'\x1B[0m\n" + + "\x1B[0m \x1B[2m12:1\x1B[22m \x1B[31merror\x1B[39m Syntax error: 'import' and 'export' may appear only with 'sourceType: module'\x1B[0m\n" + + "\x1B[0m \x1B[2m20:5\x1B[22m \x1B[31merror\x1B[39m Nonstandard language tag 'ts': use one of 'javascript', 'js' or 'jsx'\x1B[0m\n" + + "\x1B[0m \x1B[2m23:7\x1B[22m \x1B[31merror\x1B[39m Syntax error: Identifier 'foo' has already been declared\x1B[0m\n" + + "\x1B[0m\x1B[0m\n" + + "\x1B[0m\x1B[31m\x1B[1m✖ 4 problems (4 errors, 0 warnings)\x1B[22m\x1B[39m\x1B[0m\n" + + "\x1B[0m\x1B[31m\x1B[1m\x1B[22m\x1B[39m\x1B[0m\n" + } + ); + }); + + it("fails when a file cannot be processed", async () => { + const promise = runCheckRuleExamples("tests/fixtures/non-existing-examples.md"); + + await assert.rejects( + promise, + ({ code, stdout, stderr }) => { + assert.strictEqual(code, 1); + assert.strictEqual(stdout, ""); + const expectedStderr = + "\x1B[0m\x1B[0m\n" + + "\x1B[0m\x1B[4mtests/fixtures/non-existing-examples.md\x1B[24m\x1B[0m\n" + + "\x1B[0m \x1B[2m0:0\x1B[22m \x1B[31merror\x1B[39m Error checking file: ENOENT: no such file or directory, open \x1B[0m\n" + + "\x1B[0m\x1B[0m\n" + + "\x1B[0m\x1B[31m\x1B[1m✖ 1 problem (1 error, 0 warnings)\x1B[22m\x1B[39m\x1B[0m\n" + + "\x1B[0m\x1B[31m\x1B[1m\x1B[22m\x1B[39m\x1B[0m\n"; + + // Replace filename as it's OS-dependent. + const normalizedStderr = stderr.replace(/'.+'/u, ""); + + assert.strictEqual(normalizedStderr, expectedStderr); + return true; + } + ); + }); +}); diff --git a/tools/check-rule-examples.js b/tools/check-rule-examples.js new file mode 100644 index 00000000000..d4df4ef9cfb --- /dev/null +++ b/tools/check-rule-examples.js @@ -0,0 +1,150 @@ +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const { parse } = require("espree"); +const { readFile } = require("fs").promises; +const glob = require("glob"); +const markdownIt = require("markdown-it"); +const markdownItContainer = require("markdown-it-container"); +const { promisify } = require("util"); +const markdownItRuleExample = require("../docs/tools/markdown-it-rule-example"); + +//------------------------------------------------------------------------------ +// Typedefs +//------------------------------------------------------------------------------ + +/** @typedef {import("../lib/shared/types").LintMessage} LintMessage */ +/** @typedef {import("../lib/shared/types").LintResult} LintResult */ +/** @typedef {import("../lib/shared/types").ParserOptions} ParserOptions */ + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +const STANDARD_LANGUAGE_TAGS = new Set(["javascript", "js", "jsx"]); + +/** + * Tries to parse a specified JavaScript code with Playground presets. + * @param {string} code The JavaScript code to parse. + * @param {ParserOptions} parserOptions Explicitly specified parser options. + * @returns {SyntaxError | null} A `SyntaxError` object if the code cannot be parsed, or `null`. + */ +function tryParseForPlayground(code, parserOptions) { + try { + parse(code, { ecmaVersion: "latest", ...parserOptions }); + } catch (error) { + return error; + } + return null; +} + +/** + * Checks the example code blocks in a rule documentation file. + * @param {string} filename The file to be checked. + * @returns {Promise} A promise of problems found. The promise will be rejected if an error occurs. + */ +async function findProblems(filename) { + const text = await readFile(filename, "UTF-8"); + const problems = []; + const ruleExampleOptions = markdownItRuleExample({ + open({ code, parserOptions, codeBlockToken }) { + const languageTag = codeBlockToken.info; + + if (!STANDARD_LANGUAGE_TAGS.has(languageTag)) { + + /* + * Missing language tags are also reported by Markdownlint rule MD040 for all code blocks, + * but the message we output here is more specific. + */ + const message = `${languageTag + ? `Nonstandard language tag '${languageTag}'` + : "Missing language tag"}: use one of 'javascript', 'js' or 'jsx'`; + + problems.push({ + fatal: false, + severity: 2, + message, + line: codeBlockToken.map[0] + 1, + column: codeBlockToken.markup.length + 1 + }); + } + + const error = tryParseForPlayground(code, parserOptions); + + if (error) { + const message = `Syntax error: ${error.message}`; + const line = codeBlockToken.map[0] + 1 + error.lineNumber; + const { column } = error; + + problems.push({ + fatal: false, + severity: 2, + message, + line, + column + }); + } + } + }); + + // Run `markdown-it` to check rule examples in the current file. + markdownIt({ html: true }) + .use(markdownItContainer, "rule-example", ruleExampleOptions) + .render(text); + return problems; +} + +/** + * Checks the example code blocks in a rule documentation file. + * @param {string} filename The file to be checked. + * @returns {Promise} The result of checking the file. + */ +async function checkFile(filename) { + let fatalErrorCount = 0, + problems; + + try { + problems = await findProblems(filename); + } catch (error) { + fatalErrorCount = 1; + problems = [{ + fatal: true, + severity: 2, + message: `Error checking file: ${error.message}` + }]; + } + return { + filePath: filename, + errorCount: problems.length, + warningCount: 0, + fatalErrorCount, + messages: problems + }; +} + +//------------------------------------------------------------------------------ +// Main +//------------------------------------------------------------------------------ + +const patterns = process.argv.slice(2); + +(async function() { + const globAsync = promisify(glob); + + // determine which files to check + const filenames = (await Promise.all(patterns.map(pattern => globAsync(pattern, { nonull: true })))).flat(); + const results = await Promise.all(filenames.map(checkFile)); + + if (results.every(result => result.errorCount === 0)) { + return; + } + + const formatter = require("../lib/cli-engine/formatters/stylish"); + const output = formatter(results); + + console.error(output); + process.exitCode = 1; +}());
- [+] /var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js + [+] /var/lib/jenkins/workspace/eslint Release/eslint/fullOfProblems.js 9 problems (5 errors, 4 warnings)