From 47074b0cb8ac34508e662deefea6138b3106dea4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 24 Jan 2023 12:02:25 +0400 Subject: [PATCH 01/19] chore(deps): update nx to v15.5.2 (#6361) --- .github/actions/prepare-build/action.yml | 2 +- package.json | 18 ++-- yarn.lock | 125 +++++++++++++---------- 3 files changed, 80 insertions(+), 65 deletions(-) diff --git a/.github/actions/prepare-build/action.yml b/.github/actions/prepare-build/action.yml index ce69eddedc50..d656587ca56a 100644 --- a/.github/actions/prepare-build/action.yml +++ b/.github/actions/prepare-build/action.yml @@ -19,4 +19,4 @@ runs: shell: bash # Website will be built by the Netlify GitHub App run: | - yarn build --exclude website + npx nx run-many --target=build --parallel --exclude website diff --git a/package.json b/package.json index 6607ca6146fc..16fef2bf3ba0 100644 --- a/package.json +++ b/package.json @@ -22,10 +22,10 @@ "url": "https://github.com/typescript-eslint/typescript-eslint/issues" }, "scripts": { - "build": "nx run-many --target=build --all --parallel --exclude website", + "build": "nx run-many --target=build --parallel --exclude website", "check-clean-workspace-after-install": "git diff --quiet --exit-code", - "check-configs": "nx run-many --target=check-configs --all --parallel", - "check-docs": "nx run-many --target=check-docs --all --parallel", + "check-configs": "nx run-many --target=check-configs --parallel", + "check-docs": "nx run-many --target=check-docs --parallel", "check-format": "prettier --list-different .", "check-spelling": "cspell --config=.cspell.json \"**/*.{md,mdx,ts,mts,cts,js,cjs,mjs,tsx,jsx}\"", "clean": "lerna clean -y && nx run-many --target=clean", @@ -37,13 +37,13 @@ "lint-fix": "eslint . --fix", "lint-markdown-fix": "yarn lint-markdown --fix", "lint-markdown": "markdownlint \"**/*.md\" --config=.markdownlint.json --ignore-path=.markdownlintignore", - "lint": "nx run-many --target=lint --all --parallel", + "lint": "nx run-many --target=lint --parallel", "postinstall": "yarn tsx ./tools/postinstall.ts", "pre-commit": "yarn lint-staged", "start": "nx run website:start", - "test": "nx run-many --target=test --all --parallel", + "test": "nx run-many --target=test --parallel", "test-integration": "yarn jest -c ./tests/integration/jest.config.js", - "typecheck": "nx run-many --target=typecheck --all --parallel" + "typecheck": "nx run-many --target=typecheck --parallel" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -54,9 +54,9 @@ "@babel/eslint-parser": "^7.19.1", "@babel/parser": "^7.20.7", "@babel/types": "^7.20.2", - "@nrwl/jest": "15.3.2", + "@nrwl/jest": "15.5.3", "@nrwl/nx-cloud": "15.0.2", - "@nrwl/workspace": "15.3.2", + "@nrwl/workspace": "15.5.3", "@swc/core": "^1.3.1", "@swc/jest": "^0.2.21", "@types/babel__code-frame": "^7.0.3", @@ -99,7 +99,7 @@ "make-dir": "^3.1.0", "markdownlint-cli": "^0.33.0", "ncp": "^2.0.0", - "nx": "15.3.2", + "nx": "15.5.3", "patch-package": "^6.4.7", "prettier": "2.8.1", "pretty-format": "^29.0.3", diff --git a/yarn.lock b/yarn.lock index 16ac4cfec250..4d8f7f823440 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3246,13 +3246,6 @@ read-package-json-fast "^2.0.3" which "^2.0.2" -"@nrwl/cli@15.3.2": - version "15.3.2" - resolved "https://registry.yarnpkg.com/@nrwl/cli/-/cli-15.3.2.tgz#dd713e6d6a064587a0ededd75d301b72f820e222" - integrity sha512-3xlH5LlNDzQ1mvVk+8w2WPoDwaOuUKR+9+38nnxTW6jW8g8S+h259/2IGsXnJ+cD7oEv3TARTC6aCrwVNn7egA== - dependencies: - nx "15.3.2" - "@nrwl/cli@15.4.5": version "15.4.5" resolved "https://registry.yarnpkg.com/@nrwl/cli/-/cli-15.4.5.tgz#2a8f663e5265379812ba83c0577abdc94dcdba8f" @@ -3260,10 +3253,17 @@ dependencies: nx "15.4.5" -"@nrwl/devkit@15.3.2": - version "15.3.2" - resolved "https://registry.yarnpkg.com/@nrwl/devkit/-/devkit-15.3.2.tgz#44ea9bc038ce87d9ea24447f6b3f3e1351a58787" - integrity sha512-h0MmDOjvhBJCrpXaAEK6eojpO5juaV6OEX0XjadPAQs4McxTALJxNP7Te6wIfgsY8t9WecARPIt85zKsLJeCjg== +"@nrwl/cli@15.5.3": + version "15.5.3" + resolved "https://registry.npmjs.org/@nrwl/cli/-/cli-15.5.3.tgz#13277e5a0e8ba713850bcf13fa76717ea747a2bb" + integrity sha512-NWf9CWswvdYM6YzXuweaZPAZ2erMtQrrHZdgFbUGeojZBZ+b4TCGzLWNodZj4yQOa/eTwlyPMYO2LEw9CoapDQ== + dependencies: + nx "15.5.3" + +"@nrwl/devkit@15.5.3": + version "15.5.3" + resolved "https://registry.npmjs.org/@nrwl/devkit/-/devkit-15.5.3.tgz#16fac0147c2ab6ebba7b5357b2b959ad46b6eb26" + integrity sha512-GGNLLGXDGWflrpaLimnE6hChfZfq3+XWZ0LJWL0IuCnchngPbNzuyh8S8KPgNKKgq4Nv0hglWefIwMg2UhHysA== dependencies: "@phenomnomnominal/tsquery" "4.1.1" ejs "^3.1.7" @@ -3282,16 +3282,16 @@ semver "7.3.4" tslib "^2.3.0" -"@nrwl/jest@15.3.2": - version "15.3.2" - resolved "https://registry.yarnpkg.com/@nrwl/jest/-/jest-15.3.2.tgz#5616af79444914e8a6c4b0dd7426eac8993accfb" - integrity sha512-3ksxm7gtJjXp/WeThxs2H5bAYI0zWQwquTjaNwaGKWvtwjtUbu+sM4zEF2HgOu4CKP6In3wFA4q0gZH7QlCEsw== +"@nrwl/jest@15.5.3": + version "15.5.3" + resolved "https://registry.npmjs.org/@nrwl/jest/-/jest-15.5.3.tgz#492ab42ac3171354a9afd6f93a7c43a6c56b3f61" + integrity sha512-BSs4ZQJtRjQ+OAPHdfeemoAiYsGL3Zuq2Ezj8XwGp50SkgVLUBZdXg2Ld1ARjTh/d3pMg+Mf+yKfjoYqFzKx+A== dependencies: "@jest/reporters" "28.1.1" "@jest/test-result" "28.1.1" - "@nrwl/devkit" "15.3.2" + "@nrwl/devkit" "15.5.3" "@phenomnomnominal/tsquery" "4.1.1" - chalk "4.1.0" + chalk "^4.1.0" dotenv "~10.0.0" identity-obj-proxy "3.0.0" jest-config "28.1.1" @@ -3300,12 +3300,12 @@ resolve.exports "1.1.0" tslib "^2.3.0" -"@nrwl/linter@15.3.2": - version "15.3.2" - resolved "https://registry.yarnpkg.com/@nrwl/linter/-/linter-15.3.2.tgz#7c947ece44d964d7331795e405966da71a02318b" - integrity sha512-sMOgmMufH5jhsseRLipKTk7GTfW3l0edjHFj9zVo49tQmGjMeurXdIw4MkJhX23JdSc1w1JGdrqeUi10iqtMyg== +"@nrwl/linter@15.5.3": + version "15.5.3" + resolved "https://registry.npmjs.org/@nrwl/linter/-/linter-15.5.3.tgz#de9c10c51d2ec92d51cc89207f642d41493314ba" + integrity sha512-ZeUtLOT0olORBL4FpEXmJoaiSKq4VIffW/vmCbosRIuHZqL4Cye5uHyQ6/KJXjD44Z+P6QCkyfr0etcy3lhSkg== dependencies: - "@nrwl/devkit" "15.3.2" + "@nrwl/devkit" "15.5.3" "@phenomnomnominal/tsquery" "4.1.1" tmp "~0.2.1" tslib "^2.3.0" @@ -3324,13 +3324,6 @@ tar "6.1.11" yargs-parser ">=21.0.1" -"@nrwl/tao@15.3.2": - version "15.3.2" - resolved "https://registry.yarnpkg.com/@nrwl/tao/-/tao-15.3.2.tgz#3498bd6596e582cbc5b922a45e5d8db5bcb2ce47" - integrity sha512-iP7e7gxSLn7xahz13Mj0c6KMSd9S2sUmD1Z6+F/H/lThikkrgURckSyZFtAW6OQNYOkWWi9RwdzVsH5He0syhQ== - dependencies: - nx "15.3.2" - "@nrwl/tao@15.4.5": version "15.4.5" resolved "https://registry.yarnpkg.com/@nrwl/tao/-/tao-15.4.5.tgz#d07f6d06cecb6acb84259e0654cfc59fcc5edd53" @@ -3338,15 +3331,22 @@ dependencies: nx "15.4.5" -"@nrwl/workspace@15.3.2": - version "15.3.2" - resolved "https://registry.yarnpkg.com/@nrwl/workspace/-/workspace-15.3.2.tgz#143609997f1e391083a2934a7e5305f0ef385ea5" - integrity sha512-h5WtTpRTHBmcO/V7WPnkzGJADQtAubZAinTn5ptkvFOYr0jnidwiVOidm0AgNvYMJtHIUf8h3jbKUIBAsRFF0g== +"@nrwl/tao@15.5.3": + version "15.5.3" + resolved "https://registry.npmjs.org/@nrwl/tao/-/tao-15.5.3.tgz#08c05715d2ecb108ed8b2c5381b9017cf1448b4a" + integrity sha512-vgPLIW9IoBfQ4IkHRT5RC4LqNwFBK5jmHYmFIRgbIeFRudFBbnpmOaKRME0OwN7qJ6964PVVbzahAPvYVD02xw== + dependencies: + nx "15.5.3" + +"@nrwl/workspace@15.5.3": + version "15.5.3" + resolved "https://registry.npmjs.org/@nrwl/workspace/-/workspace-15.5.3.tgz#3343b0de3a0fb8b0b7176c0c3cb7c19907e1485e" + integrity sha512-/Udv+dF4Z/9GZ4QmdCu/6e4QUJYx7zGTcoCOZi+Pt+OPRqOULkBbfKmB+xtiG/D32WnFePsxcssaZGux/aysUQ== dependencies: - "@nrwl/devkit" "15.3.2" - "@nrwl/linter" "15.3.2" + "@nrwl/devkit" "15.5.3" + "@nrwl/linter" "15.5.3" "@parcel/watcher" "2.0.4" - chalk "4.1.0" + chalk "^4.1.0" chokidar "^3.5.1" cli-cursor "3.1.0" cli-spinners "2.6.1" @@ -3354,12 +3354,13 @@ enquirer "~2.3.6" figures "3.2.0" flat "^5.0.2" - fs-extra "^10.1.0" + fs-extra "^11.1.0" glob "7.1.4" ignore "^5.0.4" + jsonc-parser "3.2.0" minimatch "3.0.5" npm-run-path "^4.0.1" - nx "15.3.2" + nx "15.5.3" open "^8.4.0" rxjs "^6.5.4" semver "7.3.4" @@ -7703,6 +7704,15 @@ fs-extra@^10.1.0: jsonfile "^6.0.1" universalify "^2.0.0" +fs-extra@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.0.tgz#5784b102104433bb0e090f48bfc4a30742c357ed" + integrity sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + fs-extra@^7.0.1, fs-extra@~7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" @@ -9774,6 +9784,11 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= +lines-and-columns@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-2.0.3.tgz#b2f0badedb556b747020ab8ea7f0373e22efac1b" + integrity sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w== + linkify-it@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-4.0.1.tgz#01f1d5e508190d06669982ba31a7d9f56a5751ec" @@ -10774,13 +10789,13 @@ nth-check@^2.0.0, nth-check@^2.0.1: dependencies: boolbase "^1.0.0" -nx@15.3.2: - version "15.3.2" - resolved "https://registry.yarnpkg.com/nx/-/nx-15.3.2.tgz#3269b7c1c0be4dc4c389a4c54f463eb43636d542" - integrity sha512-i/y9pkZj6OACnk/+VmJaqrRIhY9VZw0twyeUp9z3gy7KElFoQZ7EMm4LcacFpVYy/MTsHYi0c87CDzkSyPogOA== +nx@15.4.5, "nx@>=15.4.2 < 16": + version "15.4.5" + resolved "https://registry.yarnpkg.com/nx/-/nx-15.4.5.tgz#12daa740256fa29ba634fbc4f3f87b6d078c2990" + integrity sha512-1spZL6sgOV8JJJuN8W5CLtJYwTOnlyaV32jPXfidavU0QMS8MP+rW3+NUQ9Uzc1UYhOu8llZWtnen93neVGQRw== dependencies: - "@nrwl/cli" "15.3.2" - "@nrwl/tao" "15.3.2" + "@nrwl/cli" "15.4.5" + "@nrwl/tao" "15.4.5" "@parcel/watcher" "2.0.4" "@yarnpkg/lockfile" "^1.1.0" "@yarnpkg/parsers" "^3.0.0-rc.18" @@ -10809,26 +10824,25 @@ nx@15.3.2: strong-log-transformer "^2.1.0" tar-stream "~2.2.0" tmp "~0.2.1" - tsconfig-paths "^3.9.0" + tsconfig-paths "^4.1.2" tslib "^2.3.0" v8-compile-cache "2.3.0" yargs "^17.6.2" yargs-parser "21.1.1" -nx@15.4.5, "nx@>=15.4.2 < 16": - version "15.4.5" - resolved "https://registry.yarnpkg.com/nx/-/nx-15.4.5.tgz#12daa740256fa29ba634fbc4f3f87b6d078c2990" - integrity sha512-1spZL6sgOV8JJJuN8W5CLtJYwTOnlyaV32jPXfidavU0QMS8MP+rW3+NUQ9Uzc1UYhOu8llZWtnen93neVGQRw== +nx@15.5.3: + version "15.5.3" + resolved "https://registry.npmjs.org/nx/-/nx-15.5.3.tgz#bf6252e7d9e17121dd82dec4f6fce319b9e005fa" + integrity sha512-PHB8VbiBLP108xb+yR8IGEsYWr7OcmDDOjHL+73oP4lVjyPgT8wdTMe6tI5LdBgv+KZ+0kiThK3ckvcPsfgvLQ== dependencies: - "@nrwl/cli" "15.4.5" - "@nrwl/tao" "15.4.5" + "@nrwl/cli" "15.5.3" + "@nrwl/tao" "15.5.3" "@parcel/watcher" "2.0.4" "@yarnpkg/lockfile" "^1.1.0" "@yarnpkg/parsers" "^3.0.0-rc.18" "@zkochan/js-yaml" "0.0.6" axios "^1.0.0" - chalk "4.1.0" - chokidar "^3.5.1" + chalk "^4.1.0" cli-cursor "3.1.0" cli-spinners "2.6.1" cliui "^7.0.2" @@ -10837,11 +10851,12 @@ nx@15.4.5, "nx@>=15.4.2 < 16": fast-glob "3.2.7" figures "3.2.0" flat "^5.0.2" - fs-extra "^10.1.0" + fs-extra "^11.1.0" glob "7.1.4" ignore "^5.0.4" js-yaml "4.1.0" jsonc-parser "3.2.0" + lines-and-columns "~2.0.3" minimatch "3.0.5" npm-run-path "^4.0.1" open "^8.4.0" @@ -13663,7 +13678,7 @@ ts-node@10.7.0: v8-compile-cache-lib "^3.0.0" yn "3.1.1" -tsconfig-paths@^3.14.1, tsconfig-paths@^3.9.0: +tsconfig-paths@^3.14.1: version "3.14.1" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== From 09d57cec8901880c6b24ea80dfa7d9fcdc463930 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Wed, 25 Jan 2023 08:01:35 +0900 Subject: [PATCH 02/19] fix(eslint-plugin): [ban-ts-comment] counts graphemes instead of `String.prototype.length` (#5704) * fix: counts graphemes instead of String length * Update packages/eslint-plugin/src/rules/ban-ts-comment.ts Co-authored-by: Josh Goldberg * chore: add valid tests * Add grapheme-splitter to peerDependencies * Move to standard dependency * No more peerDependency Co-authored-by: Josh Goldberg Co-authored-by: Josh Goldberg --- packages/eslint-plugin/package.json | 2 + .../eslint-plugin/src/rules/ban-ts-comment.ts | 19 +++- .../tests/rules/ban-ts-comment.test.ts | 96 +++++++++++++++++++ yarn.lock | 5 + 4 files changed, 121 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index de64bdb760ef..5e2304c49e0c 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -48,6 +48,7 @@ "@typescript-eslint/type-utils": "5.49.0", "@typescript-eslint/utils": "5.49.0", "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", "regexpp": "^3.2.0", @@ -61,6 +62,7 @@ "@types/natural-compare-lite": "^1.4.0", "@types/prettier": "*", "chalk": "^5.0.1", + "grapheme-splitter": "^1.0.4", "cross-fetch": "^3.1.5", "json-schema": "*", "markdown-table": "^3.0.2", diff --git a/packages/eslint-plugin/src/rules/ban-ts-comment.ts b/packages/eslint-plugin/src/rules/ban-ts-comment.ts index 9c55b437da63..f0bfce93ff6e 100644 --- a/packages/eslint-plugin/src/rules/ban-ts-comment.ts +++ b/packages/eslint-plugin/src/rules/ban-ts-comment.ts @@ -1,7 +1,22 @@ import { AST_TOKEN_TYPES } from '@typescript-eslint/utils'; +import GraphemeSplitter from 'grapheme-splitter'; import * as util from '../util'; +let splitter: GraphemeSplitter; +function isASCII(value: string): boolean { + return /^[\u0020-\u007f]*$/u.test(value); +} +function getStringLength(value: string): number { + if (isASCII(value)) { + return value.length; + } + + splitter ??= new GraphemeSplitter(); + + return splitter.countGraphemes(value); +} + type DirectiveConfig = | boolean | 'allow-with-description' @@ -147,7 +162,9 @@ export default util.createRule<[Options], MessageIds>({ minimumDescriptionLength = defaultMinimumDescriptionLength, } = options; const format = descriptionFormats.get(fullDirective); - if (description.trim().length < minimumDescriptionLength) { + if ( + getStringLength(description.trim()) < minimumDescriptionLength + ) { context.report({ data: { directive, minimumDescriptionLength }, node: comment, diff --git a/packages/eslint-plugin/tests/rules/ban-ts-comment.test.ts b/packages/eslint-plugin/tests/rules/ban-ts-comment.test.ts index 7e8ef295ba91..54855f19cf39 100644 --- a/packages/eslint-plugin/tests/rules/ban-ts-comment.test.ts +++ b/packages/eslint-plugin/tests/rules/ban-ts-comment.test.ts @@ -45,6 +45,14 @@ ruleTester.run('ts-expect-error', rule, { }, ], }, + { + code: noFormat`// @ts-expect-error ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ`, + options: [ + { + 'ts-expect-error': 'allow-with-description', + }, + ], + }, ], invalid: [ { @@ -228,6 +236,22 @@ if (false) { }, ], }, + { + code: noFormat`// @ts-expect-error ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ`, + options: [ + { + 'ts-expect-error': 'allow-with-description', + }, + ], + errors: [ + { + data: { directive: 'expect-error', minimumDescriptionLength: 3 }, + messageId: 'tsDirectiveCommentRequiresDescription', + line: 1, + column: 1, + }, + ], + }, ], }); @@ -266,6 +290,14 @@ ruleTester.run('ts-ignore', rule, { }, ], }, + { + code: noFormat`// @ts-ignore ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ`, + options: [ + { + 'ts-ignore': 'allow-with-description', + }, + ], + }, ], invalid: [ { @@ -460,6 +492,22 @@ if (false) { }, ], }, + { + code: noFormat`// @ts-ignore ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ`, + options: [ + { + 'ts-ignore': 'allow-with-description', + }, + ], + errors: [ + { + data: { directive: 'ignore', minimumDescriptionLength: 3 }, + messageId: 'tsDirectiveCommentRequiresDescription', + line: 1, + column: 1, + }, + ], + }, ], }); @@ -498,6 +546,14 @@ ruleTester.run('ts-nocheck', rule, { }, ], }, + { + code: noFormat`// @ts-nocheck ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ`, + options: [ + { + 'ts-nocheck': 'allow-with-description', + }, + ], + }, ], invalid: [ { @@ -668,6 +724,22 @@ if (false) { }, ], }, + { + code: noFormat`// @ts-nocheck ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ`, + options: [ + { + 'ts-nocheck': 'allow-with-description', + }, + ], + errors: [ + { + data: { directive: 'nocheck', minimumDescriptionLength: 3 }, + messageId: 'tsDirectiveCommentRequiresDescription', + line: 1, + column: 1, + }, + ], + }, ], }); @@ -700,6 +772,14 @@ ruleTester.run('ts-check', rule, { }, ], }, + { + code: noFormat`// @ts-check ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ`, + options: [ + { + 'ts-check': 'allow-with-description', + }, + ], + }, ], invalid: [ { @@ -863,5 +943,21 @@ if (false) { }, ], }, + { + code: noFormat`// @ts-check ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ`, + options: [ + { + 'ts-check': 'allow-with-description', + }, + ], + errors: [ + { + data: { directive: 'check', minimumDescriptionLength: 3 }, + messageId: 'tsDirectiveCommentRequiresDescription', + line: 1, + column: 1, + }, + ], + }, ], }); diff --git a/yarn.lock b/yarn.lock index 4d8f7f823440..a1ed83510144 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8086,6 +8086,11 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6 resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== +grapheme-splitter@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" + integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== + gray-matter@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/gray-matter/-/gray-matter-4.0.3.tgz#e893c064825de73ea1f5f7d88c7a9f7274288798" From 67706e72e332bf11c82fdf51f3d417d3c93a86cf Mon Sep 17 00:00:00 2001 From: Eliott C Date: Wed, 25 Jan 2023 00:27:50 +0100 Subject: [PATCH 03/19] feat(eslint-plugin): add `key-spacing` rule extension for interface & type declarations (#6211) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ๐Ÿšง key-spacing for interface on default settings * ๐Ÿšง Support type literals as welll * ๐Ÿšง Add full typing for the options * ๐Ÿšง Add 'mode' param * ๐Ÿ› Fix index signatures * โœจ Support classes * ๐Ÿฉน fixes * โœ… Add tests on mode, multiLine, singleLine * ๐Ÿท๏ธ Allow options.multiline.align to be an object * ๐ŸŽจ Use ast utils to locate last character before token * โœจ Support comments in-between properties * โœ… Add test cases for nested type declarations & multiline type annotations * โœจ Autofix for non-aligned values * โœจ Autofix for aligned values * โœ๏ธ * ๐Ÿšจ * ๐Ÿ› Support optional ? token * โœ… Add tests with class property assignments * ๐Ÿ“ Add documentation on key-spacing * ๐ŸŽจ Use .at() to access last element of array * โœ… Fix tests * fixup! โœ… Fix tests * โœ… Add some coverage * ๐Ÿ› Fix edge case in determining aligned groups In case there is three statements in one line, and one statement in the line after * โšก๏ธ Use Array.concat instead of .push(...) .push could error if 60k + arguments * ๐ŸŽจ Improve readability * ๐ŸŽจ Use tempate literals in tests * โœ… Add test with anonymous types * โœ… Add test with quoted keys * โž• Add grapheme-splitter to deal with emojis * โœ… Add test case for multiline comments * ๐Ÿšจ Remove 'in' statements, reduce amount of null-assertions * โœ… Add test case for properties without type annotation or assignments * โœ… Add wacky test cases * โœ… Add coverage * โœ… Add coverage, again * โœ… Add coverage, again * โœ… Add coverage when align is an object, but align.on is missing It defaults to 'colon' in this case * KeyTypeNodeWithTypeAnnotation * Extract to shared helper Co-authored-by: Josh Goldberg --- .../eslint-plugin/docs/rules/key-spacing.md | 12 + packages/eslint-plugin/package.json | 1 + packages/eslint-plugin/src/configs/all.ts | 2 + .../eslint-plugin/src/rules/ban-ts-comment.ts | 18 +- packages/eslint-plugin/src/rules/index.ts | 2 + .../eslint-plugin/src/rules/key-spacing.ts | 421 ++++++ .../src/util/getESLintCoreRule.ts | 1 + .../eslint-plugin/src/util/getStringLength.ts | 17 + packages/eslint-plugin/src/util/index.ts | 1 + .../tests/rules/key-spacing.test.ts | 1278 +++++++++++++++++ .../eslint-plugin/typings/eslint-rules.d.ts | 52 + 11 files changed, 1789 insertions(+), 16 deletions(-) create mode 100644 packages/eslint-plugin/docs/rules/key-spacing.md create mode 100644 packages/eslint-plugin/src/rules/key-spacing.ts create mode 100644 packages/eslint-plugin/src/util/getStringLength.ts create mode 100644 packages/eslint-plugin/tests/rules/key-spacing.test.ts diff --git a/packages/eslint-plugin/docs/rules/key-spacing.md b/packages/eslint-plugin/docs/rules/key-spacing.md new file mode 100644 index 000000000000..3bfcf5f389f0 --- /dev/null +++ b/packages/eslint-plugin/docs/rules/key-spacing.md @@ -0,0 +1,12 @@ +--- +description: 'Enforce consistent spacing between property names and type annotations in types and interfaces.' +--- + +> ๐Ÿ›‘ This file is source code, not the primary documentation location! ๐Ÿ›‘ +> +> See **https://typescript-eslint.io/rules/key-spacing** for documentation. + +## Examples + +This rule extends the base [`eslint/keyword-spacing`](https://eslint.org/docs/rules/key-spacing) rule. +This version adds support for type annotations on interfaces, classes and type literals properties. diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 5e2304c49e0c..55992f5b7272 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -50,6 +50,7 @@ "debug": "^4.3.4", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", + "grapheme-splitter": "^1.0.4", "natural-compare-lite": "^1.4.0", "regexpp": "^3.2.0", "semver": "^7.3.7", diff --git a/packages/eslint-plugin/src/configs/all.ts b/packages/eslint-plugin/src/configs/all.ts index 20ea892f581d..452035c4ebf2 100644 --- a/packages/eslint-plugin/src/configs/all.ts +++ b/packages/eslint-plugin/src/configs/all.ts @@ -37,6 +37,8 @@ export = { '@typescript-eslint/indent': 'error', 'init-declarations': 'off', '@typescript-eslint/init-declarations': 'error', + 'key-spacing': 'off', + '@typescript-eslint/key-spacing': 'error', 'keyword-spacing': 'off', '@typescript-eslint/keyword-spacing': 'error', 'lines-between-class-members': 'off', diff --git a/packages/eslint-plugin/src/rules/ban-ts-comment.ts b/packages/eslint-plugin/src/rules/ban-ts-comment.ts index f0bfce93ff6e..511a951280e7 100644 --- a/packages/eslint-plugin/src/rules/ban-ts-comment.ts +++ b/packages/eslint-plugin/src/rules/ban-ts-comment.ts @@ -1,22 +1,7 @@ import { AST_TOKEN_TYPES } from '@typescript-eslint/utils'; -import GraphemeSplitter from 'grapheme-splitter'; import * as util from '../util'; -let splitter: GraphemeSplitter; -function isASCII(value: string): boolean { - return /^[\u0020-\u007f]*$/u.test(value); -} -function getStringLength(value: string): number { - if (isASCII(value)) { - return value.length; - } - - splitter ??= new GraphemeSplitter(); - - return splitter.countGraphemes(value); -} - type DirectiveConfig = | boolean | 'allow-with-description' @@ -163,7 +148,8 @@ export default util.createRule<[Options], MessageIds>({ } = options; const format = descriptionFormats.get(fullDirective); if ( - getStringLength(description.trim()) < minimumDescriptionLength + util.getStringLength(description.trim()) < + minimumDescriptionLength ) { context.report({ data: { directive, minimumDescriptionLength }, diff --git a/packages/eslint-plugin/src/rules/index.ts b/packages/eslint-plugin/src/rules/index.ts index 8a3c2bbf4371..f7e51fdabd58 100644 --- a/packages/eslint-plugin/src/rules/index.ts +++ b/packages/eslint-plugin/src/rules/index.ts @@ -22,6 +22,7 @@ import explicitModuleBoundaryTypes from './explicit-module-boundary-types'; import funcCallSpacing from './func-call-spacing'; import indent from './indent'; import initDeclarations from './init-declarations'; +import keySpacing from './key-spacing'; import keywordSpacing from './keyword-spacing'; import linesBetweenClassMembers from './lines-between-class-members'; import memberDelimiterStyle from './member-delimiter-style'; @@ -153,6 +154,7 @@ export default { 'func-call-spacing': funcCallSpacing, indent: indent, 'init-declarations': initDeclarations, + 'key-spacing': keySpacing, 'keyword-spacing': keywordSpacing, 'lines-between-class-members': linesBetweenClassMembers, 'member-delimiter-style': memberDelimiterStyle, diff --git a/packages/eslint-plugin/src/rules/key-spacing.ts b/packages/eslint-plugin/src/rules/key-spacing.ts new file mode 100644 index 000000000000..587d2674f4f3 --- /dev/null +++ b/packages/eslint-plugin/src/rules/key-spacing.ts @@ -0,0 +1,421 @@ +import type { TSESTree } from '@typescript-eslint/utils'; +import { AST_NODE_TYPES } from '@typescript-eslint/utils'; + +import * as util from '../util'; +import { getESLintCoreRule } from '../util/getESLintCoreRule'; + +const baseRule = getESLintCoreRule('key-spacing'); + +export type Options = util.InferOptionsTypeFromRule; +export type MessageIds = util.InferMessageIdsTypeFromRule; + +// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment +const baseSchema = Array.isArray(baseRule.meta.schema) + ? baseRule.meta.schema[0] + : baseRule.meta.schema; + +export default util.createRule({ + name: 'key-spacing', + meta: { + type: 'layout', + docs: { + description: + 'Enforce consistent spacing between property names and type annotations in types and interfaces', + recommended: false, + extendsBaseRule: true, + }, + fixable: 'whitespace', + hasSuggestions: baseRule.meta.hasSuggestions, + schema: [baseSchema], + messages: baseRule.meta.messages, + }, + defaultOptions: [{}], + + create(context, [options]) { + const sourceCode = context.getSourceCode(); + const baseRules = baseRule.create(context); + + /** + * @returns the column of the position after converting all unicode characters in the line to 1 char length + */ + function adjustedColumn(position: TSESTree.Position): number { + const line = position.line - 1; // position.line is 1-indexed + return util.getStringLength( + sourceCode.lines[line].slice(0, position.column), + ); + } + + /** + * Starting from the given a node (a property.key node here) looks forward + * until it finds the last token before a colon punctuator and returns it. + */ + function getLastTokenBeforeColon(node: TSESTree.Node): TSESTree.Token { + const colonToken = sourceCode.getTokenAfter(node, util.isColonToken)!; + + return sourceCode.getTokenBefore(colonToken)!; + } + + type KeyTypeNode = + | TSESTree.TSIndexSignature + | TSESTree.TSPropertySignature + | TSESTree.PropertyDefinition; + + type KeyTypeNodeWithTypeAnnotation = KeyTypeNode & { + typeAnnotation: TSESTree.TSTypeAnnotation; + }; + + function isKeyTypeNode( + node: TSESTree.Node, + ): node is KeyTypeNodeWithTypeAnnotation { + return ( + (node.type === AST_NODE_TYPES.TSPropertySignature || + node.type === AST_NODE_TYPES.TSIndexSignature || + node.type === AST_NODE_TYPES.PropertyDefinition) && + !!node.typeAnnotation + ); + } + + /** + * To handle index signatures, to get the whole text for the parameters + */ + function getKeyText(node: KeyTypeNodeWithTypeAnnotation): string { + if (node.type !== AST_NODE_TYPES.TSIndexSignature) { + return sourceCode.getText(node.key); + } + + const code = sourceCode.getText(node); + return code.slice( + 0, + sourceCode.getTokenAfter( + node.parameters.at(-1)!, + util.isClosingBracketToken, + )!.range[1] - node.range[0], + ); + } + + /** + * To handle index signatures, be able to get the end position of the parameters + */ + function getKeyLocEnd( + node: KeyTypeNodeWithTypeAnnotation, + ): TSESTree.Position { + return getLastTokenBeforeColon( + node.type !== AST_NODE_TYPES.TSIndexSignature + ? node.key + : node.parameters.at(-1)!, + ).loc.end; + } + + function checkBeforeColon( + node: KeyTypeNodeWithTypeAnnotation, + expectedWhitespaceBeforeColon: number, + mode: 'strict' | 'minimum', + ): void { + const { typeAnnotation } = node; + const colon = typeAnnotation.loc.start.column; + const keyEnd = getKeyLocEnd(node); + const difference = colon - keyEnd.column - expectedWhitespaceBeforeColon; + if (mode === 'strict' ? difference : difference < 0) { + context.report({ + node, + messageId: difference > 0 ? 'extraKey' : 'missingKey', + fix: fixer => { + if (difference > 0) { + return fixer.removeRange([ + typeAnnotation.range[0] - difference, + typeAnnotation.range[0], + ]); + } else { + return fixer.insertTextBefore( + typeAnnotation, + ' '.repeat(-difference), + ); + } + }, + data: { + computed: '', + key: getKeyText(node), + }, + }); + } + } + + function checkAfterColon( + node: KeyTypeNodeWithTypeAnnotation, + expectedWhitespaceAfterColon: number, + mode: 'strict' | 'minimum', + ): void { + const { typeAnnotation } = node; + const colon = typeAnnotation.loc.start.column; + const typeStart = typeAnnotation.typeAnnotation.loc.start.column; + const difference = typeStart - colon - 1 - expectedWhitespaceAfterColon; + if (mode === 'strict' ? difference : difference < 0) { + context.report({ + node, + messageId: difference > 0 ? 'extraValue' : 'missingValue', + fix: fixer => { + if (difference > 0) { + return fixer.removeRange([ + typeAnnotation.typeAnnotation.range[0] - difference, + typeAnnotation.typeAnnotation.range[0], + ]); + } else { + return fixer.insertTextBefore( + typeAnnotation.typeAnnotation, + ' '.repeat(-difference), + ); + } + }, + data: { + computed: '', + key: getKeyText(node), + }, + }); + } + } + + // adapted from https://github.com/eslint/eslint/blob/ba74253e8bd63e9e163bbee0540031be77e39253/lib/rules/key-spacing.js#L356 + function continuesAlignGroup( + lastMember: TSESTree.Node, + candidate: TSESTree.Node, + ): boolean { + const groupEndLine = lastMember.loc.start.line; + const candidateValueStartLine = ( + isKeyTypeNode(candidate) ? candidate.typeAnnotation : candidate + ).loc.start.line; + + if (candidateValueStartLine === groupEndLine) { + return false; + } + + if (candidateValueStartLine - groupEndLine === 1) { + return true; + } + + /* + * Check that the first comment is adjacent to the end of the group, the + * last comment is adjacent to the candidate property, and that successive + * comments are adjacent to each other. + */ + const leadingComments = sourceCode.getCommentsBefore(candidate); + + if ( + leadingComments.length && + leadingComments[0].loc.start.line - groupEndLine <= 1 && + candidateValueStartLine - leadingComments.at(-1)!.loc.end.line <= 1 + ) { + for (let i = 1; i < leadingComments.length; i++) { + if ( + leadingComments[i].loc.start.line - + leadingComments[i - 1].loc.end.line > + 1 + ) { + return false; + } + } + return true; + } + + return false; + } + + function checkAlignGroup(group: TSESTree.Node[]): void { + let alignColumn = 0; + const align: 'value' | 'colon' = + (typeof options.align === 'object' + ? options.align.on + : typeof options.multiLine?.align === 'object' + ? options.multiLine.align.on + : options.multiLine?.align ?? options.align) ?? 'colon'; + const beforeColon = + (typeof options.align === 'object' + ? options.align.beforeColon + : options.multiLine + ? typeof options.multiLine.align === 'object' + ? options.multiLine.align.beforeColon + : options.multiLine.beforeColon + : options.beforeColon) ?? false; + const expectedWhitespaceBeforeColon = beforeColon ? 1 : 0; + const afterColon = + (typeof options.align === 'object' + ? options.align.afterColon + : options.multiLine + ? typeof options.multiLine.align === 'object' + ? options.multiLine.align.afterColon + : options.multiLine.afterColon + : options.afterColon) ?? true; + const expectedWhitespaceAfterColon = afterColon ? 1 : 0; + const mode = + (typeof options.align === 'object' + ? options.align.mode + : options.multiLine + ? typeof options.multiLine.align === 'object' + ? // same behavior as in original rule + options.multiLine.align.mode ?? options.multiLine.mode + : options.multiLine.mode + : options.mode) ?? 'strict'; + + for (const node of group) { + if (isKeyTypeNode(node)) { + const keyEnd = adjustedColumn(getKeyLocEnd(node)); + alignColumn = Math.max( + alignColumn, + align === 'colon' + ? keyEnd + expectedWhitespaceBeforeColon + : keyEnd + + ':'.length + + expectedWhitespaceAfterColon + + expectedWhitespaceBeforeColon, + ); + } + } + + for (const node of group) { + if (!isKeyTypeNode(node)) { + continue; + } + const { typeAnnotation } = node; + const toCheck = + align === 'colon' ? typeAnnotation : typeAnnotation.typeAnnotation; + const difference = adjustedColumn(toCheck.loc.start) - alignColumn; + + if (difference) { + context.report({ + node, + messageId: + difference > 0 + ? align === 'colon' + ? 'extraKey' + : 'extraValue' + : align === 'colon' + ? 'missingKey' + : 'missingValue', + fix: fixer => { + if (difference > 0) { + return fixer.removeRange([ + toCheck.range[0] - difference, + toCheck.range[0], + ]); + } else { + return fixer.insertTextBefore(toCheck, ' '.repeat(-difference)); + } + }, + data: { + computed: '', + key: getKeyText(node), + }, + }); + } + + if (align === 'colon') { + checkAfterColon(node, expectedWhitespaceAfterColon, mode); + } else { + checkBeforeColon(node, expectedWhitespaceBeforeColon, mode); + } + } + } + + function checkIndividualNode( + node: TSESTree.Node, + { singleLine }: { singleLine: boolean }, + ): void { + const beforeColon = + (singleLine + ? options.singleLine + ? options.singleLine.beforeColon + : options.beforeColon + : options.multiLine + ? options.multiLine.beforeColon + : options.beforeColon) ?? false; + const expectedWhitespaceBeforeColon = beforeColon ? 1 : 0; + const afterColon = + (singleLine + ? options.singleLine + ? options.singleLine.afterColon + : options.afterColon + : options.multiLine + ? options.multiLine.afterColon + : options.afterColon) ?? true; + const expectedWhitespaceAfterColon = afterColon ? 1 : 0; + const mode = + (singleLine + ? options.singleLine + ? options.singleLine.mode + : options.mode + : options.multiLine + ? options.multiLine.mode + : options.mode) ?? 'strict'; + + if (isKeyTypeNode(node)) { + checkBeforeColon(node, expectedWhitespaceBeforeColon, mode); + checkAfterColon(node, expectedWhitespaceAfterColon, mode); + } + } + + function validateBody( + body: + | TSESTree.TSTypeLiteral + | TSESTree.TSInterfaceBody + | TSESTree.ClassBody, + ): void { + const isSingleLine = body.loc.start.line === body.loc.end.line; + + const members = + body.type === AST_NODE_TYPES.TSTypeLiteral ? body.members : body.body; + + let alignGroups: TSESTree.Node[][] = []; + let unalignedElements: TSESTree.Node[] = []; + + if (options.align || options.multiLine?.align) { + let currentAlignGroup: TSESTree.Node[] = []; + alignGroups.push(currentAlignGroup); + + let prevNode: TSESTree.Node | undefined = undefined; + + for (const node of members) { + let prevAlignedNode = currentAlignGroup.at(-1); + if (prevAlignedNode !== prevNode) { + prevAlignedNode = undefined; + } + + if (prevAlignedNode && continuesAlignGroup(prevAlignedNode, node)) { + currentAlignGroup.push(node); + } else if (prevNode?.loc.start.line === node.loc.start.line) { + if (prevAlignedNode) { + // Here, prevNode === prevAlignedNode === currentAlignGroup.at(-1) + unalignedElements.push(prevAlignedNode); + currentAlignGroup.pop(); + } + unalignedElements.push(node); + } else { + currentAlignGroup = [node]; + alignGroups.push(currentAlignGroup); + } + + prevNode = node; + } + + unalignedElements = unalignedElements.concat( + ...alignGroups.filter(group => group.length === 1), + ); + alignGroups = alignGroups.filter(group => group.length >= 2); + } else { + unalignedElements = members; + } + + for (const group of alignGroups) { + checkAlignGroup(group); + } + + for (const node of unalignedElements) { + checkIndividualNode(node, { singleLine: isSingleLine }); + } + } + return { + ...baseRules, + TSTypeLiteral: validateBody, + TSInterfaceBody: validateBody, + ClassBody: validateBody, + }; + }, +}); diff --git a/packages/eslint-plugin/src/util/getESLintCoreRule.ts b/packages/eslint-plugin/src/util/getESLintCoreRule.ts index 1678903acd32..80962a677b05 100644 --- a/packages/eslint-plugin/src/util/getESLintCoreRule.ts +++ b/packages/eslint-plugin/src/util/getESLintCoreRule.ts @@ -12,6 +12,7 @@ interface RuleMap { 'dot-notation': typeof import('eslint/lib/rules/dot-notation'); indent: typeof import('eslint/lib/rules/indent'); 'init-declarations': typeof import('eslint/lib/rules/init-declarations'); + 'key-spacing': typeof import('eslint/lib/rules/key-spacing'); 'keyword-spacing': typeof import('eslint/lib/rules/keyword-spacing'); 'lines-between-class-members': typeof import('eslint/lib/rules/lines-between-class-members'); 'no-dupe-args': typeof import('eslint/lib/rules/no-dupe-args'); diff --git a/packages/eslint-plugin/src/util/getStringLength.ts b/packages/eslint-plugin/src/util/getStringLength.ts new file mode 100644 index 000000000000..65a22551949a --- /dev/null +++ b/packages/eslint-plugin/src/util/getStringLength.ts @@ -0,0 +1,17 @@ +import GraphemeSplitter from 'grapheme-splitter'; + +let splitter: GraphemeSplitter; + +function isASCII(value: string): boolean { + return /^[\u0020-\u007f]*$/u.test(value); +} + +export function getStringLength(value: string): number { + if (isASCII(value)) { + return value.length; + } + + splitter ??= new GraphemeSplitter(); + + return splitter.countGraphemes(value); +} diff --git a/packages/eslint-plugin/src/util/index.ts b/packages/eslint-plugin/src/util/index.ts index b2ad2927773a..53a19a96d368 100644 --- a/packages/eslint-plugin/src/util/index.ts +++ b/packages/eslint-plugin/src/util/index.ts @@ -5,6 +5,7 @@ export * from './collectUnusedVariables'; export * from './createRule'; export * from './getFunctionHeadLoc'; export * from './getOperatorPrecedence'; +export * from './getStringLength'; export * from './getThisExpression'; export * from './getWrappingFixer'; export * from './isNodeEqual'; diff --git a/packages/eslint-plugin/tests/rules/key-spacing.test.ts b/packages/eslint-plugin/tests/rules/key-spacing.test.ts new file mode 100644 index 000000000000..40206258671c --- /dev/null +++ b/packages/eslint-plugin/tests/rules/key-spacing.test.ts @@ -0,0 +1,1278 @@ +/* eslint-disable eslint-comments/no-use */ +// this rule tests the new lines, which prettier will want to fix and break the tests +/* eslint "@typescript-eslint/internal/plugin-test-formatting": ["error", { formatWithPrettier: false }] */ +/* eslint-enable eslint-comments/no-use */ +import rule from '../../src/rules/key-spacing'; +import { RuleTester } from '../RuleTester'; + +const ruleTester = new RuleTester({ + parser: '@typescript-eslint/parser', +}); + +ruleTester.run('key-spacing', rule, { + valid: [ + // align: value + { + code: ` +interface X { + a: number; + abc: string +}; + `, + options: [{ align: 'value' }], + }, + { + code: ` +interface X { + "a:b": number; + abcde: string +}; + `, + options: [{ align: 'value' }], + }, + { + code: ` +let x: { + a: number; + abc: string +}; + `, + options: [{ align: 'value' }], + }, + { + code: ` +let x: { + a: number; + "๐Œ˜": string; + [๐Œ˜]: Date; + "๐ŸŒท": "bar", // 2 code points + "๐ŸŽ": "baz", // 2 code points + "๐Ÿ‡ฎ๐Ÿ‡ณ": "qux", // 4 code points + "๐Ÿณ๏ธโ€๐ŸŒˆ": "xyz", // 6 code points +}; + `, + options: [{ align: 'value' }], + }, + { + code: ` +interface X { + a: number; + abc: string; c: number; +}; + `, + options: [{ align: 'value' }], + }, + { + code: ` +interface X { + a: number; + abc: string; c: number; de: boolean; + abcef: number; +}; + `, + options: [{ align: 'colon' }], + }, + { + code: ` +interface X { + a : number; + abc; + abcef: number; +}; + `, + options: [{ align: 'colon' }], + }, + { + code: ` +interface X { + a?: number; + abc: string +}; + `, + options: [{ align: 'value' }], + }, + { + code: ` +interface X { + a: number; + // Some comment + abc: string +}; + `, + options: [{ align: 'value' }], + }, + { + code: ` +interface X { + a: number; + // Some comment + // on multiple lines + abc: string +}; + `, + options: [{ align: 'value' }], + }, + { + code: ` +interface X { + a: number; + /** + * Some comment + * on multiple lines + */ + abc: string +}; + `, + options: [{ align: 'value' }], + }, + { + code: ` +interface X { + a: number; + /** + * Doc comment + */ + abc: string +}; + `, + options: [{ align: 'value' }], + }, + { + code: ` +interface X { + a: number; + + abc: string +}; + `, + options: [{ align: 'value' }], + }, + { + code: ` +class X { + a: number; + abc: string +}; + `, + options: [{ align: 'value' }], + }, + { + code: ` +class X { + a?: number; + abc: string +}; + `, + options: [{ align: 'value' }], + }, + { + code: ` +class X { + x: number; + z = 1; + xbcef: number; + } + `, + options: [{ align: 'value' }], + }, + { + code: ` +class X { + a: number; + + abc: string +}; + `, + options: [{ align: 'value' }], + }, + { + code: ` +type X = { + a: number; + abc: string +}; + `, + options: [{ align: 'value' }], + }, + { + code: ` +type X = { + a: number; + + abc: string +}; + `, + options: [{ align: 'value' }], + }, + { + code: ` +type X = { + a : number; + abc: string +}; + `, + options: [{ align: 'value', mode: 'minimum' }], + }, + { + code: ` +type X = { + a : number; + abc: string +}; + `, + options: [ + { + align: { + on: 'value', + mode: 'minimum', + beforeColon: false, + afterColon: true, + }, + }, + ], + }, + { + code: ` +interface X { + a: number; + prop: { + abc: number; + a: number; + }; + abc: string +} + `, + options: [{ align: 'value' }], + }, + { + code: ` +class X { + a: number; + prop: { + abc: number; + a: number; + }; + abc: string + x = 1; + d: number; + z: number = 1; + ef: string; +} + `, + options: [{ align: 'value' }], + }, + // align: colon + { + code: ` +interface X { + a : number; + abc: string +}; + `, + options: [{ align: 'colon' }], + }, + { + code: ` +interface X { + a :number; + abc:string +}; + `, + options: [{ align: 'colon', afterColon: false }], + }, + { + code: ` +interface X { + a : number; + abc: string +}; + `, + options: [{ align: 'colon', mode: 'minimum' }], + }, + // no align + { + code: ` +interface X { + a: number; + abc: string +}; + `, + options: [{}], + }, + { + code: ` +interface X { + a : number; + abc : string +}; + `, + options: [{ beforeColon: true }], + }, + // singleLine / multiLine + { + code: ` +interface X { + a : number; + abc : string +}; + `, + options: [ + { + singleLine: { beforeColon: false, afterColon: false }, + multiLine: { beforeColon: true, afterColon: true }, + }, + ], + }, + { + code: ` +interface X { + a : number; + abc : string +}; + `, + options: [ + { + align: { on: 'value', beforeColon: true, afterColon: true }, + singleLine: { beforeColon: false, afterColon: false }, + multiLine: { beforeColon: false, afterColon: false }, + }, + ], + }, + { + code: ` +interface X { + a : number; + abc : string +}; + `, + options: [ + { + align: { beforeColon: true, afterColon: true }, // defaults to 'colon' + singleLine: { beforeColon: false, afterColon: false }, + multiLine: { beforeColon: false, afterColon: false }, + }, + ], + }, + { + code: ` +interface X { + a : number; + abc : string +}; + `, + options: [ + { + singleLine: { beforeColon: false, afterColon: false }, + multiLine: { beforeColon: true, afterColon: true, align: 'value' }, + }, + ], + }, + { + code: ` +interface X { + a : number; + abc : string +}; + `, + options: [ + { + singleLine: { beforeColon: false, afterColon: false }, + multiLine: { + beforeColon: true, + afterColon: true, + align: { + on: 'colon', + mode: 'strict', + afterColon: true, + beforeColon: true, + }, + }, + }, + ], + }, + { + code: ` +interface X { + a : number; + abc : string +}; + `, + options: [ + { + singleLine: { beforeColon: false, afterColon: false }, + multiLine: { + beforeColon: true, + afterColon: true, + align: { + mode: 'strict', + afterColon: true, + beforeColon: true, + }, + }, + }, + ], + }, + { + code: ` +interface X { + a : number; + abc : string +}; + `, + options: [ + { + beforeColon: true, + afterColon: true, + align: { + on: 'colon', + mode: 'strict', + afterColon: true, + beforeColon: true, + }, + }, + ], + }, + { + code: ` +interface X { + a : number; + abc : string +}; + `, + options: [ + { + beforeColon: true, + afterColon: true, + align: { + mode: 'strict', + afterColon: true, + beforeColon: true, + }, + }, + ], + }, + { + code: ` +interface X { + a : number; + abc: string + + xadzd : number; +}; + `, + options: [ + { + singleLine: { beforeColon: false, afterColon: false }, + multiLine: { + beforeColon: true, + afterColon: true, + align: { + on: 'colon', + mode: 'strict', + afterColon: true, + beforeColon: false, + }, + }, + }, + ], + }, + { + code: ` +interface X { + a : number; + abc: string + + xadzd : number; +}; + `, + options: [ + { + singleLine: { beforeColon: false, afterColon: false }, + multiLine: { + beforeColon: true, + afterColon: true, + mode: 'strict', + align: { + on: 'colon', + afterColon: true, + beforeColon: false, + }, + }, + }, + ], + }, + { + code: ` +interface X { + a : number; + abc: string + + xadzd : number; +}; + `, + options: [ + { + singleLine: { beforeColon: false, afterColon: false }, + multiLine: { + beforeColon: true, + afterColon: true, + mode: 'minimum', + align: { + on: 'colon', + afterColon: true, + beforeColon: false, + }, + }, + }, + ], + }, + { + code: ` +interface X { a:number; abc:string; }; + `, + options: [ + { + singleLine: { beforeColon: false, afterColon: false }, + multiLine: { beforeColon: true, afterColon: true }, + }, + ], + }, + ], + invalid: [ + // align: value + { + code: ` +interface X { + a: number; + abc: string +}; + `, + output: ` +interface X { + a: number; + abc: string +}; + `, + options: [{ align: 'value' }], + errors: [{ messageId: 'missingValue' }], + }, + { + code: ` +interface X { + a: number; + "a:c": string +}; + `, + output: ` +interface X { + a: number; + "a:c": string +}; + `, + options: [{ align: 'value' }], + errors: [{ messageId: 'missingValue' }], + }, + { + code: ` +let x: { + a: number; + abc: string +}; + `, + output: ` +let x: { + a: number; + abc: string +}; + `, + options: [{ align: 'value' }], + errors: [{ messageId: 'missingValue' }], + }, + { + code: ` +let x: { + a: number; + abc: string +}; + `, + output: ` +let x: { + a: number; + abc: string +}; + `, + options: [{ align: { on: 'value' } }], + errors: [{ messageId: 'missingValue' }], + }, + { + code: ` +let x: { + a: number; + "๐ŸŒท": "bar", // 2 code points + "๐ŸŽ": "baz", // 2 code points + "๐Ÿ‡ฎ๐Ÿ‡ณ": "qux", // 4 code points + "๐Ÿณ๏ธโ€๐ŸŒˆ": "xyz", // 6 code points + [๐Œ˜]: string + "๐Œ˜": string +}; + `, + output: ` +let x: { + a: number; + "๐ŸŒท": "bar", // 2 code points + "๐ŸŽ": "baz", // 2 code points + "๐Ÿ‡ฎ๐Ÿ‡ณ": "qux", // 4 code points + "๐Ÿณ๏ธโ€๐ŸŒˆ": "xyz", // 6 code points + [๐Œ˜]: string + "๐Œ˜": string +}; + `, + options: [{ align: 'value' }], + errors: [{ messageId: 'missingValue' }], + }, + { + code: ` +class X { + a: number; + abc: string +}; + `, + output: ` +class X { + a: number; + abc: string +}; + `, + options: [{ align: 'value' }], + errors: [{ messageId: 'missingValue' }], + }, + { + code: ` +class X { + a: number; + abc: string +}; + `, + output: ` +class X { + a: number; + abc: string +}; + `, + options: [{ align: 'value', mode: 'minimum' }], + errors: [{ messageId: 'missingValue' }], + }, + { + code: ` +class X { + a: number; + b; + abc: string +}; + `, + output: ` +class X { + a: number; + b; + abc: string +}; + `, + options: [{ align: 'value', mode: 'minimum' }], + errors: [{ messageId: 'missingValue' }], + }, + { + code: ` +type X = { + a: number; + abc: string +}; + `, + output: ` +type X = { + a: number; + abc: string +}; + `, + options: [{ align: 'value' }], + errors: [{ messageId: 'missingValue' }], + }, + { + code: ` +interface X { + a: number; + abc: string +}; + `, + output: ` +interface X { + a: number; + abc: string +}; + `, + options: [{ align: 'value' }], + errors: [{ messageId: 'extraValue' }], + }, + { + code: ` +class X { + a: number; + abc: string +}; + `, + output: ` +class X { + a: number; + abc: string +}; + `, + options: [{ align: 'value' }], + errors: [{ messageId: 'extraValue' }], + }, + { + code: ` +class X { + x: number; + z = 1; + xbcef: number; + } + `, + output: ` +class X { + x: number; + z = 1; + xbcef: number; + } + `, + options: [{ align: 'value' }], + errors: [{ messageId: 'missingValue' }], + }, + { + code: ` +interface X { + a: number; + + abc : string +}; + `, + output: ` +interface X { + a: number; + + abc: string +}; + `, + options: [{ align: 'value' }], + errors: [{ messageId: 'extraValue' }, { messageId: 'extraKey' }], + }, + { + code: ` +class X { + a: number; + + abc : string +}; + `, + output: ` +class X { + a: number; + + abc: string +}; + `, + options: [{ align: 'value' }], + errors: [{ messageId: 'extraValue' }, { messageId: 'extraKey' }], + }, + { + code: ` +interface X { + a: number; + // Some comment + + // interrupted in the middle + abc: string +}; + `, + output: ` +interface X { + a: number; + // Some comment + + // interrupted in the middle + abc: string +}; + `, + options: [{ align: 'value' }], + errors: [{ messageId: 'extraValue' }], + }, + { + code: ` +interface X { + a: number; + /** + * Multiline comment + */ + + /** interrupted in the middle */ + abc: string +}; + `, + output: ` +interface X { + a: number; + /** + * Multiline comment + */ + + /** interrupted in the middle */ + abc: string +}; + `, + options: [{ align: 'value' }], + errors: [{ messageId: 'extraValue' }], + }, + { + code: ` +interface X { + a: number; + prop: { + abc: number; + a: number; + }, + abc: string +} + `, + output: ` +interface X { + a: number; + prop: { + abc: number; + a: number; + }, + abc: string +} + `, + options: [{ align: 'value' }], + errors: [{ messageId: 'missingValue' }], + }, + { + code: ` +interface X { + a: number; + prop: { + abc: number; + a: number; + }, + abc: string +} + `, + output: ` +interface X { + a: number; + prop: { + abc: number; + a: number; + }, + abc: string +} + `, + options: [{ align: 'value' }], + errors: [{ messageId: 'missingValue' }], + }, + { + code: ` +interface X { + a: number; + prop: { + abc: number; + a: number; + }, + abc: string +} + `, + output: ` +interface X { + a: number; + prop: { + abc: number; + a: number; + }, + abc: string +} + `, + options: [{ align: 'value' }], + errors: [{ messageId: 'extraValue' }], + }, + { + code: ` +class X { + a: number; + prop: { + abc: number; + a?: number; + }; + abc: string; + x = 1; + d: number; + z: number = 1; + ef: string; +} + `, + output: ` +class X { + a: number; + prop: { + abc: number; + a?: number; + }; + abc: string; + x = 1; + d: number; + z: number = 1; + ef: string; +} + `, + options: [{ align: 'value' }], + errors: [ + { messageId: 'extraValue' }, + { messageId: 'missingValue' }, + { messageId: 'missingValue' }, + { messageId: 'missingValue' }, + { messageId: 'missingValue' }, + ], + }, + // align: colon + { + code: ` +interface X { + a : number; + abc: string +}; + `, + output: ` +interface X { + a : number; + abc: string +}; + `, + options: [{ align: 'colon' }], + errors: [{ messageId: 'extraKey' }], + }, + { + code: ` +interface X { + a : number; + abc: string +}; + `, + output: ` +interface X { + a : number; + abc: string +}; + `, + options: [{ align: { on: 'colon' } }], + errors: [{ messageId: 'extraKey' }], + }, + { + code: ` +interface X { + a : number; + abc: string +}; + `, + output: ` +interface X { + a : number; + abc : string +}; + `, + options: [{ align: 'colon', beforeColon: true, afterColon: true }], + errors: [{ messageId: 'missingKey' }], + }, + // no align + { + code: ` +interface X { + [x: number]: string; +} + `, + output: ` +interface X { + [x: number]: string; +} + `, + errors: [{ messageId: 'extraValue' }], + }, + { + code: ` +interface X { + [x: number]:string; +} + `, + output: ` +interface X { + [x: number]: string; +} + `, + errors: [{ messageId: 'missingValue' }], + }, + // singleLine / multiLine + { + code: ` +interface X { + a:number; + abc:string +}; + `, + output: ` +interface X { + a : number; + abc : string +}; + `, + options: [ + { + singleLine: { beforeColon: false, afterColon: false }, + multiLine: { beforeColon: true, afterColon: true }, + }, + ], + errors: [ + { messageId: 'missingKey' }, + { messageId: 'missingValue' }, + { messageId: 'missingKey' }, + { messageId: 'missingValue' }, + ], + }, + { + code: ` +interface X { a : number; abc : string; }; + `, + output: ` +interface X { a:number; abc:string; }; + `, + options: [ + { + singleLine: { beforeColon: false, afterColon: false }, + multiLine: { beforeColon: true, afterColon: true }, + }, + ], + errors: [ + { messageId: 'extraKey' }, + { messageId: 'extraValue' }, + { messageId: 'extraKey' }, + { messageId: 'extraValue' }, + ], + }, + { + code: ` +interface X { a : number; abc : string; }; + `, + output: ` +interface X { a: number; abc: string; }; + `, + options: [ + { + singleLine: { beforeColon: false, afterColon: true }, + multiLine: { beforeColon: true, afterColon: true }, + }, + ], + errors: [{ messageId: 'extraKey' }, { messageId: 'extraKey' }], + }, + { + code: ` +interface X { a:number; abc:string; }; + `, + output: ` +interface X { a : number; abc : string; }; + `, + options: [ + { + singleLine: { beforeColon: true, afterColon: true, mode: 'strict' }, + multiLine: { beforeColon: true, afterColon: true }, + }, + ], + errors: [ + { messageId: 'missingKey' }, + { messageId: 'missingValue' }, + { messageId: 'missingKey' }, + { messageId: 'missingValue' }, + ], + }, + { + code: ` +interface X { a:number; abc: string; }; + `, + output: ` +interface X { a : number; abc : string; }; + `, + options: [ + { + singleLine: { beforeColon: true, afterColon: true, mode: 'minimum' }, + multiLine: { beforeColon: true, afterColon: true }, + }, + ], + errors: [ + { messageId: 'missingKey' }, + { messageId: 'missingValue' }, + { messageId: 'missingKey' }, + ], + }, + { + code: ` +interface X { a : number; abc : string; }; + `, + output: ` +interface X { a:number; abc:string; }; + `, + options: [ + { + beforeColon: false, + afterColon: false, + }, + ], + errors: [ + { messageId: 'extraKey' }, + { messageId: 'extraValue' }, + { messageId: 'extraKey' }, + { messageId: 'extraValue' }, + ], + }, + { + code: ` +interface X { a:number; abc:string; }; + `, + output: ` +interface X { a : number; abc : string; }; + `, + options: [ + { + beforeColon: true, + afterColon: true, + mode: 'strict', + }, + ], + errors: [ + { messageId: 'missingKey' }, + { messageId: 'missingValue' }, + { messageId: 'missingKey' }, + { messageId: 'missingValue' }, + ], + }, + { + code: ` +type Wacky = { + a: number; + b: string; + agc: number; + middle: Date | { + inner: { + a: boolean; + bc: boolean; + "๐ŸŒท": "rose"; + } + [x: number]: string; + abc: boolean; + } +} & { + a: "string"; + abc: number; +} + `, + output: ` +type Wacky = { + a: number; + b: string; + agc: number; + middle: Date | { + inner: { + a: boolean; + bc: boolean; + "๐ŸŒท": "rose"; + } + [x: number]: string; + abc: boolean; + } +} & { + a: "string"; + abc: number; +} + `, + options: [{ align: 'value' }], + errors: [ + { messageId: 'missingValue' }, + { messageId: 'missingValue' }, + { messageId: 'missingValue' }, + { messageId: 'missingValue' }, + { messageId: 'missingValue' }, + { messageId: 'missingValue' }, + { messageId: 'missingValue' }, + ], + }, + { + code: ` +class Wacky { + a: number; + b?: string; + public z: number; + abc = 10; + private override xy: number; + static x = "test"; + static abcdef: number = 1; + get fn(): number { return 0; }; + inter: number; + get fn2(): number { + return 1; + }; + agc: number; + middle: Date | { + inner: { + a: boolean; + bc: boolean; + "๐ŸŒท": "rose"; + } + [x: number]: string; + abc: boolean; + } +} + `, + output: ` +class Wacky { + a: number; + b?: string; + public z: number; + abc = 10; + private override xy: number; + static x = "test"; + static abcdef: number = 1; + get fn(): number { return 0; }; + inter: number; + get fn2(): number { + return 1; + }; + agc: number; + middle: Date | { + inner: { + a: boolean; + bc: boolean; + "๐ŸŒท": "rose"; + } + [x: number]: string; + abc: boolean; + } +} + `, + options: [{ align: 'value' }], + errors: [ + { messageId: 'missingValue' }, + { messageId: 'missingValue' }, + { messageId: 'missingValue' }, + { messageId: 'missingValue' }, + { messageId: 'missingValue' }, + { messageId: 'missingValue' }, + { messageId: 'missingValue' }, + { messageId: 'missingValue' }, + { messageId: 'missingValue' }, + ], + }, + ], +}); diff --git a/packages/eslint-plugin/typings/eslint-rules.d.ts b/packages/eslint-plugin/typings/eslint-rules.d.ts index 09b54ae4a516..38682f60c5b2 100644 --- a/packages/eslint-plugin/typings/eslint-rules.d.ts +++ b/packages/eslint-plugin/typings/eslint-rules.d.ts @@ -141,6 +141,58 @@ declare module 'eslint/lib/rules/indent' { export = rule; } +declare module 'eslint/lib/rules/key-spacing' { + import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; + import type { RuleFunction } from '@typescript-eslint/utils/dist/ts-eslint'; + + type Options = [ + { + beforeColon?: boolean; + afterColon?: boolean; + mode?: 'strict' | 'minimum'; + align?: + | 'value' + | 'colon' + | { + on?: 'value' | 'colon'; + beforeColon?: boolean; + afterColon?: boolean; + mode?: 'strict' | 'minimum'; + }; + singleLine?: { + beforeColon?: boolean; + afterColon?: boolean; + mode?: 'strict' | 'minimum'; + }; + multiLine?: { + beforeColon?: boolean; + afterColon?: boolean; + mode?: 'strict' | 'minimum'; + align?: + | 'value' + | 'colon' + | { + on?: 'value' | 'colon'; + beforeColon?: boolean; + afterColon?: boolean; + mode?: 'strict' | 'minimum'; + }; + }; + }, + ]; + type MessageIds = 'extraKey' | 'extraValue' | 'missingKey' | 'missingValue'; + + const rule: TSESLint.RuleModule< + MessageIds, + Options, + { + ObjectExpression: RuleFunction; + Property: RuleFunction; + } + >; + export = rule; +} + declare module 'eslint/lib/rules/keyword-spacing' { import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import type { RuleFunction } from '@typescript-eslint/utils/dist/ts-eslint'; From 033e87cb71a54c895a6165da3fe514bb5ba5b6c6 Mon Sep 17 00:00:00 2001 From: Jeffrey Bosch Date: Wed, 25 Jan 2023 18:30:13 +0100 Subject: [PATCH 04/19] test: verify that there are no errors on the website (#6365) closes: #6354 --- packages/website/tests/index.spec.ts | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/website/tests/index.spec.ts b/packages/website/tests/index.spec.ts index 1fd2a70b413d..e0a99f3d12cc 100644 --- a/packages/website/tests/index.spec.ts +++ b/packages/website/tests/index.spec.ts @@ -1,7 +1,22 @@ import AxeBuilder from '@axe-core/playwright'; -import { test } from '@playwright/test'; +import { expect, test } from '@playwright/test'; -test('Index', async ({ page }) => { - await page.goto('/'); - await new AxeBuilder({ page }).analyze(); +test.describe('Website', () => { + test('Axe', async ({ page }) => { + await page.goto('/'); + await new AxeBuilder({ page }).analyze(); + }); + + test('should have no errors', async ({ page }) => { + const errorMessages: string[] = []; + page.on('console', msg => { + if (['error', 'warning'].includes(msg.type())) { + errorMessages.push(`[${msg.type()}] ${msg.text()}`); + } + }); + await page.goto('/'); + expect(errorMessages).toStrictEqual([ + "[error] Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot", + ]); + }); }); From b0f6c8ec0b372696ef26ca3a2b4f82dafd9dc417 Mon Sep 17 00:00:00 2001 From: Sviatoslav Zaytsev Date: Thu, 26 Jan 2023 19:18:52 +0300 Subject: [PATCH 05/19] fix(eslint-plugin): [prefer-optional-chain] fixer produces wrong logic (#5919) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(eslint-plugin): [prefer-optional-chain] fixer produces wrong logic (#1438) * Update packages/eslint-plugin/src/rules/prefer-optional-chain.ts * fix(eslint-plugin): [prefer-optional-chain] fix tests * fix(eslint-plugin): [prefer-optional-chain] fix tests Co-authored-by: Josh Goldberg Co-authored-by: ะกะฒัั‚ะพัะปะฐะฒ ะ—ะฐะนั†ะตะฒ --- .../src/rules/prefer-optional-chain.ts | 16 +- .../rules/prefer-optional-chain/base-cases.ts | 228 ++++++++++++++++++ .../prefer-optional-chain.test.ts | 208 +++------------- 3 files changed, 273 insertions(+), 179 deletions(-) create mode 100644 packages/eslint-plugin/tests/rules/prefer-optional-chain/base-cases.ts rename packages/eslint-plugin/tests/rules/{ => prefer-optional-chain}/prefer-optional-chain.test.ts (85%) diff --git a/packages/eslint-plugin/src/rules/prefer-optional-chain.ts b/packages/eslint-plugin/src/rules/prefer-optional-chain.ts index 9a4949b734bc..f5ed3ccb5897 100644 --- a/packages/eslint-plugin/src/rules/prefer-optional-chain.ts +++ b/packages/eslint-plugin/src/rules/prefer-optional-chain.ts @@ -490,10 +490,20 @@ function reportIfMoreThanOne({ shouldHandleChainedAnds && previous.right.type === AST_NODE_TYPES.BinaryExpression ) { + let operator = previous.right.operator; + if ( + previous.right.operator === '!==' && + // TODO(#4820): Use the type checker to know whether this is `null` + previous.right.right.type === AST_NODE_TYPES.Literal && + previous.right.right.raw === 'null' + ) { + // case like foo !== null && foo.bar !== null + operator = '!='; + } // case like foo && foo.bar !== someValue - optionallyChainedCode += ` ${ - previous.right.operator - } ${sourceCode.getText(previous.right.right)}`; + optionallyChainedCode += ` ${operator} ${sourceCode.getText( + previous.right.right, + )}`; } context.report({ diff --git a/packages/eslint-plugin/tests/rules/prefer-optional-chain/base-cases.ts b/packages/eslint-plugin/tests/rules/prefer-optional-chain/base-cases.ts new file mode 100644 index 000000000000..99cfe6b0ff9b --- /dev/null +++ b/packages/eslint-plugin/tests/rules/prefer-optional-chain/base-cases.ts @@ -0,0 +1,228 @@ +import type { TSESLint } from '@typescript-eslint/utils'; + +import type rule from '../../../src/rules/prefer-optional-chain'; +import type { + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +} from '../../../src/util'; + +type InvalidTestCase = TSESLint.InvalidTestCase< + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule +>; + +interface BaseCase { + canReplaceAndWithOr: boolean; + output: string; + code: string; +} + +const mapper = (c: BaseCase): InvalidTestCase => ({ + code: c.code.trim(), + output: null, + errors: [ + { + messageId: 'preferOptionalChain', + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: c.output.trim(), + }, + ], + }, + ], +}); + +const baseCases: Array = [ + // chained members + { + code: 'foo && foo.bar', + output: 'foo?.bar', + canReplaceAndWithOr: true, + }, + { + code: 'foo.bar && foo.bar.baz', + output: 'foo.bar?.baz', + canReplaceAndWithOr: true, + }, + { + code: 'foo && foo()', + output: 'foo?.()', + canReplaceAndWithOr: true, + }, + { + code: 'foo.bar && foo.bar()', + output: 'foo.bar?.()', + canReplaceAndWithOr: true, + }, + { + code: 'foo && foo.bar && foo.bar.baz && foo.bar.baz.buzz', + output: 'foo?.bar?.baz?.buzz', + canReplaceAndWithOr: true, + }, + { + code: 'foo.bar && foo.bar.baz && foo.bar.baz.buzz', + output: 'foo.bar?.baz?.buzz', + canReplaceAndWithOr: true, + }, + // case with a jump (i.e. a non-nullish prop) + { + code: 'foo && foo.bar && foo.bar.baz.buzz', + output: 'foo?.bar?.baz.buzz', + canReplaceAndWithOr: true, + }, + { + code: 'foo.bar && foo.bar.baz.buzz', + output: 'foo.bar?.baz.buzz', + canReplaceAndWithOr: true, + }, + // case where for some reason there is a doubled up expression + { + code: 'foo && foo.bar && foo.bar.baz && foo.bar.baz && foo.bar.baz.buzz', + output: 'foo?.bar?.baz?.buzz', + canReplaceAndWithOr: true, + }, + { + code: 'foo.bar && foo.bar.baz && foo.bar.baz && foo.bar.baz.buzz', + output: 'foo.bar?.baz?.buzz', + canReplaceAndWithOr: true, + }, + // chained members with element access + { + code: 'foo && foo[bar] && foo[bar].baz && foo[bar].baz.buzz', + output: 'foo?.[bar]?.baz?.buzz', + canReplaceAndWithOr: true, + }, + { + // case with a jump (i.e. a non-nullish prop) + code: 'foo && foo[bar].baz && foo[bar].baz.buzz', + output: 'foo?.[bar].baz?.buzz', + canReplaceAndWithOr: true, + }, + // case with a property access in computed property + { + code: 'foo && foo[bar.baz] && foo[bar.baz].buzz', + output: 'foo?.[bar.baz]?.buzz', + canReplaceAndWithOr: true, + }, + // case with this keyword + { + code: 'foo[this.bar] && foo[this.bar].baz', + output: 'foo[this.bar]?.baz', + canReplaceAndWithOr: true, + }, + // chained calls + { + code: 'foo && foo.bar && foo.bar.baz && foo.bar.baz.buzz()', + output: 'foo?.bar?.baz?.buzz()', + canReplaceAndWithOr: true, + }, + { + code: 'foo && foo.bar && foo.bar.baz && foo.bar.baz.buzz && foo.bar.baz.buzz()', + output: 'foo?.bar?.baz?.buzz?.()', + canReplaceAndWithOr: true, + }, + { + code: 'foo.bar && foo.bar.baz && foo.bar.baz.buzz && foo.bar.baz.buzz()', + output: 'foo.bar?.baz?.buzz?.()', + canReplaceAndWithOr: true, + }, + // case with a jump (i.e. a non-nullish prop) + { + code: 'foo && foo.bar && foo.bar.baz.buzz()', + output: 'foo?.bar?.baz.buzz()', + canReplaceAndWithOr: true, + }, + { + code: 'foo.bar && foo.bar.baz.buzz()', + output: 'foo.bar?.baz.buzz()', + canReplaceAndWithOr: true, + }, + { + // case with a jump (i.e. a non-nullish prop) + code: 'foo && foo.bar && foo.bar.baz.buzz && foo.bar.baz.buzz()', + output: 'foo?.bar?.baz.buzz?.()', + canReplaceAndWithOr: true, + }, + { + // case with a call expr inside the chain for some inefficient reason + code: 'foo && foo.bar() && foo.bar().baz && foo.bar().baz.buzz && foo.bar().baz.buzz()', + output: 'foo?.bar()?.baz?.buzz?.()', + canReplaceAndWithOr: true, + }, + // chained calls with element access + { + code: 'foo && foo.bar && foo.bar.baz && foo.bar.baz[buzz]()', + output: 'foo?.bar?.baz?.[buzz]()', + canReplaceAndWithOr: true, + }, + { + code: 'foo && foo.bar && foo.bar.baz && foo.bar.baz[buzz] && foo.bar.baz[buzz]()', + output: 'foo?.bar?.baz?.[buzz]?.()', + canReplaceAndWithOr: true, + }, + // (partially) pre-optional chained + { + code: 'foo && foo?.bar && foo?.bar.baz && foo?.bar.baz[buzz] && foo?.bar.baz[buzz]()', + output: 'foo?.bar?.baz?.[buzz]?.()', + canReplaceAndWithOr: true, + }, + { + code: 'foo && foo?.bar.baz && foo?.bar.baz[buzz]', + output: 'foo?.bar.baz?.[buzz]', + canReplaceAndWithOr: true, + }, + { + code: 'foo && foo?.() && foo?.().bar', + output: 'foo?.()?.bar', + canReplaceAndWithOr: true, + }, + { + code: 'foo.bar && foo.bar?.() && foo.bar?.().baz', + output: 'foo.bar?.()?.baz', + canReplaceAndWithOr: true, + }, + { + code: 'foo !== null && foo.bar !== null', + output: 'foo?.bar != null', + canReplaceAndWithOr: false, + }, + { + code: 'foo != null && foo.bar != null', + output: 'foo?.bar != null', + canReplaceAndWithOr: false, + }, + { + code: 'foo != null && foo.bar !== null', + output: 'foo?.bar != null', + canReplaceAndWithOr: false, + }, + { + code: 'foo !== null && foo.bar != null', + output: 'foo?.bar != null', + canReplaceAndWithOr: false, + }, +]; + +interface Selector { + all(): Array; + select>( + key: K, + value: BaseCase[K], + ): Selector; +} + +const selector = (cases: Array): Selector => ({ + all: () => cases.map(mapper), + select: >( + key: K, + value: BaseCase[K], + ): Selector => { + const selectedCases = baseCases.filter(c => c[key] === value); + return selector(selectedCases); + }, +}); + +const { all, select } = selector(baseCases); + +export { all, select }; diff --git a/packages/eslint-plugin/tests/rules/prefer-optional-chain.test.ts b/packages/eslint-plugin/tests/rules/prefer-optional-chain/prefer-optional-chain.test.ts similarity index 85% rename from packages/eslint-plugin/tests/rules/prefer-optional-chain.test.ts rename to packages/eslint-plugin/tests/rules/prefer-optional-chain/prefer-optional-chain.test.ts index 120ad20aaeac..ca783df13b32 100644 --- a/packages/eslint-plugin/tests/rules/prefer-optional-chain.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-optional-chain/prefer-optional-chain.test.ts @@ -1,160 +1,11 @@ -import type { TSESLint } from '@typescript-eslint/utils'; - -import rule from '../../src/rules/prefer-optional-chain'; -import type { - InferMessageIdsTypeFromRule, - InferOptionsTypeFromRule, -} from '../../src/util'; -import { noFormat, RuleTester } from '../RuleTester'; +import rule from '../../../src/rules/prefer-optional-chain'; +import { noFormat, RuleTester } from '../../RuleTester'; +import * as BaseCases from './base-cases'; const ruleTester = new RuleTester({ parser: '@typescript-eslint/parser', }); -const baseCases = [ - // chained members - { - code: 'foo && foo.bar', - output: 'foo?.bar', - }, - { - code: 'foo.bar && foo.bar.baz', - output: 'foo.bar?.baz', - }, - { - code: 'foo && foo()', - output: 'foo?.()', - }, - { - code: 'foo.bar && foo.bar()', - output: 'foo.bar?.()', - }, - { - code: 'foo && foo.bar && foo.bar.baz && foo.bar.baz.buzz', - output: 'foo?.bar?.baz?.buzz', - }, - { - code: 'foo.bar && foo.bar.baz && foo.bar.baz.buzz', - output: 'foo.bar?.baz?.buzz', - }, - // case with a jump (i.e. a non-nullish prop) - { - code: 'foo && foo.bar && foo.bar.baz.buzz', - output: 'foo?.bar?.baz.buzz', - }, - { - code: 'foo.bar && foo.bar.baz.buzz', - output: 'foo.bar?.baz.buzz', - }, - // case where for some reason there is a doubled up expression - { - code: 'foo && foo.bar && foo.bar.baz && foo.bar.baz && foo.bar.baz.buzz', - output: 'foo?.bar?.baz?.buzz', - }, - { - code: 'foo.bar && foo.bar.baz && foo.bar.baz && foo.bar.baz.buzz', - output: 'foo.bar?.baz?.buzz', - }, - // chained members with element access - { - code: 'foo && foo[bar] && foo[bar].baz && foo[bar].baz.buzz', - output: 'foo?.[bar]?.baz?.buzz', - }, - { - // case with a jump (i.e. a non-nullish prop) - code: 'foo && foo[bar].baz && foo[bar].baz.buzz', - output: 'foo?.[bar].baz?.buzz', - }, - // case with a property access in computed property - { - code: 'foo && foo[bar.baz] && foo[bar.baz].buzz', - output: 'foo?.[bar.baz]?.buzz', - }, - // case with this keyword - { - code: 'foo[this.bar] && foo[this.bar].baz', - output: 'foo[this.bar]?.baz', - }, - // chained calls - { - code: 'foo && foo.bar && foo.bar.baz && foo.bar.baz.buzz()', - output: 'foo?.bar?.baz?.buzz()', - }, - { - code: 'foo && foo.bar && foo.bar.baz && foo.bar.baz.buzz && foo.bar.baz.buzz()', - output: 'foo?.bar?.baz?.buzz?.()', - }, - { - code: 'foo.bar && foo.bar.baz && foo.bar.baz.buzz && foo.bar.baz.buzz()', - output: 'foo.bar?.baz?.buzz?.()', - }, - // case with a jump (i.e. a non-nullish prop) - { - code: 'foo && foo.bar && foo.bar.baz.buzz()', - output: 'foo?.bar?.baz.buzz()', - }, - { - code: 'foo.bar && foo.bar.baz.buzz()', - output: 'foo.bar?.baz.buzz()', - }, - { - // case with a jump (i.e. a non-nullish prop) - code: 'foo && foo.bar && foo.bar.baz.buzz && foo.bar.baz.buzz()', - output: 'foo?.bar?.baz.buzz?.()', - }, - { - // case with a call expr inside the chain for some inefficient reason - code: 'foo && foo.bar() && foo.bar().baz && foo.bar().baz.buzz && foo.bar().baz.buzz()', - output: 'foo?.bar()?.baz?.buzz?.()', - }, - // chained calls with element access - { - code: 'foo && foo.bar && foo.bar.baz && foo.bar.baz[buzz]()', - output: 'foo?.bar?.baz?.[buzz]()', - }, - { - code: 'foo && foo.bar && foo.bar.baz && foo.bar.baz[buzz] && foo.bar.baz[buzz]()', - output: 'foo?.bar?.baz?.[buzz]?.()', - }, - // (partially) pre-optional chained - { - code: 'foo && foo?.bar && foo?.bar.baz && foo?.bar.baz[buzz] && foo?.bar.baz[buzz]()', - output: 'foo?.bar?.baz?.[buzz]?.()', - }, - { - code: 'foo && foo?.bar.baz && foo?.bar.baz[buzz]', - output: 'foo?.bar.baz?.[buzz]', - }, - { - code: 'foo && foo?.() && foo?.().bar', - output: 'foo?.()?.bar', - }, - { - code: 'foo.bar && foo.bar?.() && foo.bar?.().baz', - output: 'foo.bar?.()?.baz', - }, -].map( - c => - ({ - code: c.code.trim(), - output: null, - errors: [ - { - messageId: 'preferOptionalChain', - suggestions: [ - { - messageId: 'optionalChainSuggest', - output: c.output.trim(), - }, - ], - }, - ], - } as TSESLint.InvalidTestCase< - InferMessageIdsTypeFromRule, - InferOptionsTypeFromRule - >), -); - ruleTester.run('prefer-optional-chain', rule, { valid: [ '!a || !b;', @@ -219,18 +70,18 @@ ruleTester.run('prefer-optional-chain', rule, { '!new.target || true;', ], invalid: [ - ...baseCases, + ...BaseCases.all(), // it should ignore whitespace in the expressions - ...baseCases.map(c => ({ + ...BaseCases.all().map(c => ({ ...c, code: c.code.replace(/\./g, '. '), })), - ...baseCases.map(c => ({ + ...BaseCases.all().map(c => ({ ...c, code: c.code.replace(/\./g, '.\n'), })), // it should ignore parts of the expression that aren't part of the expression chain - ...baseCases.map(c => ({ + ...BaseCases.all().map(c => ({ ...c, code: `${c.code} && bing`, errors: [ @@ -245,7 +96,7 @@ ruleTester.run('prefer-optional-chain', rule, { }, ], })), - ...baseCases.map(c => ({ + ...BaseCases.all().map(c => ({ ...c, code: `${c.code} && bing.bong`, errors: [ @@ -261,22 +112,42 @@ ruleTester.run('prefer-optional-chain', rule, { ], })), // strict nullish equality checks x !== null && x.y !== null - ...baseCases.map(c => ({ + ...BaseCases.all().map(c => ({ ...c, code: c.code.replace(/&&/g, '!== null &&'), })), - ...baseCases.map(c => ({ + ...BaseCases.all().map(c => ({ ...c, code: c.code.replace(/&&/g, '!= null &&'), })), - ...baseCases.map(c => ({ + ...BaseCases.all().map(c => ({ ...c, code: c.code.replace(/&&/g, '!== undefined &&'), })), - ...baseCases.map(c => ({ + ...BaseCases.all().map(c => ({ ...c, code: c.code.replace(/&&/g, '!= undefined &&'), })), + + // replace && with ||: foo && foo.bar -> !foo || !foo.bar + ...BaseCases.select('canReplaceAndWithOr', true) + .all() + .map(c => ({ + ...c, + code: c.code.replace(/(^|\s)foo/g, '$1!foo').replace(/&&/g, '||'), + errors: [ + { + ...c.errors[0], + suggestions: [ + { + ...c.errors[0].suggestions![0], + output: `!${c.errors[0].suggestions![0].output}`, + }, + ], + }, + ], + })), + // two errors { code: noFormat`foo && foo.bar && foo.bar.baz || baz && baz.bar && baz.bar.foo`, @@ -1211,21 +1082,6 @@ foo?.bar(/* comment */a, }, ], }, - ...baseCases.map(c => ({ - ...c, - code: c.code.replace(/foo/g, '!foo').replace(/&&/g, '||'), - errors: [ - { - ...c.errors[0], - suggestions: [ - { - ...c.errors[0].suggestions![0], - output: `!${c.errors[0].suggestions![0].output}`, - }, - ], - }, - ], - })), // case with this keyword at the start of expression { code: '!this.bar || !this.bar.baz;', From f17d34b74c83d4fed8dc4224d3594a6b44c19952 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Sun, 29 Jan 2023 20:44:01 -0500 Subject: [PATCH 06/19] docs(eslint-plugin): update site description of ban-types docs (#6209) --- packages/eslint-plugin/docs/rules/ban-types.md | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/ban-types.md b/packages/eslint-plugin/docs/rules/ban-types.md index 016b2a7217e7..3f2e663669a8 100644 --- a/packages/eslint-plugin/docs/rules/ban-types.md +++ b/packages/eslint-plugin/docs/rules/ban-types.md @@ -72,12 +72,6 @@ The default options provide a set of "best practices", intended to provide safet - This is a point of confusion for many developers, who think it means "any object type". - See [this comment for more information](https://github.com/typescript-eslint/typescript-eslint/issues/2063#issuecomment-675156492). -:::important - -The default options suggest using `Record`; this was a stylistic decision, as the built-in `Record` type is considered to look cleaner. - -::: -
Default Options @@ -115,15 +109,16 @@ const defaultTypes = { Object: { message: [ 'The `Object` type actually means "any non-nullish value", so it is marginally better than `unknown`.', - '- If you want a type meaning "any object", you probably want `Record` instead.', + '- If you want a type meaning "any object", you probably want `object` instead.', '- If you want a type meaning "any value", you probably want `unknown` instead.', ].join('\n'), }, '{}': { message: [ '`{}` actually means "any non-nullish value".', - '- If you want a type meaning "any object", you probably want `Record` instead.', + '- If you want a type meaning "any object", you probably want `object` instead.', '- If you want a type meaning "any value", you probably want `unknown` instead.', + '- If you want a type meaning "empty object", you probably want `Record` instead.', ].join('\n'), }, }; From 1623350899c5d0ac8776933ca99f0561d0ec1827 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Sun, 29 Jan 2023 20:44:14 -0500 Subject: [PATCH 07/19] docs(eslint-plugin): corrected eslint-plugin README.md getting started link (#6223) --- packages/eslint-plugin/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index b9dd0cecd032..9c98f8c7d4b6 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -5,6 +5,6 @@ An ESLint plugin which provides lint rules for TypeScript codebases. [![NPM Version](https://img.shields.io/npm/v/@typescript-eslint/eslint-plugin.svg?style=flat-square)](https://www.npmjs.com/package/@typescript-eslint/eslint-plugin) [![NPM Downloads](https://img.shields.io/npm/dm/@typescript-eslint/eslint-plugin.svg?style=flat-square)](https://www.npmjs.com/package/@typescript-eslint/eslint-plugin) -๐Ÿ‘‰ See **https://typescript-eslint.io/architecture/utils** for our Getting Started docs. +๐Ÿ‘‰ See **https://typescript-eslint.io/getting-started** for our Getting Started docs. > See https://typescript-eslint.io for general documentation on typescript-eslint, the tooling that allows you to run ESLint and Prettier on TypeScript code. From 403f2afc1a33f9ef3d6e4f6b97894c4773424815 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Sun, 29 Jan 2023 20:44:55 -0500 Subject: [PATCH 08/19] docs: explained tsconfigRootDir in website (#6236) --- docs/architecture/Parser.mdx | 3 ++- docs/linting/Typed_Linting.md | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/docs/architecture/Parser.mdx b/docs/architecture/Parser.mdx index 9f5d51a53bb6..d8d4f05ee43d 100644 --- a/docs/architecture/Parser.mdx +++ b/docs/architecture/Parser.mdx @@ -226,7 +226,8 @@ For example, by default it will ensure that a glob like `./**/tsconfig.json` wil > Default `undefined`. -This option allows you to provide the root directory for relative tsconfig paths specified in the `project` option above. +This option allows you to provide the root directory for relative TSConfig paths specified in the `project` option above. +Doing so ensures running ESLint from a directory other than the root will still be able to find your TSConfig. ### `warnOnUnsupportedTypeScriptVersion` diff --git a/docs/linting/Typed_Linting.md b/docs/linting/Typed_Linting.md index 3e1beb396a8a..65e2c875fff9 100644 --- a/docs/linting/Typed_Linting.md +++ b/docs/linting/Typed_Linting.md @@ -8,30 +8,30 @@ To tap into TypeScript's additional powers, there are two small changes you need ```js title=".eslintrc.js" module.exports = { - root: true, - parser: '@typescript-eslint/parser', - // Added lines start - parserOptions: { - tsconfigRootDir: __dirname, - project: ['./tsconfig.json'], - }, - // Added lines end - plugins: ['@typescript-eslint'], extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended', // Add this line 'plugin:@typescript-eslint/recommended-requiring-type-checking', ], + plugins: ['@typescript-eslint'], + parser: '@typescript-eslint/parser', + // Added lines start + parserOptions: { + project: ['./tsconfig.json'], + tsconfigRootDir: __dirname, + }, + // Added lines end + root: true, }; ``` In more detail: -- `parserOptions.tsconfigRootDir` tells our parser the absolute path of your project's root directory. +- `plugin:@typescript-eslint/recommended-requiring-type-checking` is another [recommended configuration](./CONFIGURATIONS.mdx) we provide. This one contains recommended rules that additionally require type information. - `parserOptions.project` tells our parser the relative path where your project's `tsconfig.json` is. - If your project is a multi-package monorepo, see [our docs on configuring a monorepo](./typed-linting/Monorepos.md). -- `plugin:@typescript-eslint/recommended-requiring-type-checking` is another recommended configuration we provide. This one contains rules that specifically require type information. +- `parserOptions.tsconfigRootDir` tells our parser the absolute path of your project's root directory (see [Parser#tsconfigRootDir](../architecture/Parser.mdx#tsconfigRootDir)). With that done, run the same lint command you ran before. You may see new rules reporting errors based on type information! From e8d2af308eb9e82181e47c553d13cda65083e678 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Sun, 29 Jan 2023 21:09:43 -0500 Subject: [PATCH 09/19] docs: added Contributing > Discussions page (#6249) --- .cspell.json | 1 + docs/contributing/Discussions.md | 28 +++++++++++++++++++++++ docs/maintenance/ISSUES.md | 2 +- packages/website/sidebars/sidebar.base.js | 1 + 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 docs/contributing/Discussions.md diff --git a/.cspell.json b/.cspell.json index f1806362b478..edd2532abf92 100644 --- a/.cspell.json +++ b/.cspell.json @@ -62,6 +62,7 @@ "declarators", "destructure", "destructured", + "discoverability", "dprint", "errored", "erroring", diff --git a/docs/contributing/Discussions.md b/docs/contributing/Discussions.md new file mode 100644 index 000000000000..52de99914096 --- /dev/null +++ b/docs/contributing/Discussions.md @@ -0,0 +1,28 @@ +--- +id: discussions +title: Discussions +--- + +Most proposals in the typescript-eslint repository happen in [GitHub Issues](https://docs.github.com/issues). +We generally try to keep conversations inside issues for their discoverability and ability to be linked to [GitHub Pull Requests](https://docs.github.com/pull-requests). + +We have [GitHub Discussions](https://docs.github.com/discussions) enabled to enable three kinds of deeper, threaded conversations: + +- **Community Feedback**: Questions from the maintainer team that should be raised to the broader community +- **RFCs (Requests For Comments)**: Formalized proposals for larger changes that should be discussed before turned into issues +- **Technical Discussions**: Deeper questions about typescript-eslint's architecture and/or APIs + +Before filing a Discussion, search the issue tracker for any related conversations. +Link to them in the Discussion, along with a detailed description of what you'd like to discuss. + +:::tip +For change proposals that match an [existing issue format](https://github.com/typescript-eslint/typescript-eslint/issues/new/choose), keep to filing issues. +Most don't need to be moved to this separate format. +We can always move an issue to a discussion if it becomes unexpectedly deep. +::: + +:::caution +Please don't use Discussions as a support forum. +We don't have the maintainer-budget to handle that. +See [Issues > Questions and Support Requests](./Issues.mdx#questions-and-support-requests). +::: diff --git a/docs/maintenance/ISSUES.md b/docs/maintenance/ISSUES.md index ebddcc6df1b4..012ece57fff7 100644 --- a/docs/maintenance/ISSUES.md +++ b/docs/maintenance/ISSUES.md @@ -3,7 +3,7 @@ id: issues title: Issues --- -This document serves as a guide for how you might manage issues, also known as issue triaging. +This document serves as a guide for how you might manage our [GitHub Issues](https://docs.github.com/issues), also known as issue triaging. Use your best judgement when triaging issues, and most of all remember to be **kind, friendly, and encouraging** when responding to users. Many users are new to open source and/or typed linting. diff --git a/packages/website/sidebars/sidebar.base.js b/packages/website/sidebars/sidebar.base.js index e6e7401727f1..770ab620ec02 100644 --- a/packages/website/sidebars/sidebar.base.js +++ b/packages/website/sidebars/sidebar.base.js @@ -39,6 +39,7 @@ module.exports = { 'custom-rules', { items: [ + 'contributing/discussions', 'contributing/issues', 'contributing/local-development', 'contributing/pull-requests', From 2545b6828780612d31f270c4cba75bcbdcbc33c2 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Sun, 29 Jan 2023 21:16:52 -0500 Subject: [PATCH 10/19] docs(website): added maintenance docs for rule feature requests (#6254) --- docs/maintenance/ISSUES.md | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/docs/maintenance/ISSUES.md b/docs/maintenance/ISSUES.md index 012ece57fff7..e7850e3a4b3c 100644 --- a/docs/maintenance/ISSUES.md +++ b/docs/maintenance/ISSUES.md @@ -93,13 +93,41 @@ These bugs should be reported with a link to a GitHub repository that can be che If you cannot reproduce the issue as described using repository's README.md and issue description, it has not provided enough information. Consider using a specific response like the _Needs Full Reproduction_ response. -### โœจ Rule Enhancements +### ๐Ÿ— Feature Requests -TODO: This will be filled out... soon! +For any feature request, make sure the requested support is either: -### ๐Ÿš€ New Rules +- Very useful for at least one commonly used way to run TypeScript (e.g. tsc-built CLI package; bundler-managed web app) +- Relevant for _most_ projects that would be using typescript-eslint -TODO: This will be filled out... soon! +We avoid features that: + +- Are only relevant for a minority of users, as they aren't likely worth the maintenance burden +- Aren't TypeScript-specific (e.g. should be in ESLint core instead) +- Are only relevant with specific userland frameworks or libraries, such as Jest or React +- Are for "formatting" functionality (we [strongly recommend users use a separate dedicated formatter](../linting/troubleshooting/FORMATTING.md)) + +#### โœจ Rule Enhancements + +We're generally accepting of rule enhancements that meet the above feature request criteria. +If a rule enhancement would substantially change the target area of the rule, consider whether it should instead be a new rule. +Common signs of this are the rule's original name now being inaccurate, or some options being relevant just for the old functionality. + +Enhancements that can cause new reports to be reported are considered breaking changes. +We have two common strategies for them: + +- Treat the enhancement as a breaking change, and block merging it until the next major version +- Add an option to disable the new logic: which is a breaking change if opt-in, and a non-breaking change if opt-out +- Add an option to enable the new logic: which is a breaking change if opt-out, and a non-breaking change if opt-in + +See [Can we standardize logical direction of rule options?](https://github.com/typescript-eslint/typescript-eslint/discussions/6101) for context on naming options. + +For enhancements meant to limit which kinds of nodes the rule targets, mark the issue as blocked on [RFC: Common format to specify a type or value as a rule option](https://github.com/typescript-eslint/typescript-eslint/discussions/6017). + +#### ๐Ÿš€ New Rules + +We're generally accepting of new rules that meet the above feature request criteria. +The biggest exception is rules that can roughly be implemented with [`@typescript-eslint/ban-types`](https://typescript-eslint.io/rules/ban-types) and/or [`no-restricted-syntax`](https://eslint.org/docs/latest/rules/no-restricted-syntax). ## Pruning Old Issues From f53bcbc4ba9d67612b61340a2c98d12fe9186985 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Mon, 30 Jan 2023 02:31:23 -0500 Subject: [PATCH 11/19] chore(website): add links to and widen Silver Supporters (#6327) --- .../FinancialContributors/Sponsor.tsx | 34 ++++++++----------- .../FinancialContributors/Sponsors/index.tsx | 8 ++--- .../Sponsors/styles.module.css | 1 - .../FinancialContributors/index.tsx | 3 +- .../FinancialContributors/styles.module.css | 15 ++++---- .../components/FinancialContributors/types.ts | 5 --- 6 files changed, 29 insertions(+), 37 deletions(-) diff --git a/packages/website/src/components/FinancialContributors/Sponsor.tsx b/packages/website/src/components/FinancialContributors/Sponsor.tsx index 06f53dd438f1..c50ab89b609c 100644 --- a/packages/website/src/components/FinancialContributors/Sponsor.tsx +++ b/packages/website/src/components/FinancialContributors/Sponsor.tsx @@ -1,17 +1,17 @@ import React from 'react'; import styles from './styles.module.css'; -import type { SponsorData, SponsorIncludeOptions } from './types'; +import type { SponsorData } from './types'; interface SponsorProps { - include?: SponsorIncludeOptions; + includeName?: boolean; sponsor: SponsorData; } -export function Sponsor({ include = {}, sponsor }: SponsorProps): JSX.Element { +export function Sponsor({ includeName, sponsor }: SponsorProps): JSX.Element { let children = {`${sponsor.name}; - if (include.name) { + if (includeName) { children = ( <> {children} @@ -20,19 +20,15 @@ export function Sponsor({ include = {}, sponsor }: SponsorProps): JSX.Element { ); } - if (include.link) { - children = ( - - {children} - - ); - } - - return children; + return ( + + {children} + + ); } diff --git a/packages/website/src/components/FinancialContributors/Sponsors/index.tsx b/packages/website/src/components/FinancialContributors/Sponsors/index.tsx index dfcdad8c7b96..6c2d8874593c 100644 --- a/packages/website/src/components/FinancialContributors/Sponsors/index.tsx +++ b/packages/website/src/components/FinancialContributors/Sponsors/index.tsx @@ -2,12 +2,12 @@ import clsx from 'clsx'; import React from 'react'; import { Sponsor } from '../Sponsor'; -import type { SponsorData, SponsorIncludeOptions } from '../types'; +import type { SponsorData } from '../types'; import styles from './styles.module.css'; interface SponsorsProps { className: string; - include?: SponsorIncludeOptions; + includeName?: boolean; expanded?: boolean; sponsors: SponsorData[]; title: string; @@ -16,7 +16,7 @@ interface SponsorsProps { export function Sponsors({ className, - include, + includeName, title, tier, sponsors, @@ -27,7 +27,7 @@ export function Sponsors({
    {sponsors.map(sponsor => (
  • - +
  • ))}
diff --git a/packages/website/src/components/FinancialContributors/Sponsors/styles.module.css b/packages/website/src/components/FinancialContributors/Sponsors/styles.module.css index b92051eddcba..526e1ab745eb 100644 --- a/packages/website/src/components/FinancialContributors/Sponsors/styles.module.css +++ b/packages/website/src/components/FinancialContributors/Sponsors/styles.module.css @@ -82,7 +82,6 @@ .tierArea { margin: 16px 0; width: auto; - padding: 0 60px; } .tier-gold-supporter { diff --git a/packages/website/src/components/FinancialContributors/index.tsx b/packages/website/src/components/FinancialContributors/index.tsx index d71bd0650045..0460e1e8694e 100644 --- a/packages/website/src/components/FinancialContributors/index.tsx +++ b/packages/website/src/components/FinancialContributors/index.tsx @@ -16,14 +16,13 @@ export function FinancialContributors(): JSX.Element {
Date: Mon, 30 Jan 2023 02:33:27 -0500 Subject: [PATCH 12/19] chore(website): mention 3 months SLA for issue and PR questions (#6313) --- docs/contributing/Issues.mdx | 1 + docs/contributing/Pull_Requests.mdx | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/contributing/Issues.mdx b/docs/contributing/Issues.mdx index ae61dd0e3123..d577248b2e61 100644 --- a/docs/contributing/Issues.mdx +++ b/docs/contributing/Issues.mdx @@ -21,6 +21,7 @@ Please don't: - Leave useless comments such as _"+1"_ or _"when's this getting fixed?"_ that only act as spam - If you have nothing to add but enthusiasm and joy, add a reaction such as ๐Ÿ‘ + - One exception: if an issue has been blocked on a question to a maintainer for 3 or more months, please ping us - we probably lost track of it - Bring up unrelated topics in existing issues: instead, file a new issue - Comment on closed PRs: instead, [file a new issue](#raising-issues) - Comment on commits directly, as those comments are not searchable: instead, file a new issue diff --git a/docs/contributing/Pull_Requests.mdx b/docs/contributing/Pull_Requests.mdx index edb76feb7d6f..c5af830718ce 100644 --- a/docs/contributing/Pull_Requests.mdx +++ b/docs/contributing/Pull_Requests.mdx @@ -19,8 +19,9 @@ Please don't: - Force push after opening a PR - Reasoning: GitHub is not able to track changes across force pushes, which makes it take longer for us to perform incremental reviews -- Comment asking for updates +- Comment on an existing PR asking for updates - Reasoning: Your PR hasn't been forgotten! The volunteer maintainers have limited time to work on the project, and they will get to it as soon as they are able. + - One exception: if a PR has been blocked on a question to a maintainer for 3 or more months, please ping us - we probably lost track of it. ### Raising a PR From 4b27777ed26cc83d6efc52a89b2d3fc6c01bc0d7 Mon Sep 17 00:00:00 2001 From: Yuri Pieters Date: Mon, 30 Jan 2023 07:39:36 +0000 Subject: [PATCH 13/19] fix(ast-spec): a JSXEmptyExpression is not a possible JSXExpression (#6321) --- packages/ast-spec/src/unions/JSXExpression.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/ast-spec/src/unions/JSXExpression.ts b/packages/ast-spec/src/unions/JSXExpression.ts index 78dfad53525b..d30c150cc6f0 100644 --- a/packages/ast-spec/src/unions/JSXExpression.ts +++ b/packages/ast-spec/src/unions/JSXExpression.ts @@ -1,8 +1,4 @@ -import type { JSXEmptyExpression } from '../jsx/JSXEmptyExpression/spec'; import type { JSXExpressionContainer } from '../jsx/JSXExpressionContainer/spec'; import type { JSXSpreadChild } from '../jsx/JSXSpreadChild/spec'; -export type JSXExpression = - | JSXEmptyExpression - | JSXExpressionContainer - | JSXSpreadChild; +export type JSXExpression = JSXExpressionContainer | JSXSpreadChild; From 587bd4ebc71061bc652f9a82ede250558785494b Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Mon, 30 Jan 2023 15:05:09 -0500 Subject: [PATCH 14/19] docs: describe update steps for ESLint, Node, and TypeScript (#6251) * docs: describe update steps for ESLint, Node, and TypeScript * lil typo fix, and a heart * Finalize VERSIONING/Versioning.md rename --- .../{VERSIONING.md => Versioning.md} | 29 +++-- .../versioning/dependant-version-upgrades.mdx | 121 ++++++++++++++++++ .../src/parseSettings/warnAboutTSVersion.ts | 2 +- packages/website/sidebars/sidebar.base.js | 11 +- 4 files changed, 147 insertions(+), 16 deletions(-) rename docs/maintenance/{VERSIONING.md => Versioning.md} (95%) create mode 100644 docs/maintenance/versioning/dependant-version-upgrades.mdx diff --git a/docs/maintenance/VERSIONING.md b/docs/maintenance/Versioning.md similarity index 95% rename from docs/maintenance/VERSIONING.md rename to docs/maintenance/Versioning.md index 0dd31ae90c1b..d9a4224dbf8a 100644 --- a/docs/maintenance/VERSIONING.md +++ b/docs/maintenance/Versioning.md @@ -1,6 +1,5 @@ --- id: versioning -sidebar_label: Versioning title: Versioning --- @@ -28,9 +27,22 @@ During these periods, we manually publish `canary` releases until we are happy w ## Dependant Versions +> See [Versioning > Dependant Version Upgrades](./versioning/dependant-version-upgrades.mdx) for maintenance steps to update these versions. + +### ESLint + +> The version range of ESLint currently supported is `^6.0.0 || ^7.0.0 || ^8.0.0`. + +We generally support at least the latest two major versions of ESLint. + +### Node + +This project makes an effort to support Active LTS and Maintenance LTS release statuses of Node according to [Node's release document](https://nodejs.org/en/about/releases). +Support for specific Current status releases are considered periodically. + ### TypeScript -> The version range of TypeScript currently supported is `>=3.3.1 <4.9.0`. +> The version range of TypeScript currently supported is `>=3.3.1 <5.0.0`. These versions are what we test against. @@ -42,18 +54,7 @@ Note that our packages have an open `peerDependency` requirement in order to all If you use a non-supported version of TypeScript, the parser will log a warning to the console. If you want to disable this warning, you can configure this in your `parserOptions`. -See: [`@typescript-eslint/parser`](./packages/parser/ TODO JOSH) and [`@typescript-eslint/typescript-estree`](./packages/typescript-estree/ TODO JOSH). - -### ESLint - -> The version range of ESLint currently supported is `^6.0.0 || ^7.0.0 || ^8.0.0`. - -We generally support at least the latest two major versions of ESLint. - -### Node - -This project makes an effort to support Active LTS and Maintenance LTS release statuses of Node according to [Node's release document](https://nodejs.org/en/about/releases). -Support for specific Current status releases are considered periodically. +See: [Parser > `warnOnUnsupportedTypeScriptVersion`](../architecture/Parser.mdx#warnonunsupportedtypescriptversion). ## Breaking Changes diff --git a/docs/maintenance/versioning/dependant-version-upgrades.mdx b/docs/maintenance/versioning/dependant-version-upgrades.mdx new file mode 100644 index 000000000000..49ba51ce1e46 --- /dev/null +++ b/docs/maintenance/versioning/dependant-version-upgrades.mdx @@ -0,0 +1,121 @@ +--- +id: dependant-version-upgrades +title: Dependant Version Upgrades +--- + +## ESLint + +The typescript-eslint repository contains four kinds of version ranges for the `eslint` package: + +- Integration tests: Pinned to our lowest supported ESLint version +- Packages with a `*` `peerDependency` version: These fall back to the explicit `peerDependency` versions +- Packages with explicit `peerDependency` versions: The full range of supported ESLint major versions +- [Root `package.json`](https://github.com/typescript-eslint/typescript-eslint/blob/main/package.json)'s' `devDependency`: A relatively recent release, used only for repository development + +:::tip +Whenever you discover any new areas of work that are blocked by dropping an old ESLint version, such as new ESLint API deprecations, add a _TODO_ comment that will be caught by the regular expressions under [Removing Support for an Old ESLint Version](#removing-support-for-an-old-eslint-version). +::: + +### Adding Support for a New ESLint Version + +1. Upgrade the root `package.json` `devDependency` to the latest ESLint +1. Add the new major version to the explicit `peerDependency` versions +1. Check [`eslint-visitor-keys`](https://www.npmjs.com/package/eslint-visitor-keys) for a new version to be upgraded to as well. +1. Update [Versioning > ESLint](../Versioning.md#eslint) + +### Removing Support for an Old ESLint Version + +1. Increase the integration tests to the next lowest supported major version (`*.0.0`) +1. Remove the old major versions from packages with explicit `peerDependency` versions +1. Search for source code comments (excluding `CHANGELOG.md` files) that mention a now-unsupported version of ESLint. + - For example, to remove support for v5, searches might include: + - `/eslint.*5/i` + - `/todo.*eslint.*5/i` + - `/todo.*eslint/i` +1. Update [Versioning > ESLint](../Versioning.md#eslint) + +See [chore: drop support for ESLint v6](https://github.com/typescript-eslint/typescript-eslint/pull/5972) for reference. + +## Node + +The typescript-eslint repository contains three kinds of version ranges for Node: + +- [`.github/workflows/ci.yml`](https://github.com/typescript-eslint/typescript-eslint/blob/main/.github/workflows/ci.yml)'s `PRIMARY_NODE_VERSION`: Set to the highest Node version we support +- `node-version`: Set to a tuple of our [lowest, highest] supported versions for our unit tests in CI +- `engines` field in all `package.json`s: explicitly lists all supported Node ranges + +Change those numbers accordingly when adding support for a new Node version or removing support for an old Node version. + +See [feat: drop support for node v12](https://github.com/typescript-eslint/typescript-eslint/pull/5918) + [chore: test node v14 on ci.yml](https://github.com/typescript-eslint/typescript-eslint/pull/5512) for reference. + +## TypeScript + +### Adding Support for a New TypeScript Version + +We generally start the process of supporting a new TypeScript version just after the first beta release for that version is made available. + +1. Create and pin an issue with a title like _TypeScript X.Y Support_, `accepting prs`, `AST`, `dependencies`, and `New TypeScript Version` labels, and the following contents: + + 1. A link to the _TypeScript X.Y Iteration Plan_ issue from the Microsoft issue tracker + 2. The following text: + + ```md + This issue is just to track all of the new features and their implementation state in this project. + As with all releases, we will not necessarily support all features until closer to the full release when everything the features are stabilised. + + _Please be patient._ โค๏ธ + ``` + + 3. A heading starting with `๐Ÿ”ฒ ` for each new TypeScript feature called out in the iteration plan that will impact us + 4. A heading titled _๐Ÿ”ฒ `lib.d.ts` Updates_ and the content _We will need to regenerate our types within `scope-manager`_ + 5. A heading titled _Other changes with no impact to us_ containing a list of other changes that we don't believe will impact us + +1. At this stage, it's fine to send and/or review PRs that implement necessary features, but wait to merge them until the new TypeScript version's RC is released + - Whenever a PR is created, add ` (#1234)` to its respective heading, and change the heading's emoji from ๐Ÿ”ฒ to ๐Ÿ— + - Search for `expectBabelToNotSupport` to see how to support syntaxes not yet supported by Babel +1. Once the TypeScript RC version is released, start merging PRs + - Whenever a PR is merged, change the respective heading's emoji from ๐Ÿ— to โœ… +1. Create a PR with a title like `feat: update TypeScript to X.Y-rc` and the following changes: + - In the root `package.json`, add `|| X.Y.2-rc2` to the `dependency` on `typescript` + - In the root `package.json`, change the `devDependency` on `typescript` to `~X.Y.2-rc2` + - Change the `SUPPORTED_TYPESCRIPT_VERSIONS` constant's `<` version to the next version of TypeScript + - Change the `SUPPORTED_PRERELEASE_RANGES` constant to equal `['X.Y.2-rc']` + - Rename and update `patches/typescript*` to the new TypeScript version + - Run `yarn generate:lib` to update `scope-manager` +1. Once all PRs needed for the RC update PR are merged, merge the RC update PR +1. Once TypeScript releases the stable X.Y version, create and merge a PR with a title like `chore: bump TypeScript from X.YRC to X.Y` and the following changes: + - In the root `package.json`, remove `|| X.Y.2-rc2` from the `dependency` on `typescript`, and bump its `<` version to the next version of TypeScript + - In the root `package.json`, change the `devDependency` on `typescript` to `~X.Y.3` + - Rename and update `patches/typescript*` to the new TypeScript version + - Any other changes made necessary due to changes in TypeScript between the RC version and stable version + - Update the supported version range in [Versioning](../Versioning.md) +1. Update [Versioning > TypeScript](../Versioning.md#typescript) +1. Send a PR that updates this documentation page to point to your newer issues and PRs + - Also update any of these steps if you go with a different process + +See for reference (caveat: these don't follow the exact process described here): + +- [TypeScript 4.7 Support](https://github.com/typescript-eslint/typescript-eslint/issues/4800) +- [TypeScript 4.8 Support](https://github.com/typescript-eslint/typescript-eslint/issues/5227) +- [feat: support TypeScript 4.8](https://github.com/typescript-eslint/typescript-eslint/pull/5551) +- [feat: support TypeScript 4.9](https://github.com/typescript-eslint/typescript-eslint/pull/5716) +- [chore: bump TS from 4.9RC to 4.9](https://github.com/typescript-eslint/typescript-eslint/commit/a40a311bb52a2b1cfac43851b201f8cfc96c8d5d) + +### Removing Support for an Old TypeScript Version + +A single PR can remove support for old TypeScript versions as a breaking change: + +1. Update the root `package.json` `devDependency` +1. Update the `SUPPORTED_TYPESCRIPT_VERSIONS` constant in `warnAboutTSVersion.ts` +1. Update the `versions` constant in `version-check.ts` +1. Update [Versioning > TypeScript](../Versioning.md#typescript) +1. Search for source code comments (excluding `CHANGELOG.md` files) that mention a now-unsupported version of TypeScript. + - For example, to remove support for v4.3, searches might include: + - `4.3` + - `/is.*4.*3/i` + - `/semver.*4.*3/i` + - `/semver.satisfies/` + - `/todo.*ts/i` + - `/todo.*typescript/i` + +See [feat: bump minimum supported TS version to 4.2.4](https://github.com/typescript-eslint/typescript-eslint/pull/5915). diff --git a/packages/typescript-estree/src/parseSettings/warnAboutTSVersion.ts b/packages/typescript-estree/src/parseSettings/warnAboutTSVersion.ts index 191ac029325a..13eef19e7964 100644 --- a/packages/typescript-estree/src/parseSettings/warnAboutTSVersion.ts +++ b/packages/typescript-estree/src/parseSettings/warnAboutTSVersion.ts @@ -3,7 +3,7 @@ import * as ts from 'typescript'; import type { ParseSettings } from './index'; /** - * This needs to be kept in sync with /docs/maintenance/VERSIONING.md + * This needs to be kept in sync with /docs/maintenance/Versioning.md * in the typescript-eslint monorepo */ const SUPPORTED_TYPESCRIPT_VERSIONS = '>=3.3.1 <5.0.0'; diff --git a/packages/website/sidebars/sidebar.base.js b/packages/website/sidebars/sidebar.base.js index 770ab620ec02..7f0de7597287 100644 --- a/packages/website/sidebars/sidebar.base.js +++ b/packages/website/sidebars/sidebar.base.js @@ -82,7 +82,16 @@ module.exports = { }, 'maintenance/pull-requests', 'maintenance/releases', - 'maintenance/versioning', + { + collapsible: false, + items: ['maintenance/versioning/dependant-version-upgrades'], + label: 'Versioning', + link: { + id: 'maintenance/versioning', + type: 'doc', + }, + type: 'category', + }, ], label: 'Maintenance', link: { From ca190def071c56c0ebbdbbdfdcb31d2eb2c11809 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Mon, 30 Jan 2023 15:06:52 -0500 Subject: [PATCH 15/19] chore(website): reorganized sidebar and header nav a bit (#6311) * chore(website): reorganized sidebar and header nav a bit * Fix Formatting.md link case --- docs/maintenance/ISSUES.md | 2 +- packages/website/docusaurusConfig.ts | 2 +- packages/website/sidebars/sidebar.base.js | 28 +++++++++++------------ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/maintenance/ISSUES.md b/docs/maintenance/ISSUES.md index e7850e3a4b3c..fb5eb655dd69 100644 --- a/docs/maintenance/ISSUES.md +++ b/docs/maintenance/ISSUES.md @@ -105,7 +105,7 @@ We avoid features that: - Are only relevant for a minority of users, as they aren't likely worth the maintenance burden - Aren't TypeScript-specific (e.g. should be in ESLint core instead) - Are only relevant with specific userland frameworks or libraries, such as Jest or React -- Are for "formatting" functionality (we [strongly recommend users use a separate dedicated formatter](../linting/troubleshooting/FORMATTING.md)) +- Are for "formatting" functionality (we [strongly recommend users use a separate dedicated formatter](../linting/troubleshooting/Formatting.md)) #### โœจ Rule Enhancements diff --git a/packages/website/docusaurusConfig.ts b/packages/website/docusaurusConfig.ts index bfa844fc2f0b..ab543e80783e 100644 --- a/packages/website/docusaurusConfig.ts +++ b/packages/website/docusaurusConfig.ts @@ -76,7 +76,7 @@ const themeConfig: ThemeCommonConfig & AlgoliaThemeConfig = { items: [ { to: 'getting-started/', - label: 'Getting started', + label: 'Docs', position: 'left', }, { diff --git a/packages/website/sidebars/sidebar.base.js b/packages/website/sidebars/sidebar.base.js index 7f0de7597287..2a097b02a703 100644 --- a/packages/website/sidebars/sidebar.base.js +++ b/packages/website/sidebars/sidebar.base.js @@ -37,20 +37,6 @@ module.exports = { type: 'category', }, 'custom-rules', - { - items: [ - 'contributing/discussions', - 'contributing/issues', - 'contributing/local-development', - 'contributing/pull-requests', - ], - label: 'Contributing', - link: { - id: 'contributing', - type: 'doc', - }, - type: 'category', - }, { items: [ 'architecture/eslint-plugin', @@ -67,6 +53,20 @@ module.exports = { }, type: 'category', }, + { + items: [ + 'contributing/discussions', + 'contributing/issues', + 'contributing/local-development', + 'contributing/pull-requests', + ], + label: 'Contributing', + link: { + id: 'contributing', + type: 'doc', + }, + type: 'category', + }, { items: [ 'maintenance/branding', From 202d9fb3209c87f25671119296046ef78270b558 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 30 Jan 2023 23:40:14 +0000 Subject: [PATCH 16/19] chore(deps): update dependency eslint-plugin-simple-import-sort to v10 (#6391) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 78 ++++------------------------------------------------ 2 files changed, 7 insertions(+), 73 deletions(-) diff --git a/package.json b/package.json index 16fef2bf3ba0..8324e5d971df 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "eslint-plugin-eslint-plugin": "^5.0.1", "eslint-plugin-import": "^2.26.0", "eslint-plugin-jest": "^27.0.0", - "eslint-plugin-simple-import-sort": "^9.0.0", + "eslint-plugin-simple-import-sort": "^10.0.0", "execa": "5.1.1", "glob": "^8.0.1", "husky": "^8.0.1", diff --git a/yarn.lock b/yarn.lock index a1ed83510144..e88792c6fec5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3246,13 +3246,6 @@ read-package-json-fast "^2.0.3" which "^2.0.2" -"@nrwl/cli@15.4.5": - version "15.4.5" - resolved "https://registry.yarnpkg.com/@nrwl/cli/-/cli-15.4.5.tgz#2a8f663e5265379812ba83c0577abdc94dcdba8f" - integrity sha512-f13s0/hzS9jsV1+QPr1Lp3Um+3dOHD8gEP2h7uw17rEPrtJ5ggRKMj/HcZ9dkT9zDM9EmPtVTb6k38ON+NWcUw== - dependencies: - nx "15.4.5" - "@nrwl/cli@15.5.3": version "15.5.3" resolved "https://registry.npmjs.org/@nrwl/cli/-/cli-15.5.3.tgz#13277e5a0e8ba713850bcf13fa76717ea747a2bb" @@ -3260,7 +3253,7 @@ dependencies: nx "15.5.3" -"@nrwl/devkit@15.5.3": +"@nrwl/devkit@15.5.3", "@nrwl/devkit@>=15.4.2 < 16": version "15.5.3" resolved "https://registry.npmjs.org/@nrwl/devkit/-/devkit-15.5.3.tgz#16fac0147c2ab6ebba7b5357b2b959ad46b6eb26" integrity sha512-GGNLLGXDGWflrpaLimnE6hChfZfq3+XWZ0LJWL0IuCnchngPbNzuyh8S8KPgNKKgq4Nv0hglWefIwMg2UhHysA== @@ -3271,17 +3264,6 @@ semver "7.3.4" tslib "^2.3.0" -"@nrwl/devkit@>=15.4.2 < 16": - version "15.4.5" - resolved "https://registry.yarnpkg.com/@nrwl/devkit/-/devkit-15.4.5.tgz#22b7aa16bc14c171f061f770060d9af480d5f1cb" - integrity sha512-oag+wJgusKz+rwvgcVy9i8bNtTo7ikbjVVtSOmyVBE0ZrgN1CMFjugBj4FEjKGtd73djjpvW9Mm36uJRujrc2w== - dependencies: - "@phenomnomnominal/tsquery" "4.1.1" - ejs "^3.1.7" - ignore "^5.0.4" - semver "7.3.4" - tslib "^2.3.0" - "@nrwl/jest@15.5.3": version "15.5.3" resolved "https://registry.npmjs.org/@nrwl/jest/-/jest-15.5.3.tgz#492ab42ac3171354a9afd6f93a7c43a6c56b3f61" @@ -3324,13 +3306,6 @@ tar "6.1.11" yargs-parser ">=21.0.1" -"@nrwl/tao@15.4.5": - version "15.4.5" - resolved "https://registry.yarnpkg.com/@nrwl/tao/-/tao-15.4.5.tgz#d07f6d06cecb6acb84259e0654cfc59fcc5edd53" - integrity sha512-UMtxXxTWqbyZOdyD9Zt2IsDY/JVXIFZtY6pO4jPha7+UIHWf2Zi8Dszs6UoUTS4mqpNMIkKymwpZGtkDTfiAJA== - dependencies: - nx "15.4.5" - "@nrwl/tao@15.5.3": version "15.5.3" resolved "https://registry.npmjs.org/@nrwl/tao/-/tao-15.5.3.tgz#08c05715d2ecb108ed8b2c5381b9017cf1448b4a" @@ -7135,10 +7110,10 @@ eslint-plugin-react@^7.29.4: semver "^6.3.0" string.prototype.matchall "^4.0.7" -eslint-plugin-simple-import-sort@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-9.0.0.tgz#04c97f06a2e526afd40e0ac694b70d1aaaec1aef" - integrity sha512-PtrLjyXP8kjRneWT1n0b99y/2Fyup37we7FVoWsI61/O7x4ztLohzhep/pxI/cYlECr/cQ2j6utckdvWpVwXNA== +eslint-plugin-simple-import-sort@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-10.0.0.tgz#cc4ceaa81ba73252427062705b64321946f61351" + integrity sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw== eslint-scope@5.1.1, eslint-scope@^5.1.1: version "5.1.1" @@ -10794,48 +10769,7 @@ nth-check@^2.0.0, nth-check@^2.0.1: dependencies: boolbase "^1.0.0" -nx@15.4.5, "nx@>=15.4.2 < 16": - version "15.4.5" - resolved "https://registry.yarnpkg.com/nx/-/nx-15.4.5.tgz#12daa740256fa29ba634fbc4f3f87b6d078c2990" - integrity sha512-1spZL6sgOV8JJJuN8W5CLtJYwTOnlyaV32jPXfidavU0QMS8MP+rW3+NUQ9Uzc1UYhOu8llZWtnen93neVGQRw== - dependencies: - "@nrwl/cli" "15.4.5" - "@nrwl/tao" "15.4.5" - "@parcel/watcher" "2.0.4" - "@yarnpkg/lockfile" "^1.1.0" - "@yarnpkg/parsers" "^3.0.0-rc.18" - "@zkochan/js-yaml" "0.0.6" - axios "^1.0.0" - chalk "4.1.0" - chokidar "^3.5.1" - cli-cursor "3.1.0" - cli-spinners "2.6.1" - cliui "^7.0.2" - dotenv "~10.0.0" - enquirer "~2.3.6" - fast-glob "3.2.7" - figures "3.2.0" - flat "^5.0.2" - fs-extra "^10.1.0" - glob "7.1.4" - ignore "^5.0.4" - js-yaml "4.1.0" - jsonc-parser "3.2.0" - minimatch "3.0.5" - npm-run-path "^4.0.1" - open "^8.4.0" - semver "7.3.4" - string-width "^4.2.3" - strong-log-transformer "^2.1.0" - tar-stream "~2.2.0" - tmp "~0.2.1" - tsconfig-paths "^4.1.2" - tslib "^2.3.0" - v8-compile-cache "2.3.0" - yargs "^17.6.2" - yargs-parser "21.1.1" - -nx@15.5.3: +nx@15.5.3, "nx@>=15.4.2 < 16": version "15.5.3" resolved "https://registry.npmjs.org/nx/-/nx-15.5.3.tgz#bf6252e7d9e17121dd82dec4f6fce319b9e005fa" integrity sha512-PHB8VbiBLP108xb+yR8IGEsYWr7OcmDDOjHL+73oP4lVjyPgT8wdTMe6tI5LdBgv+KZ+0kiThK3ckvcPsfgvLQ== From 85e783c1fabe96d390729a5796d6d346e401692b Mon Sep 17 00:00:00 2001 From: Omri Luzon Date: Tue, 31 Jan 2023 09:21:23 +0200 Subject: [PATCH 17/19] fix(eslint-plugin): [prefer-optional-chain] fix `ThisExpression` and `PrivateIdentifier` errors (#6028) --- .../src/rules/prefer-optional-chain.ts | 46 +++++++++++++------ .../prefer-optional-chain.test.ts | 15 +++++- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/packages/eslint-plugin/src/rules/prefer-optional-chain.ts b/packages/eslint-plugin/src/rules/prefer-optional-chain.ts index f5ed3ccb5897..efccc2ccfd2d 100644 --- a/packages/eslint-plugin/src/rules/prefer-optional-chain.ts +++ b/packages/eslint-plugin/src/rules/prefer-optional-chain.ts @@ -10,6 +10,7 @@ type ValidChainTarget = | TSESTree.CallExpression | TSESTree.ChainExpression | TSESTree.Identifier + | TSESTree.PrivateIdentifier | TSESTree.MemberExpression | TSESTree.ThisExpression | TSESTree.MetaProperty; @@ -164,7 +165,9 @@ export default util.createRule({ break; } + let invalidOptionallyChainedPrivateProperty; ({ + invalidOptionallyChainedPrivateProperty, expressionCount, previousLeftText, optionallyChainedCode, @@ -178,6 +181,9 @@ export default util.createRule({ previous, current, )); + if (invalidOptionallyChainedPrivateProperty) { + return; + } } reportIfMoreThanOne({ @@ -243,7 +249,9 @@ export default util.createRule({ break; } + let invalidOptionallyChainedPrivateProperty; ({ + invalidOptionallyChainedPrivateProperty, expressionCount, previousLeftText, optionallyChainedCode, @@ -257,6 +265,9 @@ export default util.createRule({ previous, current, )); + if (invalidOptionallyChainedPrivateProperty) { + return; + } } reportIfMoreThanOne({ @@ -343,7 +354,10 @@ export default util.createRule({ return `${calleeText}${argumentsText}`; } - if (node.type === AST_NODE_TYPES.Identifier) { + if ( + node.type === AST_NODE_TYPES.Identifier || + node.type === AST_NODE_TYPES.PrivateIdentifier + ) { return node.name; } @@ -381,15 +395,12 @@ export default util.createRule({ // cases should match the list in ALLOWED_MEMBER_OBJECT_TYPES switch (node.object.type) { - case AST_NODE_TYPES.CallExpression: - case AST_NODE_TYPES.Identifier: - objectText = getText(node.object); - break; - case AST_NODE_TYPES.MemberExpression: objectText = getMemberExpressionText(node.object); break; + case AST_NODE_TYPES.CallExpression: + case AST_NODE_TYPES.Identifier: case AST_NODE_TYPES.MetaProperty: case AST_NODE_TYPES.ThisExpression: objectText = getText(node.object); @@ -397,7 +408,7 @@ export default util.createRule({ /* istanbul ignore next */ default: - throw new Error(`Unexpected member object type: ${node.object.type}`); + return ''; } let propertyText: string; @@ -420,9 +431,7 @@ export default util.createRule({ /* istanbul ignore next */ default: - throw new Error( - `Unexpected member property type: ${node.object.type}`, - ); + return ''; } return `${objectText}${node.optional ? '?.' : ''}[${propertyText}]`; @@ -432,12 +441,12 @@ export default util.createRule({ case AST_NODE_TYPES.Identifier: propertyText = getText(node.property); break; + case AST_NODE_TYPES.PrivateIdentifier: + propertyText = '#' + getText(node.property); + break; - /* istanbul ignore next */ default: - throw new Error( - `Unexpected member property type: ${node.object.type}`, - ); + propertyText = sourceCode.getText(node.property); } return `${objectText}${node.optional ? '?.' : '.'}${propertyText}`; @@ -461,6 +470,7 @@ const ALLOWED_COMPUTED_PROP_TYPES: ReadonlySet = new Set([ ]); const ALLOWED_NON_COMPUTED_PROP_TYPES: ReadonlySet = new Set([ AST_NODE_TYPES.Identifier, + AST_NODE_TYPES.PrivateIdentifier, ]); interface ReportIfMoreThanOneOptions { @@ -525,6 +535,7 @@ function reportIfMoreThanOne({ } interface NormalizedPattern { + invalidOptionallyChainedPrivateProperty: boolean; expressionCount: number; previousLeftText: string; optionallyChainedCode: string; @@ -541,6 +552,7 @@ function normalizeRepeatingPatterns( current: TSESTree.Node, ): NormalizedPattern { const leftText = previousLeftText; + let invalidOptionallyChainedPrivateProperty = false; // omit weird doubled up expression that make no sense like foo.bar && foo.bar if (rightText !== previousLeftText) { expressionCount += 1; @@ -576,6 +588,11 @@ function normalizeRepeatingPatterns( diff === '?.buzz' */ const diff = rightText.replace(leftText, ''); + if (diff.startsWith('.#')) { + // Do not handle direct optional chaining on private properties because of a typescript bug (https://github.com/microsoft/TypeScript/issues/42734) + // We still allow in computed properties + invalidOptionallyChainedPrivateProperty = true; + } if (diff.startsWith('?')) { // item was "pre optional chained" optionallyChainedCode += diff; @@ -591,6 +608,7 @@ function normalizeRepeatingPatterns( util.NullThrowsReasons.MissingParent, ); return { + invalidOptionallyChainedPrivateProperty, expressionCount, previousLeftText, optionallyChainedCode, diff --git a/packages/eslint-plugin/tests/rules/prefer-optional-chain/prefer-optional-chain.test.ts b/packages/eslint-plugin/tests/rules/prefer-optional-chain/prefer-optional-chain.test.ts index ca783df13b32..a18de12bf7b1 100644 --- a/packages/eslint-plugin/tests/rules/prefer-optional-chain/prefer-optional-chain.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-optional-chain/prefer-optional-chain.test.ts @@ -45,6 +45,16 @@ ruleTester.run('prefer-optional-chain', rule, { 'match && match$1 !== undefined;', 'foo !== null && foo !== undefined;', "x['y'] !== undefined && x['y'] !== null;", + // private properties + 'this.#a && this.#b;', + '!this.#a || !this.#b;', + 'a.#foo?.bar;', + '!a.#foo?.bar;', + '!foo().#a || a;', + '!a.b.#a || a;', + '!new A().#b || a;', + '!(await a).#b || a;', + "!(foo as any).bar || 'anything';", // currently do not handle complex computed properties 'foo && foo[bar as string] && foo[bar as string].baz;', 'foo && foo[1 + 2] && foo[1 + 2].baz;', @@ -68,6 +78,10 @@ ruleTester.run('prefer-optional-chain', rule, { '!import.meta && !import.meta.foo;', 'new.target || new.target.length;', '!new.target || true;', + // Do not handle direct optional chaining on private properties because of a typescript bug (https://github.com/microsoft/TypeScript/issues/42734) + // We still allow in computed properties + 'foo && foo.#bar;', + '!foo || !foo.#bar;', ], invalid: [ ...BaseCases.all(), @@ -1240,7 +1254,6 @@ foo?.bar(/* comment */a, }, ], }, - { code: noFormat`import.meta && import.meta?.() && import.meta?.().baz;`, output: null, From a3ba163ccd73cf369c18493d5393003cc932cc23 Mon Sep 17 00:00:00 2001 From: James Henry Date: Tue, 31 Jan 2023 13:12:09 +0400 Subject: [PATCH 18/19] chore: update nx to 15.6 (#6387) --- nx.json | 35 ++++-- package.json | 6 +- packages/ast-spec/project.json | 2 +- packages/shared-fixtures/project.json | 4 +- .../type-utils/tests/isTypeReadonly.test.ts | 2 +- packages/website-eslint/project.json | 4 +- yarn.lock | 110 +++++++++++++----- 7 files changed, 113 insertions(+), 50 deletions(-) diff --git a/nx.json b/nx.json index b34a91f78001..731dc56a3c7a 100644 --- a/nx.json +++ b/nx.json @@ -1,22 +1,12 @@ { "$schema": "./node_modules/nx/schemas/nx-schema.json", "npmScope": "typescript-eslint", - "affected": { - "defaultBase": "main" - }, - "workspaceLayout": { - "libsDir": "packages" - }, "tasksRunnerOptions": { "default": { "runner": "@nrwl/nx-cloud", "options": { "cacheableOperations": ["build", "lint", "package", "prebuild", "test"], - "accessToken": "YjFjNTBhOWUtY2JmNy00ZDhiLWE5N2UtZjliNDAwNmIzOTdjfHJlYWQtd3JpdGU=", - "canTrackAnalytics": false, - "showUsageWarnings": true, - "runtimeCacheInputs": ["node -v", "echo $NETLIFY"], - "parallel": 1 + "accessToken": "YjFjNTBhOWUtY2JmNy00ZDhiLWE5N2UtZjliNDAwNmIzOTdjfHJlYWQtd3JpdGU=" } } }, @@ -26,11 +16,32 @@ "inputs": ["production", "^production"] }, "test": { + "inputs": [ + "default", + "{workspaceRoot}/jest.config.js", + "{workspaceRoot}/jest.config.base.js" + ], "outputs": ["{projectRoot}/coverage"] + }, + "lint": { + "inputs": [ + "default", + "{workspaceRoot}/.eslintrc.js", + "{workspaceRoot}/.eslintignore" + ] } }, "namedInputs": { - "default": ["{projectRoot}/**/*", "sharedGlobals"], + "default": [ + "{projectRoot}/**/*", + "sharedGlobals", + { + "runtime": "node -v" + }, + { + "runtime": "echo $NETLIFY" + } + ], "sharedGlobals": ["{workspaceRoot}/.github/workflows/ci.yml"], "production": ["default"] } diff --git a/package.json b/package.json index 8324e5d971df..f8b24d34edf6 100644 --- a/package.json +++ b/package.json @@ -54,9 +54,9 @@ "@babel/eslint-parser": "^7.19.1", "@babel/parser": "^7.20.7", "@babel/types": "^7.20.2", - "@nrwl/jest": "15.5.3", + "@nrwl/jest": "15.6.3", "@nrwl/nx-cloud": "15.0.2", - "@nrwl/workspace": "15.5.3", + "@nrwl/workspace": "15.6.3", "@swc/core": "^1.3.1", "@swc/jest": "^0.2.21", "@types/babel__code-frame": "^7.0.3", @@ -99,7 +99,7 @@ "make-dir": "^3.1.0", "markdownlint-cli": "^0.33.0", "ncp": "^2.0.0", - "nx": "15.5.3", + "nx": "15.6.3", "patch-package": "^6.4.7", "prettier": "2.8.1", "pretty-format": "^29.0.3", diff --git a/packages/ast-spec/project.json b/packages/ast-spec/project.json index 682cdbf3d91c..41721d18d711 100644 --- a/packages/ast-spec/project.json +++ b/packages/ast-spec/project.json @@ -10,7 +10,7 @@ "cwd": "packages/ast-spec", "commands": ["yarn build"] }, - "outputs": ["packages/ast-spec/dist/**/*.ts"] + "outputs": ["{projectRoot}/dist/**/*.ts"] }, "lint": { "executor": "@nrwl/linter:eslint", diff --git a/packages/shared-fixtures/project.json b/packages/shared-fixtures/project.json index 18cfac971353..412bca4935ff 100644 --- a/packages/shared-fixtures/project.json +++ b/packages/shared-fixtures/project.json @@ -1,6 +1,6 @@ { + "name": "shared-fixtures", "$schema": "../../node_modules/nx/schemas/project-schema.json", "type": "library", - "implicitDependencies": [], - "name": "shared-fixtures" + "implicitDependencies": [] } diff --git a/packages/type-utils/tests/isTypeReadonly.test.ts b/packages/type-utils/tests/isTypeReadonly.test.ts index 382091a23754..0b171dc12a2c 100644 --- a/packages/type-utils/tests/isTypeReadonly.test.ts +++ b/packages/type-utils/tests/isTypeReadonly.test.ts @@ -4,8 +4,8 @@ import path from 'path'; import type * as ts from 'typescript'; import { - type ReadonlynessOptions, isTypeReadonly, + type ReadonlynessOptions, } from '../src/isTypeReadonly'; describe('isTypeReadonly', () => { diff --git a/packages/website-eslint/project.json b/packages/website-eslint/project.json index 517439cbec3d..862c5b948f1f 100644 --- a/packages/website-eslint/project.json +++ b/packages/website-eslint/project.json @@ -1,6 +1,6 @@ { + "name": "website-eslint", "$schema": "../../node_modules/nx/schemas/project-schema.json", "type": "library", - "implicitDependencies": [], - "name": "website-eslint" + "implicitDependencies": [] } diff --git a/yarn.lock b/yarn.lock index e88792c6fec5..bbe5aba913b6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3246,14 +3246,25 @@ read-package-json-fast "^2.0.3" which "^2.0.2" -"@nrwl/cli@15.5.3": - version "15.5.3" - resolved "https://registry.npmjs.org/@nrwl/cli/-/cli-15.5.3.tgz#13277e5a0e8ba713850bcf13fa76717ea747a2bb" - integrity sha512-NWf9CWswvdYM6YzXuweaZPAZ2erMtQrrHZdgFbUGeojZBZ+b4TCGzLWNodZj4yQOa/eTwlyPMYO2LEw9CoapDQ== +"@nrwl/cli@15.6.3": + version "15.6.3" + resolved "https://registry.npmjs.org/@nrwl/cli/-/cli-15.6.3.tgz#999531d6efb30afc39373bdcbd7e78254a3a3fd3" + integrity sha512-K4E0spofThZXMnhA6R8hkUTdfqmwSnUE2+DlD5Y3jqsvKTAgwF5U41IFkEouFZCf+dWjy0RA20bWoX48EVFtmQ== + dependencies: + nx "15.6.3" + +"@nrwl/devkit@15.6.3": + version "15.6.3" + resolved "https://registry.npmjs.org/@nrwl/devkit/-/devkit-15.6.3.tgz#e4e96c53ba3304786a49034286c8511534b2b194" + integrity sha512-/JDvdzNxUM+C1PCZPCrvmFx+OfywqZdOq1GS9QR8C0VctTLG4D/SGSFD88O1SAdcbH/f1mMiBGfEYZYd23fghQ== dependencies: - nx "15.5.3" + "@phenomnomnominal/tsquery" "4.1.1" + ejs "^3.1.7" + ignore "^5.0.4" + semver "7.3.4" + tslib "^2.3.0" -"@nrwl/devkit@15.5.3", "@nrwl/devkit@>=15.4.2 < 16": +"@nrwl/devkit@>=15.4.2 < 16": version "15.5.3" resolved "https://registry.npmjs.org/@nrwl/devkit/-/devkit-15.5.3.tgz#16fac0147c2ab6ebba7b5357b2b959ad46b6eb26" integrity sha512-GGNLLGXDGWflrpaLimnE6hChfZfq3+XWZ0LJWL0IuCnchngPbNzuyh8S8KPgNKKgq4Nv0hglWefIwMg2UhHysA== @@ -3264,14 +3275,14 @@ semver "7.3.4" tslib "^2.3.0" -"@nrwl/jest@15.5.3": - version "15.5.3" - resolved "https://registry.npmjs.org/@nrwl/jest/-/jest-15.5.3.tgz#492ab42ac3171354a9afd6f93a7c43a6c56b3f61" - integrity sha512-BSs4ZQJtRjQ+OAPHdfeemoAiYsGL3Zuq2Ezj8XwGp50SkgVLUBZdXg2Ld1ARjTh/d3pMg+Mf+yKfjoYqFzKx+A== +"@nrwl/jest@15.6.3": + version "15.6.3" + resolved "https://registry.npmjs.org/@nrwl/jest/-/jest-15.6.3.tgz#66b1c387352cbbf666959fd7fe921d4980c6084a" + integrity sha512-pG8ESEJFkgyBGOOVZ6bFohklkDXn7JrDPSjmnoKvcOzprluPS7Nx4Ce5bw7wk2Ul3fqJcpAcH5LAZvb+HtA85w== dependencies: "@jest/reporters" "28.1.1" "@jest/test-result" "28.1.1" - "@nrwl/devkit" "15.5.3" + "@nrwl/devkit" "15.6.3" "@phenomnomnominal/tsquery" "4.1.1" chalk "^4.1.0" dotenv "~10.0.0" @@ -3282,12 +3293,12 @@ resolve.exports "1.1.0" tslib "^2.3.0" -"@nrwl/linter@15.5.3": - version "15.5.3" - resolved "https://registry.npmjs.org/@nrwl/linter/-/linter-15.5.3.tgz#de9c10c51d2ec92d51cc89207f642d41493314ba" - integrity sha512-ZeUtLOT0olORBL4FpEXmJoaiSKq4VIffW/vmCbosRIuHZqL4Cye5uHyQ6/KJXjD44Z+P6QCkyfr0etcy3lhSkg== +"@nrwl/linter@15.6.3": + version "15.6.3" + resolved "https://registry.npmjs.org/@nrwl/linter/-/linter-15.6.3.tgz#9cffa150109c604827c06ce0ccd5c925d4cd7c01" + integrity sha512-efGOduHbUa/L6MuJLb2SoDwi4hEKpz6lM1X/Yg36dYDjLuJdpLC23K4WwEOQeZL6jkcUerfY65W8NMPinAHWKg== dependencies: - "@nrwl/devkit" "15.5.3" + "@nrwl/devkit" "15.6.3" "@phenomnomnominal/tsquery" "4.1.1" tmp "~0.2.1" tslib "^2.3.0" @@ -3306,20 +3317,20 @@ tar "6.1.11" yargs-parser ">=21.0.1" -"@nrwl/tao@15.5.3": - version "15.5.3" - resolved "https://registry.npmjs.org/@nrwl/tao/-/tao-15.5.3.tgz#08c05715d2ecb108ed8b2c5381b9017cf1448b4a" - integrity sha512-vgPLIW9IoBfQ4IkHRT5RC4LqNwFBK5jmHYmFIRgbIeFRudFBbnpmOaKRME0OwN7qJ6964PVVbzahAPvYVD02xw== +"@nrwl/tao@15.6.3": + version "15.6.3" + resolved "https://registry.npmjs.org/@nrwl/tao/-/tao-15.6.3.tgz#b24e11345375dea96bc386c60b9b1102a7584932" + integrity sha512-bDZbPIbU5Mf2BvX0q8GjPxrm1WkYyfW+gp7mLuuJth2sEpZiCr47mSwuGko/y4CKXvIX46VQcAS0pKQMKugXsg== dependencies: - nx "15.5.3" + nx "15.6.3" -"@nrwl/workspace@15.5.3": - version "15.5.3" - resolved "https://registry.npmjs.org/@nrwl/workspace/-/workspace-15.5.3.tgz#3343b0de3a0fb8b0b7176c0c3cb7c19907e1485e" - integrity sha512-/Udv+dF4Z/9GZ4QmdCu/6e4QUJYx7zGTcoCOZi+Pt+OPRqOULkBbfKmB+xtiG/D32WnFePsxcssaZGux/aysUQ== +"@nrwl/workspace@15.6.3": + version "15.6.3" + resolved "https://registry.npmjs.org/@nrwl/workspace/-/workspace-15.6.3.tgz#a9fd3c5692dfaebb04642e4e86d930d144bc2fed" + integrity sha512-RkCmDvcMXCVanR0RS8CZ14D7OMojSyvAal+b37P521MpizDkiN+zdRKewKvyOonzDeTAmZODtYccQ/uM5DjRfQ== dependencies: - "@nrwl/devkit" "15.5.3" - "@nrwl/linter" "15.5.3" + "@nrwl/devkit" "15.6.3" + "@nrwl/linter" "15.6.3" "@parcel/watcher" "2.0.4" chalk "^4.1.0" chokidar "^3.5.1" @@ -3335,7 +3346,7 @@ jsonc-parser "3.2.0" minimatch "3.0.5" npm-run-path "^4.0.1" - nx "15.5.3" + nx "15.6.3" open "^8.4.0" rxjs "^6.5.4" semver "7.3.4" @@ -10769,7 +10780,48 @@ nth-check@^2.0.0, nth-check@^2.0.1: dependencies: boolbase "^1.0.0" -nx@15.5.3, "nx@>=15.4.2 < 16": +nx@15.6.3: + version "15.6.3" + resolved "https://registry.npmjs.org/nx/-/nx-15.6.3.tgz#900087bce38c6e5975660c23ebd41ead1bf54f98" + integrity sha512-3t0A0GPLNen1yPAyE+VGZ3nkAzZYb5nfXtAcx8SHBlKq4u42yBY3khBmP1y4Og3jhIwFIj7J7Npeh8ZKrthmYQ== + dependencies: + "@nrwl/cli" "15.6.3" + "@nrwl/tao" "15.6.3" + "@parcel/watcher" "2.0.4" + "@yarnpkg/lockfile" "^1.1.0" + "@yarnpkg/parsers" "^3.0.0-rc.18" + "@zkochan/js-yaml" "0.0.6" + axios "^1.0.0" + chalk "^4.1.0" + cli-cursor "3.1.0" + cli-spinners "2.6.1" + cliui "^7.0.2" + dotenv "~10.0.0" + enquirer "~2.3.6" + fast-glob "3.2.7" + figures "3.2.0" + flat "^5.0.2" + fs-extra "^11.1.0" + glob "7.1.4" + ignore "^5.0.4" + js-yaml "4.1.0" + jsonc-parser "3.2.0" + lines-and-columns "~2.0.3" + minimatch "3.0.5" + npm-run-path "^4.0.1" + open "^8.4.0" + semver "7.3.4" + string-width "^4.2.3" + strong-log-transformer "^2.1.0" + tar-stream "~2.2.0" + tmp "~0.2.1" + tsconfig-paths "^4.1.2" + tslib "^2.3.0" + v8-compile-cache "2.3.0" + yargs "^17.6.2" + yargs-parser "21.1.1" + +"nx@>=15.4.2 < 16": version "15.5.3" resolved "https://registry.npmjs.org/nx/-/nx-15.5.3.tgz#bf6252e7d9e17121dd82dec4f6fce319b9e005fa" integrity sha512-PHB8VbiBLP108xb+yR8IGEsYWr7OcmDDOjHL+73oP4lVjyPgT8wdTMe6tI5LdBgv+KZ+0kiThK3ckvcPsfgvLQ== From 99c091e0e3cf38a28aa5e1d1d2b03b602d51aa0a Mon Sep 17 00:00:00 2001 From: "typescript-eslint[bot]" Date: Tue, 31 Jan 2023 09:39:21 +0000 Subject: [PATCH 19/19] chore: publish v5.50.0 --- CHANGELOG.md | 19 +++++++++++++++++++ lerna.json | 2 +- packages/ast-spec/CHANGELOG.md | 11 +++++++++++ packages/ast-spec/package.json | 2 +- packages/eslint-plugin-internal/CHANGELOG.md | 8 ++++++++ packages/eslint-plugin-internal/package.json | 8 ++++---- packages/eslint-plugin-tslint/CHANGELOG.md | 8 ++++++++ packages/eslint-plugin-tslint/package.json | 6 +++--- packages/eslint-plugin/CHANGELOG.md | 18 ++++++++++++++++++ packages/eslint-plugin/package.json | 11 +++++------ packages/experimental-utils/CHANGELOG.md | 8 ++++++++ packages/experimental-utils/package.json | 4 ++-- packages/parser/CHANGELOG.md | 8 ++++++++ packages/parser/package.json | 8 ++++---- packages/scope-manager/CHANGELOG.md | 8 ++++++++ packages/scope-manager/package.json | 8 ++++---- packages/shared-fixtures/CHANGELOG.md | 8 ++++++++ packages/shared-fixtures/package.json | 2 +- packages/type-utils/CHANGELOG.md | 8 ++++++++ packages/type-utils/package.json | 8 ++++---- packages/types/CHANGELOG.md | 8 ++++++++ packages/types/package.json | 2 +- packages/typescript-estree/CHANGELOG.md | 8 ++++++++ packages/typescript-estree/package.json | 8 ++++---- packages/utils/CHANGELOG.md | 8 ++++++++ packages/utils/package.json | 10 +++++----- packages/visitor-keys/CHANGELOG.md | 8 ++++++++ packages/visitor-keys/package.json | 4 ++-- packages/website-eslint/CHANGELOG.md | 8 ++++++++ packages/website-eslint/package.json | 16 ++++++++-------- packages/website/CHANGELOG.md | 8 ++++++++ packages/website/package.json | 8 ++++---- 32 files changed, 205 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e18c2ad1d33c..9ad61e896afe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.50.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.49.0...v5.50.0) (2023-01-31) + + +### Bug Fixes + +* **ast-spec:** a JSXEmptyExpression is not a possible JSXExpression ([#6321](https://github.com/typescript-eslint/typescript-eslint/issues/6321)) ([4b27777](https://github.com/typescript-eslint/typescript-eslint/commit/4b27777ed26cc83d6efc52a89b2d3fc6c01bc0d7)) +* **eslint-plugin:** [ban-ts-comment] counts graphemes instead of `String.prototype.length` ([#5704](https://github.com/typescript-eslint/typescript-eslint/issues/5704)) ([09d57ce](https://github.com/typescript-eslint/typescript-eslint/commit/09d57cec8901880c6b24ea80dfa7d9fcdc463930)) +* **eslint-plugin:** [prefer-optional-chain] fix `ThisExpression` and `PrivateIdentifier` errors ([#6028](https://github.com/typescript-eslint/typescript-eslint/issues/6028)) ([85e783c](https://github.com/typescript-eslint/typescript-eslint/commit/85e783c1fabe96d390729a5796d6d346e401692b)) +* **eslint-plugin:** [prefer-optional-chain] fixer produces wrong logic ([#5919](https://github.com/typescript-eslint/typescript-eslint/issues/5919)) ([b0f6c8e](https://github.com/typescript-eslint/typescript-eslint/commit/b0f6c8ec0b372696ef26ca3a2b4f82dafd9dc417)), closes [#1438](https://github.com/typescript-eslint/typescript-eslint/issues/1438) + + +### Features + +* **eslint-plugin:** add `key-spacing` rule extension for interface & type declarations ([#6211](https://github.com/typescript-eslint/typescript-eslint/issues/6211)) ([67706e7](https://github.com/typescript-eslint/typescript-eslint/commit/67706e72e332bf11c82fdf51f3d417d3c93a86cf)) + + + + + # [5.49.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.48.2...v5.49.0) (2023-01-23) diff --git a/lerna.json b/lerna.json index ca3b45abd274..e150bc530f7f 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "5.49.0", + "version": "5.50.0", "npmClient": "yarn", "useWorkspaces": true, "stream": true diff --git a/packages/ast-spec/CHANGELOG.md b/packages/ast-spec/CHANGELOG.md index 49507c453596..3b4168eff864 100644 --- a/packages/ast-spec/CHANGELOG.md +++ b/packages/ast-spec/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.50.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.49.0...v5.50.0) (2023-01-31) + + +### Bug Fixes + +* **ast-spec:** a JSXEmptyExpression is not a possible JSXExpression ([#6321](https://github.com/typescript-eslint/typescript-eslint/issues/6321)) ([4b27777](https://github.com/typescript-eslint/typescript-eslint/commit/4b27777ed26cc83d6efc52a89b2d3fc6c01bc0d7)) + + + + + # [5.49.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.48.2...v5.49.0) (2023-01-23) **Note:** Version bump only for package @typescript-eslint/ast-spec diff --git a/packages/ast-spec/package.json b/packages/ast-spec/package.json index 75a1485853db..c5e160a5c415 100644 --- a/packages/ast-spec/package.json +++ b/packages/ast-spec/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/ast-spec", - "version": "5.49.0", + "version": "5.50.0", "description": "Complete specification for the TypeScript-ESTree AST", "private": true, "keywords": [ diff --git a/packages/eslint-plugin-internal/CHANGELOG.md b/packages/eslint-plugin-internal/CHANGELOG.md index 7bb1ad9d0df3..0cd6ad00030d 100644 --- a/packages/eslint-plugin-internal/CHANGELOG.md +++ b/packages/eslint-plugin-internal/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.50.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.49.0...v5.50.0) (2023-01-31) + +**Note:** Version bump only for package @typescript-eslint/eslint-plugin-internal + + + + + # [5.49.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.48.2...v5.49.0) (2023-01-23) **Note:** Version bump only for package @typescript-eslint/eslint-plugin-internal diff --git a/packages/eslint-plugin-internal/package.json b/packages/eslint-plugin-internal/package.json index b2e03c24a7ac..7b81526e7edd 100644 --- a/packages/eslint-plugin-internal/package.json +++ b/packages/eslint-plugin-internal/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin-internal", - "version": "5.49.0", + "version": "5.50.0", "private": true, "main": "dist/index.js", "scripts": { @@ -14,9 +14,9 @@ }, "dependencies": { "@types/prettier": "*", - "@typescript-eslint/scope-manager": "5.49.0", - "@typescript-eslint/type-utils": "5.49.0", - "@typescript-eslint/utils": "5.49.0", + "@typescript-eslint/scope-manager": "5.50.0", + "@typescript-eslint/type-utils": "5.50.0", + "@typescript-eslint/utils": "5.50.0", "prettier": "*" } } diff --git a/packages/eslint-plugin-tslint/CHANGELOG.md b/packages/eslint-plugin-tslint/CHANGELOG.md index 92e446a5cc68..b2551812889f 100644 --- a/packages/eslint-plugin-tslint/CHANGELOG.md +++ b/packages/eslint-plugin-tslint/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.50.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.49.0...v5.50.0) (2023-01-31) + +**Note:** Version bump only for package @typescript-eslint/eslint-plugin-tslint + + + + + # [5.49.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.48.2...v5.49.0) (2023-01-23) **Note:** Version bump only for package @typescript-eslint/eslint-plugin-tslint diff --git a/packages/eslint-plugin-tslint/package.json b/packages/eslint-plugin-tslint/package.json index 47762f6b1e07..23bf62f3fc5c 100644 --- a/packages/eslint-plugin-tslint/package.json +++ b/packages/eslint-plugin-tslint/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin-tslint", - "version": "5.49.0", + "version": "5.50.0", "main": "dist/index.js", "typings": "src/index.ts", "description": "ESLint plugin that wraps a TSLint configuration and lints the whole source using TSLint", @@ -38,7 +38,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/utils": "5.49.0", + "@typescript-eslint/utils": "5.50.0", "lodash": "^4.17.21" }, "peerDependencies": { @@ -48,6 +48,6 @@ }, "devDependencies": { "@types/lodash": "*", - "@typescript-eslint/parser": "5.49.0" + "@typescript-eslint/parser": "5.50.0" } } diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index 52c4bf72c2a1..25cce92ccc4f 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -3,6 +3,24 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.50.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.49.0...v5.50.0) (2023-01-31) + + +### Bug Fixes + +* **eslint-plugin:** [ban-ts-comment] counts graphemes instead of `String.prototype.length` ([#5704](https://github.com/typescript-eslint/typescript-eslint/issues/5704)) ([09d57ce](https://github.com/typescript-eslint/typescript-eslint/commit/09d57cec8901880c6b24ea80dfa7d9fcdc463930)) +* **eslint-plugin:** [prefer-optional-chain] fix `ThisExpression` and `PrivateIdentifier` errors ([#6028](https://github.com/typescript-eslint/typescript-eslint/issues/6028)) ([85e783c](https://github.com/typescript-eslint/typescript-eslint/commit/85e783c1fabe96d390729a5796d6d346e401692b)) +* **eslint-plugin:** [prefer-optional-chain] fixer produces wrong logic ([#5919](https://github.com/typescript-eslint/typescript-eslint/issues/5919)) ([b0f6c8e](https://github.com/typescript-eslint/typescript-eslint/commit/b0f6c8ec0b372696ef26ca3a2b4f82dafd9dc417)), closes [#1438](https://github.com/typescript-eslint/typescript-eslint/issues/1438) + + +### Features + +* **eslint-plugin:** add `key-spacing` rule extension for interface & type declarations ([#6211](https://github.com/typescript-eslint/typescript-eslint/issues/6211)) ([67706e7](https://github.com/typescript-eslint/typescript-eslint/commit/67706e72e332bf11c82fdf51f3d417d3c93a86cf)) + + + + + # [5.49.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.48.2...v5.49.0) (2023-01-23) diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 55992f5b7272..724b3eea0f1c 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin", - "version": "5.49.0", + "version": "5.50.0", "description": "TypeScript plugin for ESLint", "keywords": [ "eslint", @@ -44,13 +44,12 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/scope-manager": "5.49.0", - "@typescript-eslint/type-utils": "5.49.0", - "@typescript-eslint/utils": "5.49.0", + "@typescript-eslint/scope-manager": "5.50.0", + "@typescript-eslint/type-utils": "5.50.0", + "@typescript-eslint/utils": "5.50.0", "debug": "^4.3.4", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", - "grapheme-splitter": "^1.0.4", "natural-compare-lite": "^1.4.0", "regexpp": "^3.2.0", "semver": "^7.3.7", @@ -63,8 +62,8 @@ "@types/natural-compare-lite": "^1.4.0", "@types/prettier": "*", "chalk": "^5.0.1", - "grapheme-splitter": "^1.0.4", "cross-fetch": "^3.1.5", + "grapheme-splitter": "^1.0.4", "json-schema": "*", "markdown-table": "^3.0.2", "marked": "^4.0.15", diff --git a/packages/experimental-utils/CHANGELOG.md b/packages/experimental-utils/CHANGELOG.md index e578cc75abf2..a11333dc15c7 100644 --- a/packages/experimental-utils/CHANGELOG.md +++ b/packages/experimental-utils/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.50.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.49.0...v5.50.0) (2023-01-31) + +**Note:** Version bump only for package @typescript-eslint/experimental-utils + + + + + # [5.49.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.48.2...v5.49.0) (2023-01-23) **Note:** Version bump only for package @typescript-eslint/experimental-utils diff --git a/packages/experimental-utils/package.json b/packages/experimental-utils/package.json index ef176c09959a..e3d44a14dfec 100644 --- a/packages/experimental-utils/package.json +++ b/packages/experimental-utils/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/experimental-utils", - "version": "5.49.0", + "version": "5.50.0", "description": "(Experimental) Utilities for working with TypeScript + ESLint together", "keywords": [ "eslint", @@ -38,7 +38,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/utils": "5.49.0" + "@typescript-eslint/utils": "5.50.0" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" diff --git a/packages/parser/CHANGELOG.md b/packages/parser/CHANGELOG.md index e1b4ba3f6982..8dd79a4e7d19 100644 --- a/packages/parser/CHANGELOG.md +++ b/packages/parser/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.50.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.49.0...v5.50.0) (2023-01-31) + +**Note:** Version bump only for package @typescript-eslint/parser + + + + + # [5.49.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.48.2...v5.49.0) (2023-01-23) **Note:** Version bump only for package @typescript-eslint/parser diff --git a/packages/parser/package.json b/packages/parser/package.json index fd704210cc82..72b9df7a210c 100644 --- a/packages/parser/package.json +++ b/packages/parser/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/parser", - "version": "5.49.0", + "version": "5.50.0", "description": "An ESLint custom parser which leverages TypeScript ESTree", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -45,9 +45,9 @@ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "dependencies": { - "@typescript-eslint/scope-manager": "5.49.0", - "@typescript-eslint/types": "5.49.0", - "@typescript-eslint/typescript-estree": "5.49.0", + "@typescript-eslint/scope-manager": "5.50.0", + "@typescript-eslint/types": "5.50.0", + "@typescript-eslint/typescript-estree": "5.50.0", "debug": "^4.3.4" }, "devDependencies": { diff --git a/packages/scope-manager/CHANGELOG.md b/packages/scope-manager/CHANGELOG.md index 7643d240f880..4243c56c73e5 100644 --- a/packages/scope-manager/CHANGELOG.md +++ b/packages/scope-manager/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.50.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.49.0...v5.50.0) (2023-01-31) + +**Note:** Version bump only for package @typescript-eslint/scope-manager + + + + + # [5.49.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.48.2...v5.49.0) (2023-01-23) **Note:** Version bump only for package @typescript-eslint/scope-manager diff --git a/packages/scope-manager/package.json b/packages/scope-manager/package.json index b91e07821da8..afa72f7662a5 100644 --- a/packages/scope-manager/package.json +++ b/packages/scope-manager/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/scope-manager", - "version": "5.49.0", + "version": "5.50.0", "description": "TypeScript scope analyser for ESLint", "keywords": [ "eslint", @@ -38,12 +38,12 @@ "typecheck": "nx typecheck" }, "dependencies": { - "@typescript-eslint/types": "5.49.0", - "@typescript-eslint/visitor-keys": "5.49.0" + "@typescript-eslint/types": "5.50.0", + "@typescript-eslint/visitor-keys": "5.50.0" }, "devDependencies": { "@types/glob": "*", - "@typescript-eslint/typescript-estree": "5.49.0", + "@typescript-eslint/typescript-estree": "5.50.0", "glob": "*", "jest-specific-snapshot": "*", "make-dir": "*", diff --git a/packages/shared-fixtures/CHANGELOG.md b/packages/shared-fixtures/CHANGELOG.md index a5102cf788ee..3548d5254c6d 100644 --- a/packages/shared-fixtures/CHANGELOG.md +++ b/packages/shared-fixtures/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.50.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.49.0...v5.50.0) (2023-01-31) + +**Note:** Version bump only for package @typescript-eslint/shared-fixtures + + + + + # [5.49.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.48.2...v5.49.0) (2023-01-23) **Note:** Version bump only for package @typescript-eslint/shared-fixtures diff --git a/packages/shared-fixtures/package.json b/packages/shared-fixtures/package.json index 3abb676c6aec..0e3d35976d45 100644 --- a/packages/shared-fixtures/package.json +++ b/packages/shared-fixtures/package.json @@ -1,6 +1,6 @@ { "description": "Code fixtures used to test the typescript-estree parser.", "name": "@typescript-eslint/shared-fixtures", - "version": "5.49.0", + "version": "5.50.0", "private": true } diff --git a/packages/type-utils/CHANGELOG.md b/packages/type-utils/CHANGELOG.md index 97cbdcabbc03..26f418c1436c 100644 --- a/packages/type-utils/CHANGELOG.md +++ b/packages/type-utils/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.50.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.49.0...v5.50.0) (2023-01-31) + +**Note:** Version bump only for package @typescript-eslint/type-utils + + + + + # [5.49.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.48.2...v5.49.0) (2023-01-23) **Note:** Version bump only for package @typescript-eslint/type-utils diff --git a/packages/type-utils/package.json b/packages/type-utils/package.json index 88b6dc5b8988..2b44585a6821 100644 --- a/packages/type-utils/package.json +++ b/packages/type-utils/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/type-utils", - "version": "5.49.0", + "version": "5.50.0", "description": "Type utilities for working with TypeScript + ESLint together", "keywords": [ "eslint", @@ -39,13 +39,13 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/typescript-estree": "5.49.0", - "@typescript-eslint/utils": "5.49.0", + "@typescript-eslint/typescript-estree": "5.50.0", + "@typescript-eslint/utils": "5.50.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, "devDependencies": { - "@typescript-eslint/parser": "5.49.0", + "@typescript-eslint/parser": "5.50.0", "typescript": "*" }, "peerDependencies": { diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index 4424df99e42a..0cd6d24aa095 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.50.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.49.0...v5.50.0) (2023-01-31) + +**Note:** Version bump only for package @typescript-eslint/types + + + + + # [5.49.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.48.2...v5.49.0) (2023-01-23) **Note:** Version bump only for package @typescript-eslint/types diff --git a/packages/types/package.json b/packages/types/package.json index d35920bf1c59..ccc72bcd6986 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/types", - "version": "5.49.0", + "version": "5.50.0", "description": "Types for the TypeScript-ESTree AST spec", "keywords": [ "eslint", diff --git a/packages/typescript-estree/CHANGELOG.md b/packages/typescript-estree/CHANGELOG.md index 7db432d3477e..b74f9d0a82db 100644 --- a/packages/typescript-estree/CHANGELOG.md +++ b/packages/typescript-estree/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.50.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.49.0...v5.50.0) (2023-01-31) + +**Note:** Version bump only for package @typescript-eslint/typescript-estree + + + + + # [5.49.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.48.2...v5.49.0) (2023-01-23) diff --git a/packages/typescript-estree/package.json b/packages/typescript-estree/package.json index 6972beac90d4..728c8d417e96 100644 --- a/packages/typescript-estree/package.json +++ b/packages/typescript-estree/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/typescript-estree", - "version": "5.49.0", + "version": "5.50.0", "description": "A parser that converts TypeScript source code into an ESTree compatible form", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -42,8 +42,8 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/types": "5.49.0", - "@typescript-eslint/visitor-keys": "5.49.0", + "@typescript-eslint/types": "5.50.0", + "@typescript-eslint/visitor-keys": "5.50.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -59,7 +59,7 @@ "@types/is-glob": "*", "@types/semver": "*", "@types/tmp": "*", - "@typescript-eslint/shared-fixtures": "5.49.0", + "@typescript-eslint/shared-fixtures": "5.50.0", "glob": "*", "jest-specific-snapshot": "*", "make-dir": "*", diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md index 119494deff16..ec49364f3e77 100644 --- a/packages/utils/CHANGELOG.md +++ b/packages/utils/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.50.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.49.0...v5.50.0) (2023-01-31) + +**Note:** Version bump only for package @typescript-eslint/utils + + + + + # [5.49.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.48.2...v5.49.0) (2023-01-23) **Note:** Version bump only for package @typescript-eslint/utils diff --git a/packages/utils/package.json b/packages/utils/package.json index 5a1427cd7972..13e83257c675 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/utils", - "version": "5.49.0", + "version": "5.50.0", "description": "Utilities for working with TypeScript + ESLint together", "keywords": [ "eslint", @@ -41,9 +41,9 @@ "dependencies": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.49.0", - "@typescript-eslint/types": "5.49.0", - "@typescript-eslint/typescript-estree": "5.49.0", + "@typescript-eslint/scope-manager": "5.50.0", + "@typescript-eslint/types": "5.50.0", + "@typescript-eslint/typescript-estree": "5.50.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" @@ -52,7 +52,7 @@ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "devDependencies": { - "@typescript-eslint/parser": "5.49.0", + "@typescript-eslint/parser": "5.50.0", "typescript": "*" }, "funding": { diff --git a/packages/visitor-keys/CHANGELOG.md b/packages/visitor-keys/CHANGELOG.md index 77bc19f5a7d0..a7c260ce870f 100644 --- a/packages/visitor-keys/CHANGELOG.md +++ b/packages/visitor-keys/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.50.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.49.0...v5.50.0) (2023-01-31) + +**Note:** Version bump only for package @typescript-eslint/visitor-keys + + + + + # [5.49.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.48.2...v5.49.0) (2023-01-23) **Note:** Version bump only for package @typescript-eslint/visitor-keys diff --git a/packages/visitor-keys/package.json b/packages/visitor-keys/package.json index 0227b099772d..14527dc3f80c 100644 --- a/packages/visitor-keys/package.json +++ b/packages/visitor-keys/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/visitor-keys", - "version": "5.49.0", + "version": "5.50.0", "description": "Visitor keys used to help traverse the TypeScript-ESTree AST", "keywords": [ "eslint", @@ -39,7 +39,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/types": "5.49.0", + "@typescript-eslint/types": "5.50.0", "eslint-visitor-keys": "^3.3.0" }, "devDependencies": { diff --git a/packages/website-eslint/CHANGELOG.md b/packages/website-eslint/CHANGELOG.md index f8a5a882f820..ea36b42047a0 100644 --- a/packages/website-eslint/CHANGELOG.md +++ b/packages/website-eslint/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.50.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.49.0...v5.50.0) (2023-01-31) + +**Note:** Version bump only for package @typescript-eslint/website-eslint + + + + + # [5.49.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.48.2...v5.49.0) (2023-01-23) **Note:** Version bump only for package @typescript-eslint/website-eslint diff --git a/packages/website-eslint/package.json b/packages/website-eslint/package.json index 978b82451aed..6bb1f6d3f902 100644 --- a/packages/website-eslint/package.json +++ b/packages/website-eslint/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/website-eslint", - "version": "5.49.0", + "version": "5.50.0", "private": true, "description": "ESLint which works in browsers.", "engines": { @@ -16,19 +16,19 @@ "format": "prettier --write \"./**/*.{ts,mts,cts,tsx,js,mjs,cjs,jsx,json,md,css}\" --ignore-path ../../.prettierignore" }, "dependencies": { - "@typescript-eslint/types": "5.49.0", - "@typescript-eslint/utils": "5.49.0" + "@typescript-eslint/types": "5.50.0", + "@typescript-eslint/utils": "5.50.0" }, "devDependencies": { "@rollup/plugin-commonjs": "^23.0.0", "@rollup/plugin-json": "^5.0.0", "@rollup/plugin-node-resolve": "^15.0.0", "@rollup/pluginutils": "^5.0.0", - "@typescript-eslint/eslint-plugin": "5.49.0", - "@typescript-eslint/parser": "5.49.0", - "@typescript-eslint/scope-manager": "5.49.0", - "@typescript-eslint/typescript-estree": "5.49.0", - "@typescript-eslint/visitor-keys": "5.49.0", + "@typescript-eslint/eslint-plugin": "5.50.0", + "@typescript-eslint/parser": "5.50.0", + "@typescript-eslint/scope-manager": "5.50.0", + "@typescript-eslint/typescript-estree": "5.50.0", + "@typescript-eslint/visitor-keys": "5.50.0", "eslint": "*", "rollup": "^2.75.4", "rollup-plugin-terser": "^7.0.2", diff --git a/packages/website/CHANGELOG.md b/packages/website/CHANGELOG.md index 3558af9ab446..547367d081fd 100644 --- a/packages/website/CHANGELOG.md +++ b/packages/website/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.50.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.49.0...v5.50.0) (2023-01-31) + +**Note:** Version bump only for package website + + + + + # [5.49.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.48.2...v5.49.0) (2023-01-23) **Note:** Version bump only for package website diff --git a/packages/website/package.json b/packages/website/package.json index 2397fc252a2d..8f4ee2b74aa0 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -1,6 +1,6 @@ { "name": "website", - "version": "5.49.0", + "version": "5.50.0", "private": true, "scripts": { "build": "docusaurus build", @@ -21,8 +21,8 @@ "@docusaurus/remark-plugin-npm2yarn": "~2.2.0", "@docusaurus/theme-common": "~2.2.0", "@mdx-js/react": "1.6.22", - "@typescript-eslint/parser": "5.49.0", - "@typescript-eslint/website-eslint": "5.49.0", + "@typescript-eslint/parser": "5.50.0", + "@typescript-eslint/website-eslint": "5.50.0", "clsx": "^1.1.1", "eslint": "*", "json-schema": "^0.4.0", @@ -48,7 +48,7 @@ "@types/react": "^18.0.9", "@types/react-helmet": "^6.1.5", "@types/react-router-dom": "^5.3.3", - "@typescript-eslint/eslint-plugin": "5.49.0", + "@typescript-eslint/eslint-plugin": "5.50.0", "copy-webpack-plugin": "^11.0.0", "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-react": "^7.29.4", pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy