From 5c6c956f2032eddca39ee58104dee093da312ae2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Aug 2021 17:53:22 -0700 Subject: [PATCH 01/19] chore: bump @microsoft/api-extractor from 7.18.5 to 7.18.7 (#3801) Bumps [@microsoft/api-extractor](https://github.com/microsoft/rushstack) from 7.18.5 to 7.18.7. - [Release notes](https://github.com/microsoft/rushstack/releases) - [Commits](https://github.com/microsoft/rushstack/compare/@microsoft/api-extractor_v7.18.5...@microsoft/api-extractor_v7.18.7) --- updated-dependencies: - dependency-name: "@microsoft/api-extractor" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/yarn.lock b/yarn.lock index 0b88e0d193b..3dd4468a6de 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1695,16 +1695,16 @@ "@rushstack/node-core-library" "3.40.0" "@microsoft/api-extractor@^7.15.2": - version "7.18.5" - resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.18.5.tgz#cc2804d7c8b9d0f1e63fd85d0448569b767db102" - integrity sha512-NUGS6WxexziEnroHUOI3KKVmMX02god7SLA8Y4a5GKCL5k7AHuHFqP2bpd5Otx2odfbdj15ObO7FU/XA3Oxh8w== + version "7.18.7" + resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.18.7.tgz#851d2413a3c5d696f7cc914eb59de7a7882b2e8b" + integrity sha512-JhtV8LoyLuIecbgCPyZQg08G1kngIRWpai2UzwNil9mGVGYiDZVeeKx8c2phmlPcogmMDm4oQROxyuiYt5sJiw== dependencies: "@microsoft/api-extractor-model" "7.13.5" "@microsoft/tsdoc" "0.13.2" "@microsoft/tsdoc-config" "~0.15.2" "@rushstack/node-core-library" "3.40.0" - "@rushstack/rig-package" "0.2.13" - "@rushstack/ts-command-line" "4.8.1" + "@rushstack/rig-package" "0.3.0" + "@rushstack/ts-command-line" "4.9.0" colors "~1.2.1" lodash "~4.17.15" resolve "~1.17.0" @@ -1991,18 +1991,18 @@ timsort "~0.3.0" z-schema "~3.18.3" -"@rushstack/rig-package@0.2.13": - version "0.2.13" - resolved "https://registry.yarnpkg.com/@rushstack/rig-package/-/rig-package-0.2.13.tgz#418f0aeb4c9b33bd8bd2547759fc0ae91fd970c7" - integrity sha512-qQMAFKvfb2ooaWU9DrGIK9d8QfyHy/HiuITJbWenlKgzcDXQvQgEduk57YF4Y7LLasDJ5ZzLaaXwlfX8qCRe5Q== +"@rushstack/rig-package@0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@rushstack/rig-package/-/rig-package-0.3.0.tgz#334ad2846797861361b3445d4cc9ae9164b1885c" + integrity sha512-Lj6noF7Q4BBm1hKiBDw94e6uZvq1xlBwM/d2cBFaPqXeGdV+G6r3qaCWfRiSXK0pcHpGGpV5Tb2MdfhVcO6G/g== dependencies: resolve "~1.17.0" strip-json-comments "~3.1.1" -"@rushstack/ts-command-line@4.8.1": - version "4.8.1" - resolved "https://registry.yarnpkg.com/@rushstack/ts-command-line/-/ts-command-line-4.8.1.tgz#c233a0226112338e58e7e4fd219247b4e7cec883" - integrity sha512-rmxvYdCNRbyRs+DYAPye3g6lkCkWHleqO40K8UPvUAzFqEuj6+YCVssBiOmrUDCoM5gaegSNT0wFDYhz24DWtw== +"@rushstack/ts-command-line@4.9.0": + version "4.9.0" + resolved "https://registry.yarnpkg.com/@rushstack/ts-command-line/-/ts-command-line-4.9.0.tgz#781ba42cff73cae097b6d5241b6441e7cc2fe6e0" + integrity sha512-kmT8t+JfnvphISF1C5WwY56RefjwgajhSjs9J4ckvAFXZDXR6F5cvF5/RTh7fGCzIomg8esy2PHO/b52zFoZvA== dependencies: "@types/argparse" "1.0.38" argparse "~1.0.9" From e9b1c24a986b55b375f017ca25e8a165b9b59142 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Aug 2021 17:53:30 -0700 Subject: [PATCH 02/19] chore: bump @types/rimraf from 3.0.1 to 3.0.2 (#3782) Bumps [@types/rimraf](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/rimraf) from 3.0.1 to 3.0.2. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/rimraf) --- updated-dependencies: - dependency-name: "@types/rimraf" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 3dd4468a6de..5e7d8788f16 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2226,9 +2226,9 @@ integrity sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog== "@types/rimraf@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-3.0.1.tgz#1bbc106f0978742289103e080d4b41b3b4656e58" - integrity sha512-CAoSlbco40aKZ0CkelBF2g3JeN6aioRaTVnqSX5pWsn/WApm6IDxI4e4tD9D0dY/meCkyyleP1IQDVN13F4maA== + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-3.0.2.tgz#a63d175b331748e5220ad48c901d7bbf1f44eef8" + integrity sha512-F3OznnSLAUxFrCEu/L5PY8+ny8DtcFRjx7fZZ9bycvXRi3KPTRS9HOitGZwvPg0juRhXFWIeKX58cnX5YqLohQ== dependencies: "@types/glob" "*" "@types/node" "*" From 5f2b21f131137b2f6822260523c8e8cf192faac7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Aug 2021 17:53:36 -0700 Subject: [PATCH 03/19] chore: bump eslint-plugin-import from 2.24.0 to 2.24.2 (#3802) Bumps [eslint-plugin-import](https://github.com/import-js/eslint-plugin-import) from 2.24.0 to 2.24.2. - [Release notes](https://github.com/import-js/eslint-plugin-import/releases) - [Changelog](https://github.com/import-js/eslint-plugin-import/blob/main/CHANGELOG.md) - [Commits](https://github.com/import-js/eslint-plugin-import/compare/v2.24.0...v2.24.2) --- updated-dependencies: - dependency-name: eslint-plugin-import dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/yarn.lock b/yarn.lock index 5e7d8788f16..5a91e3e11d5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4084,10 +4084,10 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" -eslint-import-resolver-node@^0.3.5: - version "0.3.5" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.5.tgz#939bbb0f74e179e757ca87f7a4a890dabed18ac4" - integrity sha512-XMoPKjSpXbkeJ7ZZ9icLnJMTY5Mc1kZbCakHquaFsXPpyWOwK0TK6CODO+0ca54UoM9LKOxyUNnoVZRl8TeaAg== +eslint-import-resolver-node@^0.3.6: + version "0.3.6" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" + integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== dependencies: debug "^3.2.7" resolve "^1.20.0" @@ -4116,25 +4116,25 @@ eslint-plugin-eslint-plugin@^3.0.3: eslint-utils "^2.1.0" eslint-plugin-import@^2.23.4: - version "2.24.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.24.0.tgz#697ffd263e24da5e84e03b282f5fb62251777177" - integrity sha512-Kc6xqT9hiYi2cgybOc0I2vC9OgAYga5o/rAFinam/yF/t5uBqxQbauNPMC6fgb640T/89P0gFoO27FOilJ/Cqg== + version "2.24.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.24.2.tgz#2c8cd2e341f3885918ee27d18479910ade7bb4da" + integrity sha512-hNVtyhiEtZmpsabL4neEj+6M5DCLgpYyG9nzJY8lZQeQXEn5UPW1DpUdsMHMXsq98dbNm7nt1w9ZMSVpfJdi8Q== dependencies: array-includes "^3.1.3" array.prototype.flat "^1.2.4" debug "^2.6.9" doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.5" + eslint-import-resolver-node "^0.3.6" eslint-module-utils "^2.6.2" find-up "^2.0.0" has "^1.0.3" - is-core-module "^2.4.0" + is-core-module "^2.6.0" minimatch "^3.0.4" - object.values "^1.1.3" + object.values "^1.1.4" pkg-up "^2.0.0" read-pkg-up "^3.0.0" resolve "^1.20.0" - tsconfig-paths "^3.9.0" + tsconfig-paths "^3.11.0" eslint-plugin-jest@^24.3.6: version "24.4.0" @@ -5471,10 +5471,10 @@ is-ci@^3.0.0: dependencies: ci-info "^3.1.1" -is-core-module@^2.1.0, is-core-module@^2.2.0, is-core-module@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.4.0.tgz#8e9fc8e15027b011418026e98f0e6f4d86305cc1" - integrity sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A== +is-core-module@^2.1.0, is-core-module@^2.2.0, is-core-module@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.6.0.tgz#d7553b2526fe59b92ba3e40c8df757ec8a709e19" + integrity sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ== dependencies: has "^1.0.3" @@ -7507,7 +7507,7 @@ object.pick@^1.3.0: dependencies: isobject "^3.0.1" -object.values@^1.1.3: +object.values@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.4.tgz#0d273762833e816b693a637d30073e7051535b30" integrity sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg== @@ -9357,10 +9357,10 @@ ts-node@^10.0.0: make-error "^1.1.1" yn "3.1.1" -tsconfig-paths@^3.9.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b" - integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw== +tsconfig-paths@^3.11.0: + version "3.11.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz#954c1fe973da6339c78e06b03ce2e48810b65f36" + integrity sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA== dependencies: "@types/json5" "^0.0.29" json5 "^1.0.1" From 29a67f2120fbc2b7cc19722689b7485d41badb9e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Aug 2021 17:53:45 -0700 Subject: [PATCH 04/19] chore: bump ts-node from 10.2.0 to 10.2.1 (#3781) Bumps [ts-node](https://github.com/TypeStrong/ts-node) from 10.2.0 to 10.2.1. - [Release notes](https://github.com/TypeStrong/ts-node/releases) - [Commits](https://github.com/TypeStrong/ts-node/compare/v10.2.0...v10.2.1) --- updated-dependencies: - dependency-name: ts-node dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 5a91e3e11d5..c7593cce0ca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9340,9 +9340,9 @@ ts-jest@^27.0.1: yargs-parser "20.x" ts-node@^10.0.0: - version "10.2.0" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.2.0.tgz#f1e88249a00e26aa95e9a93c50f70241a8a1c4bb" - integrity sha512-FstYHtQz6isj8rBtYMN4bZdnXN1vq4HCbqn9vdNQcInRqtB86PePJQIxE6es0PhxKWhj2PHuwbG40H+bxkZPmg== + version "10.2.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.2.1.tgz#4cc93bea0a7aba2179497e65bb08ddfc198b3ab5" + integrity sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw== dependencies: "@cspotcode/source-map-support" "0.6.1" "@tsconfig/node10" "^1.0.7" From cf3b44f4145a5ae76691b661e81dadf5ff7f33e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Aug 2021 17:53:54 -0700 Subject: [PATCH 05/19] chore: bump cspell from 5.7.2 to 5.8.2 (#3803) Bumps [cspell](https://github.com/streetsidesoftware/cspell) from 5.7.2 to 5.8.2. - [Release notes](https://github.com/streetsidesoftware/cspell/releases) - [Changelog](https://github.com/streetsidesoftware/cspell/blob/main/CHANGELOG.md) - [Commits](https://github.com/streetsidesoftware/cspell/compare/v5.7.2...v5.8.2) --- updated-dependencies: - dependency-name: cspell dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 122 +++++++++++++++++++++++++++++------------------------- 1 file changed, 66 insertions(+), 56 deletions(-) diff --git a/yarn.lock b/yarn.lock index c7593cce0ca..47e7497140d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -461,10 +461,10 @@ dependencies: chalk "^4.0.0" -"@cspell/cspell-bundled-dicts@^5.7.2": - version "5.7.2" - resolved "https://registry.yarnpkg.com/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.7.2.tgz#077264d9aeed15e33dda12dcbde441f0e77db63a" - integrity sha512-Vd//xmvA1YeTpyCBbt3fVjYKNbCI6tvS9/Cfjt8PmV91loysX4TWJnI+mRY+2Eltf4WfW6SAtbC7/YUWrvBgQA== +"@cspell/cspell-bundled-dicts@^5.8.2": + version "5.8.2" + resolved "https://registry.yarnpkg.com/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.8.2.tgz#8abae7b1181b8300d3baa39833d336ce9f9adc52" + integrity sha512-W4YzuDdMqL6UIgDkocFNzxuLvoiN8sl+Nt+KbEDx0miSkrcP3GabBNNuH1xY/n0QofEhZMSx1cRH9US/ROdHkQ== dependencies: "@cspell/dict-ada" "^1.1.2" "@cspell/dict-aws" "^1.0.14" @@ -475,11 +475,11 @@ "@cspell/dict-csharp" "^1.0.11" "@cspell/dict-css" "^1.0.12" "@cspell/dict-django" "^1.0.26" - "@cspell/dict-dotnet" "^1.0.29" + "@cspell/dict-dotnet" "^1.0.30" "@cspell/dict-elixir" "^1.0.25" "@cspell/dict-en-gb" "^1.1.32" "@cspell/dict-en_us" "^1.2.45" - "@cspell/dict-filetypes" "^1.1.7" + "@cspell/dict-filetypes" "^1.1.8" "@cspell/dict-fonts" "^1.0.14" "@cspell/dict-fullstack" "^1.0.38" "@cspell/dict-golang" "^1.1.24" @@ -491,7 +491,7 @@ "@cspell/dict-lorem-ipsum" "^1.0.22" "@cspell/dict-lua" "^1.0.16" "@cspell/dict-node" "^1.0.12" - "@cspell/dict-npm" "^1.0.15" + "@cspell/dict-npm" "^1.0.16" "@cspell/dict-php" "^1.0.24" "@cspell/dict-powershell" "^1.0.18" "@cspell/dict-public-licenses" "^1.0.3" @@ -499,13 +499,13 @@ "@cspell/dict-ruby" "^1.0.14" "@cspell/dict-rust" "^1.0.23" "@cspell/dict-scala" "^1.0.21" - "@cspell/dict-software-terms" "^1.0.40" + "@cspell/dict-software-terms" "^1.0.41" "@cspell/dict-typescript" "^1.0.19" -"@cspell/cspell-types@^5.7.2": - version "5.7.2" - resolved "https://registry.yarnpkg.com/@cspell/cspell-types/-/cspell-types-5.7.2.tgz#93c2632cf8ce9ae98f55503380709b13da891b9c" - integrity sha512-hRInos9xQxPk8Wv0Y23UwFddN5RkyKVhqqH6kEeWir1sok2eMy58n/eIJvVPyhx1LVeP4QS4a/n6/OigUQrNVw== +"@cspell/cspell-types@^5.8.2": + version "5.8.2" + resolved "https://registry.yarnpkg.com/@cspell/cspell-types/-/cspell-types-5.8.2.tgz#aeaf780ea0fd8d632b4e02f4d2296e3357a109d0" + integrity sha512-BWih6zBzpyFQiuBHyybByFtLCVfAJNX1G/ZvUgTFWna2xwWS0edQ3qp0H+v+FBRVCo2RHy4cmAfgzyCGtXHOmw== "@cspell/dict-ada@^1.1.2": version "1.1.2" @@ -552,10 +552,10 @@ resolved "https://registry.yarnpkg.com/@cspell/dict-django/-/dict-django-1.0.26.tgz#b97ce0112fbe8c3c3ada0387c68971b5e27483ab" integrity sha512-mn9bd7Et1L2zuibc08GVHTiD2Go3/hdjyX5KLukXDklBkq06r+tb0OtKtf1zKodtFDTIaYekGADhNhA6AnKLkg== -"@cspell/dict-dotnet@^1.0.29": - version "1.0.29" - resolved "https://registry.yarnpkg.com/@cspell/dict-dotnet/-/dict-dotnet-1.0.29.tgz#e362a85b28c2862f49da7949a7cc347f872b0df4" - integrity sha512-41fx7YQM986MBAyJpqL0fH6WOKLG/tNev4NbydNy3avYxz/smr+VwIwGN9/GLNORL5hQLiSQxPU5jfpx+bN94g== +"@cspell/dict-dotnet@^1.0.30": + version "1.0.30" + resolved "https://registry.yarnpkg.com/@cspell/dict-dotnet/-/dict-dotnet-1.0.30.tgz#0e80294fe2894b65d059130115a54c33adcb76f8" + integrity sha512-86kC5191GACB95IGtLnmYHZjuNl/Ee7lvZRcwEyvktoYiRAryd1YKSX+c/qU1OEx7Y52FTaEl07tf9uYS1wKNQ== "@cspell/dict-elixir@^1.0.25": version "1.0.25" @@ -572,10 +572,10 @@ resolved "https://registry.yarnpkg.com/@cspell/dict-en_us/-/dict-en_us-1.2.45.tgz#1314a9d81a1fd3cc7ed381dc6a0da10e7c2d02f9" integrity sha512-UPwR4rfiJCxnS+Py+EK9E4AUj3aPZE4p/yBRSHN+5aBQConlI0lLDtMceH5wlupA/sQTU1ERZGPJA9L96jVSyQ== -"@cspell/dict-filetypes@^1.1.7": - version "1.1.7" - resolved "https://registry.yarnpkg.com/@cspell/dict-filetypes/-/dict-filetypes-1.1.7.tgz#98c69f006041c145e3205c2f7fa617645a5b78ec" - integrity sha512-b0e+eiBzTiL1yJZgPBGHP8G7Z0Kkpr/35dXlR9LWoP/EnrAlVj0ulXwErPgTwSoFdxWBgbDJjKZsrMdxWCckuA== +"@cspell/dict-filetypes@^1.1.8": + version "1.1.8" + resolved "https://registry.yarnpkg.com/@cspell/dict-filetypes/-/dict-filetypes-1.1.8.tgz#c161ab48667b6539cbc91a70ff0b037fa436a64e" + integrity sha512-EllahNkhzvLWo0ptwu0l3oEeAJOQSUpZnDfnKRIh6mJVehuSovNHwA9vrdZ8jBUjuqcfaN2e7c32zN0D/qvWJQ== "@cspell/dict-fonts@^1.0.14": version "1.0.14" @@ -632,10 +632,10 @@ resolved "https://registry.yarnpkg.com/@cspell/dict-node/-/dict-node-1.0.12.tgz#a7236be30340ff8fe365f62c8d13121fdbe7f51c" integrity sha512-RPNn/7CSkflAWk0sbSoOkg0ORrgBARUjOW3QjB11KwV1gSu8f5W/ij/S50uIXtlrfoBLqd4OyE04jyON+g/Xfg== -"@cspell/dict-npm@^1.0.15": - version "1.0.15" - resolved "https://registry.yarnpkg.com/@cspell/dict-npm/-/dict-npm-1.0.15.tgz#4eac51a4e5258b48e2fd1af277c12cb1fd189f4d" - integrity sha512-6N1G1rGi5AsCaDu9mu+VmrrAj5S9gHv8TvJlarauDeEMS6uVl+ce2JpzDf7ld3Qu/4Dkr0sKS63OeA0DKeQTkw== +"@cspell/dict-npm@^1.0.16": + version "1.0.16" + resolved "https://registry.yarnpkg.com/@cspell/dict-npm/-/dict-npm-1.0.16.tgz#86870686cd0af6354a206ab297872db1d84e9c1b" + integrity sha512-RwkuZGcYBxL3Yux3cSG/IOWGlQ1e9HLCpHeyMtTVGYKAIkFAVUnGrz20l16/Q7zUG7IEktBz5O42kAozrEnqMQ== "@cspell/dict-php@^1.0.24": version "1.0.24" @@ -672,10 +672,10 @@ resolved "https://registry.yarnpkg.com/@cspell/dict-scala/-/dict-scala-1.0.21.tgz#bfda392329061e2352fbcd33d228617742c93831" integrity sha512-5V/R7PRbbminTpPS3ywgdAalI9BHzcEjEj9ug4kWYvBIGwSnS7T6QCFCiu+e9LvEGUqQC+NHgLY4zs1NaBj2vA== -"@cspell/dict-software-terms@^1.0.40": - version "1.0.40" - resolved "https://registry.yarnpkg.com/@cspell/dict-software-terms/-/dict-software-terms-1.0.40.tgz#b9d02e62b81e8213f3ec8d44227af6610eb8ff30" - integrity sha512-aHEIgjZJwqn4I+tlQ2XvC4l106VS2bSzNU8crRadpcbpuL5UC2nzMgEbEOAHK4gP1P9i009ttFB0PTKTGisKgg== +"@cspell/dict-software-terms@^1.0.41": + version "1.0.41" + resolved "https://registry.yarnpkg.com/@cspell/dict-software-terms/-/dict-software-terms-1.0.41.tgz#c8b9ca8e8891e09c2e55afd889bde38f6d7b109a" + integrity sha512-/RWiv99XoDUYh3eCo5PyF2nwDh0U8kuKmSW+UXpzbT4sj7oBl/la19h6Ahgq0Qmr0JGjTF/RxbQkz85Hcp1t5w== "@cspell/dict-typescript@^1.0.19": version "1.0.19" @@ -3496,6 +3496,17 @@ cosmiconfig@^7.0.0: path-type "^4.0.0" yaml "^1.10.0" +cosmiconfig@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" + integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.2.1" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.10.0" + create-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" @@ -3526,35 +3537,35 @@ crypto-random-string@^2.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== -cspell-glob@^5.7.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/cspell-glob/-/cspell-glob-5.7.0.tgz#f14ad50fb469717220fd4e3e92a0174d3e3b31e2" - integrity sha512-A6LlFT1MWLT8bb0o3xDlXysbuYWM/1U1Rt/iOI/Pi3C9Myqig/WHVKEZ/Lmda6ZI5eRLyDhgi+Y90sUwpd9iEQ== +cspell-glob@^5.8.2: + version "5.8.2" + resolved "https://registry.yarnpkg.com/cspell-glob/-/cspell-glob-5.8.2.tgz#56b301d7cece39f1e9b1b64dbf77f9e1d5c96e00" + integrity sha512-8BUvX0gsLHXx6uAaCO6T2l/U3xBNiFywvnwLK7648Q7IY3TzQV/L01ESbC+DrzT6G2KCA2bvQKByXJraqTTCaw== dependencies: micromatch "^4.0.4" -cspell-io@^5.7.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/cspell-io/-/cspell-io-5.7.0.tgz#5735893dda2e3e37dd981434553118bcf953843f" - integrity sha512-WOn8KwrYYpTfHJkmNG3fd+pT+NX7D1v6AcjYN6sm99fQtbY6z7xMAnjXcneGabUbQMNhAvaW56sB1pR0ABEvGA== +cspell-io@^5.8.2: + version "5.8.2" + resolved "https://registry.yarnpkg.com/cspell-io/-/cspell-io-5.8.2.tgz#66c43830dd28822397a357d9bfa65e2f77c71c26" + integrity sha512-5ejb38VchMml840gigYO5oanOcef681pLstqwQt71yV+CG4YSyJK7RqPTeDHgsXbRkntdUrbydwza0481szVkQ== dependencies: iconv-lite "^0.6.3" iterable-to-stream "^2.0.0" -cspell-lib@^5.7.2: - version "5.7.2" - resolved "https://registry.yarnpkg.com/cspell-lib/-/cspell-lib-5.7.2.tgz#5e2d47bb2a63931abebefd3030ba830de5657314" - integrity sha512-9C0d96+6GeLgyek//lCXcVpk2VeuwBUU4T+0gmnzPGYEOV1uNNK79SspFsSFZvL6+un5ztO+sQ+2MxR9zMF+gw== +cspell-lib@^5.8.2: + version "5.8.2" + resolved "https://registry.yarnpkg.com/cspell-lib/-/cspell-lib-5.8.2.tgz#3a91fa2fe3b2c1607d003dbcce0f2ca41c7d613c" + integrity sha512-Z6W+oHnmmUstdEypwMiqlnLOaA68r1T3i5OE2t+t2sxLAUgqCiTFEUQzu/yv/7vAIRKawdHuAq1rqrNKZXulbQ== dependencies: - "@cspell/cspell-bundled-dicts" "^5.7.2" - "@cspell/cspell-types" "^5.7.2" + "@cspell/cspell-bundled-dicts" "^5.8.2" + "@cspell/cspell-types" "^5.8.2" clear-module "^4.1.1" comment-json "^4.1.1" configstore "^5.0.1" - cosmiconfig "^7.0.0" - cspell-glob "^5.7.0" - cspell-io "^5.7.0" - cspell-trie-lib "^5.7.0" + cosmiconfig "^7.0.1" + cspell-glob "^5.8.2" + cspell-io "^5.8.2" + cspell-trie-lib "^5.8.2" find-up "^5.0.0" fs-extra "^10.0.0" gensequence "^3.1.1" @@ -3563,25 +3574,24 @@ cspell-lib@^5.7.2: resolve-global "^1.0.0" vscode-uri "^3.0.2" -cspell-trie-lib@^5.7.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/cspell-trie-lib/-/cspell-trie-lib-5.7.0.tgz#d80978e3da682290ae8cccb71af9c4455ad3cfca" - integrity sha512-XDJrQG2SuQOJRVj6kNUdehLHJdj+1SGzKEvFJbRAzvIRPW75zDe3+yYHHmNOZgXJXLfe0Vtr3RjSjhaQOWZ42Q== +cspell-trie-lib@^5.8.2: + version "5.8.2" + resolved "https://registry.yarnpkg.com/cspell-trie-lib/-/cspell-trie-lib-5.8.2.tgz#266a58c21c3ead1eb8434accca6cca7d7abd183d" + integrity sha512-gvNwZO8QIqMTek2ZK/CeYYupzdXnIym7ytOgy7ycE/UIeNzJh/STC62Pe44CNvL86Xh1wgS4wFnh0pF6QRkZFw== dependencies: fs-extra "^10.0.0" gensequence "^3.1.1" cspell@^5.5.2: - version "5.7.2" - resolved "https://registry.yarnpkg.com/cspell/-/cspell-5.7.2.tgz#7218ceaa71e1e87e6d67b375c6371f61940d7ded" - integrity sha512-FJAPt3GkwdVaX6I+GR1A95WsraqHPzYqkBI1rIHNE5JnJIbWW6N+pnlbhDjsUlPWXmQYHXMfUlhFtMVLUVs3mw== + version "5.8.2" + resolved "https://registry.yarnpkg.com/cspell/-/cspell-5.8.2.tgz#708067660270f3900816d99c6b055dafa8ebd6d0" + integrity sha512-yamhOvEDXq/f0ko1icR3FUH/pfbGnz5LqtnkDKskVhm5tzv2kUxUNbmYwBAYzs7N1igE+AokL1G7D/Rw9LCLBg== dependencies: - "@cspell/cspell-types" "^5.7.2" chalk "^4.1.2" commander "^8.1.0" comment-json "^4.1.1" - cspell-glob "^5.7.0" - cspell-lib "^5.7.2" + cspell-glob "^5.8.2" + cspell-lib "^5.8.2" fs-extra "^10.0.0" get-stdin "^8.0.0" glob "^7.1.7" From 058a6bfc500754be6529400a46f2a83d30c26d14 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 01:18:48 +0000 Subject: [PATCH 06/19] chore: bump tar from 4.4.15 to 4.4.19 (#3827) --- yarn.lock | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/yarn.lock b/yarn.lock index 47e7497140d..e643dfff159 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3037,7 +3037,7 @@ chokidar@^3.5.1: optionalDependencies: fsevents "~2.3.2" -chownr@^1.1.1, chownr@^1.1.2, chownr@^1.1.3: +chownr@^1.1.1, chownr@^1.1.2, chownr@^1.1.3, chownr@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== @@ -4688,7 +4688,7 @@ fs-extra@~7.0.1: jsonfile "^4.0.0" universalify "^0.1.0" -fs-minipass@^1.2.5: +fs-minipass@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== @@ -7113,7 +7113,7 @@ minimist@1.2.5, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5, minimist@~1.2 resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== -minipass@^2.3.5, minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: +minipass@^2.3.5, minipass@^2.6.0, minipass@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== @@ -7128,7 +7128,7 @@ minipass@^3.0.0: dependencies: yallist "^4.0.0" -minizlib@^1.2.1: +minizlib@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== @@ -7179,7 +7179,7 @@ mkdirp@*, mkdirp@1.x: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3: +mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5: version "0.5.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== @@ -8517,7 +8517,7 @@ rxjs@^6.4.0, rxjs@^6.5.4, rxjs@^6.6.0, rxjs@^6.6.7: dependencies: tslib "^1.9.0" -safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -9125,17 +9125,17 @@ tar@5.0.7: yallist "^4.0.0" tar@^4.4.10, tar@^4.4.12, tar@^4.4.8: - version "4.4.15" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.15.tgz#3caced4f39ebd46ddda4d6203d48493a919697f8" - integrity sha512-ItbufpujXkry7bHH9NpQyTXPbJ72iTlXgkBAYsAjDXk3Ds8t/3NfO5P4xZGy7u+sYuQUbimgzswX4uQIEeNVOA== + version "4.4.19" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3" + integrity sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA== dependencies: - chownr "^1.1.1" - fs-minipass "^1.2.5" - minipass "^2.8.6" - minizlib "^1.2.1" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.3" + chownr "^1.1.4" + fs-minipass "^1.2.7" + minipass "^2.9.0" + minizlib "^1.3.3" + mkdirp "^0.5.5" + safe-buffer "^5.2.1" + yallist "^3.1.1" temp-dir@^1.0.0: version "1.0.0" @@ -9926,7 +9926,7 @@ y18n@^5.0.5: resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.5.tgz#8769ec08d03b1ea2df2500acef561743bbb9ab18" integrity sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg== -yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: +yallist@^3.0.0, yallist@^3.0.2, yallist@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== From 780548cd616bd239767febd8a652bcc40b3a8c31 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Aug 2021 22:25:46 -0700 Subject: [PATCH 07/19] chore: bump cspell from 5.8.2 to 5.9.0 (#3828) Bumps [cspell](https://github.com/streetsidesoftware/cspell) from 5.8.2 to 5.9.0. - [Release notes](https://github.com/streetsidesoftware/cspell/releases) - [Changelog](https://github.com/streetsidesoftware/cspell/blob/main/CHANGELOG.md) - [Commits](https://github.com/streetsidesoftware/cspell/compare/v5.8.2...v5.9.0) --- updated-dependencies: - dependency-name: cspell dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 98 +++++++++++++++++++++++++++---------------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/yarn.lock b/yarn.lock index e643dfff159..26293b72031 100644 --- a/yarn.lock +++ b/yarn.lock @@ -461,24 +461,24 @@ dependencies: chalk "^4.0.0" -"@cspell/cspell-bundled-dicts@^5.8.2": - version "5.8.2" - resolved "https://registry.yarnpkg.com/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.8.2.tgz#8abae7b1181b8300d3baa39833d336ce9f9adc52" - integrity sha512-W4YzuDdMqL6UIgDkocFNzxuLvoiN8sl+Nt+KbEDx0miSkrcP3GabBNNuH1xY/n0QofEhZMSx1cRH9US/ROdHkQ== +"@cspell/cspell-bundled-dicts@^5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.9.0.tgz#4afef125ddedf13d43bb4114fdfcc3b42450e91e" + integrity sha512-qI/MVTYjGh0Uhhx2YiqCIodfazHojcwJx6yzNkQQXZN7px0rGUPsRPiPx83LuHl1aE+APc5x8cblCwnnZUbPxg== dependencies: "@cspell/dict-ada" "^1.1.2" "@cspell/dict-aws" "^1.0.14" "@cspell/dict-bash" "^1.0.15" "@cspell/dict-companies" "^1.0.40" - "@cspell/dict-cpp" "^1.1.39" + "@cspell/dict-cpp" "^1.1.40" "@cspell/dict-cryptocurrencies" "^1.0.10" "@cspell/dict-csharp" "^1.0.11" "@cspell/dict-css" "^1.0.12" "@cspell/dict-django" "^1.0.26" "@cspell/dict-dotnet" "^1.0.30" "@cspell/dict-elixir" "^1.0.25" - "@cspell/dict-en-gb" "^1.1.32" - "@cspell/dict-en_us" "^1.2.45" + "@cspell/dict-en-gb" "^1.1.33" + "@cspell/dict-en_us" "^2.0.2" "@cspell/dict-filetypes" "^1.1.8" "@cspell/dict-fonts" "^1.0.14" "@cspell/dict-fullstack" "^1.0.38" @@ -502,10 +502,10 @@ "@cspell/dict-software-terms" "^1.0.41" "@cspell/dict-typescript" "^1.0.19" -"@cspell/cspell-types@^5.8.2": - version "5.8.2" - resolved "https://registry.yarnpkg.com/@cspell/cspell-types/-/cspell-types-5.8.2.tgz#aeaf780ea0fd8d632b4e02f4d2296e3357a109d0" - integrity sha512-BWih6zBzpyFQiuBHyybByFtLCVfAJNX1G/ZvUgTFWna2xwWS0edQ3qp0H+v+FBRVCo2RHy4cmAfgzyCGtXHOmw== +"@cspell/cspell-types@^5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@cspell/cspell-types/-/cspell-types-5.9.0.tgz#1d74c2cb191f9dc7d899364a3ac366d00df181d8" + integrity sha512-S3O/4CNTTljQmWZpbBrG8IHPg9zWQ5rYpQ0tc9zoM1q/RzZev8xc55rggRu3IqtkwzyZUjVFo8apwQF5UZHXMg== "@cspell/dict-ada@^1.1.2": version "1.1.2" @@ -527,10 +527,10 @@ resolved "https://registry.yarnpkg.com/@cspell/dict-companies/-/dict-companies-1.0.40.tgz#edd7f47fc683dfa1b02cd48fb12ad732d2eece61" integrity sha512-Aw07qiTroqSST2P5joSrC4uOA05zTXzI2wMb+me3q4Davv1D9sCkzXY0TGoC2vzhNv5ooemRi9KATGaBSdU1sw== -"@cspell/dict-cpp@^1.1.39": - version "1.1.39" - resolved "https://registry.yarnpkg.com/@cspell/dict-cpp/-/dict-cpp-1.1.39.tgz#7e119e2c009f9200127733cbca3435180c405c70" - integrity sha512-zrQjzMaT5YqAa4PMEaLfOWnfyh4uJjW53kwtuTo9nfJPaga2+FfrqdeWD8XYMxvTGCtzjivXhAn4FDIMh+66YQ== +"@cspell/dict-cpp@^1.1.40": + version "1.1.40" + resolved "https://registry.yarnpkg.com/@cspell/dict-cpp/-/dict-cpp-1.1.40.tgz#f9a859e19d31b83f07a106e4c3c8720a2d93595b" + integrity sha512-sscfB3woNDNj60/yGXAdwNtIRWZ89y35xnIaJVDMk5TPMMpaDvuk0a34iOPIq0g4V+Y8e3RyAg71SH6ADwSjGw== "@cspell/dict-cryptocurrencies@^1.0.10": version "1.0.10" @@ -562,15 +562,15 @@ resolved "https://registry.yarnpkg.com/@cspell/dict-elixir/-/dict-elixir-1.0.25.tgz#bec4fd754c99f646e553184df12df88b54da1c04" integrity sha512-ZmawoBYjM5k+8fNudRMkK+PpHjhyAFAZt2rUu1EGj2rbCvE3Fn2lhRbDjbreN7nWRvcLRTW+xuPXtKP11X0ahQ== -"@cspell/dict-en-gb@^1.1.32": - version "1.1.32" - resolved "https://registry.yarnpkg.com/@cspell/dict-en-gb/-/dict-en-gb-1.1.32.tgz#587057d1cfac67aa3f2a950ec00ec3e33a239689" - integrity sha512-iu83IDyCefo0T4NipEa3jtpJ/WDSr1IWt35kljolj7HFDFrjLr4Y/2t8yqtmB4otturWpa5T/G3/k90y2KU08Q== +"@cspell/dict-en-gb@^1.1.33": + version "1.1.33" + resolved "https://registry.yarnpkg.com/@cspell/dict-en-gb/-/dict-en-gb-1.1.33.tgz#7f1fd90fc364a5cb77111b5438fc9fcf9cc6da0e" + integrity sha512-tKSSUf9BJEV+GJQAYGw5e+ouhEe2ZXE620S7BLKe3ZmpnjlNG9JqlnaBhkIMxKnNFkLY2BP/EARzw31AZnOv4g== -"@cspell/dict-en_us@^1.2.45": - version "1.2.45" - resolved "https://registry.yarnpkg.com/@cspell/dict-en_us/-/dict-en_us-1.2.45.tgz#1314a9d81a1fd3cc7ed381dc6a0da10e7c2d02f9" - integrity sha512-UPwR4rfiJCxnS+Py+EK9E4AUj3aPZE4p/yBRSHN+5aBQConlI0lLDtMceH5wlupA/sQTU1ERZGPJA9L96jVSyQ== +"@cspell/dict-en_us@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@cspell/dict-en_us/-/dict-en_us-2.0.2.tgz#9087b99ef9efa9e77d1b2546feb454e4067cbaac" + integrity sha512-g6TL4ynWHoxVKvQ0kdiMCbh4+FeXwmHFTL/dWgQbyfy6cqKXjsOqPK0OPVFIbqI5rV8QeBx5IH6ny/q/XQOvXQ== "@cspell/dict-filetypes@^1.1.8": version "1.1.8" @@ -3537,35 +3537,35 @@ crypto-random-string@^2.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== -cspell-glob@^5.8.2: - version "5.8.2" - resolved "https://registry.yarnpkg.com/cspell-glob/-/cspell-glob-5.8.2.tgz#56b301d7cece39f1e9b1b64dbf77f9e1d5c96e00" - integrity sha512-8BUvX0gsLHXx6uAaCO6T2l/U3xBNiFywvnwLK7648Q7IY3TzQV/L01ESbC+DrzT6G2KCA2bvQKByXJraqTTCaw== +cspell-glob@^5.9.0: + version "5.9.0" + resolved "https://registry.yarnpkg.com/cspell-glob/-/cspell-glob-5.9.0.tgz#ecb493cd3e12ea9cbefe4aca1cb9e86638825288" + integrity sha512-4yhDg/oJpujKNOIX6EBmeb935vyBVXgd0SVb7AR183En9lTUPkT7PR4lTYKxolNs3/z4Ajx+xwA8DORW7E5Rtw== dependencies: micromatch "^4.0.4" -cspell-io@^5.8.2: - version "5.8.2" - resolved "https://registry.yarnpkg.com/cspell-io/-/cspell-io-5.8.2.tgz#66c43830dd28822397a357d9bfa65e2f77c71c26" - integrity sha512-5ejb38VchMml840gigYO5oanOcef681pLstqwQt71yV+CG4YSyJK7RqPTeDHgsXbRkntdUrbydwza0481szVkQ== +cspell-io@^5.9.0: + version "5.9.0" + resolved "https://registry.yarnpkg.com/cspell-io/-/cspell-io-5.9.0.tgz#f74867e43823965ddd3018920b1dddf71fe27d60" + integrity sha512-T+JO9RZrgW9StS6pg2yVQfNpR503lCzPCLM/24lBykPChaXOk2VTGiBa5TPu7qKRxP9x9p7zHLiawlTkgfIjzQ== dependencies: iconv-lite "^0.6.3" iterable-to-stream "^2.0.0" -cspell-lib@^5.8.2: - version "5.8.2" - resolved "https://registry.yarnpkg.com/cspell-lib/-/cspell-lib-5.8.2.tgz#3a91fa2fe3b2c1607d003dbcce0f2ca41c7d613c" - integrity sha512-Z6W+oHnmmUstdEypwMiqlnLOaA68r1T3i5OE2t+t2sxLAUgqCiTFEUQzu/yv/7vAIRKawdHuAq1rqrNKZXulbQ== +cspell-lib@^5.9.0: + version "5.9.0" + resolved "https://registry.yarnpkg.com/cspell-lib/-/cspell-lib-5.9.0.tgz#2efec17a98ac4b7e2da294fac747f236a820a125" + integrity sha512-86SsD7lOAu9ia5j2o7tBUIUrTrAjwEjMgP96+bE8NdSCArjvnY7FiTkes7AHGZ9g3KhluMEaDKhzJhK0TaZenQ== dependencies: - "@cspell/cspell-bundled-dicts" "^5.8.2" - "@cspell/cspell-types" "^5.8.2" + "@cspell/cspell-bundled-dicts" "^5.9.0" + "@cspell/cspell-types" "^5.9.0" clear-module "^4.1.1" comment-json "^4.1.1" configstore "^5.0.1" cosmiconfig "^7.0.1" - cspell-glob "^5.8.2" - cspell-io "^5.8.2" - cspell-trie-lib "^5.8.2" + cspell-glob "^5.9.0" + cspell-io "^5.9.0" + cspell-trie-lib "^5.9.0" find-up "^5.0.0" fs-extra "^10.0.0" gensequence "^3.1.1" @@ -3574,24 +3574,24 @@ cspell-lib@^5.8.2: resolve-global "^1.0.0" vscode-uri "^3.0.2" -cspell-trie-lib@^5.8.2: - version "5.8.2" - resolved "https://registry.yarnpkg.com/cspell-trie-lib/-/cspell-trie-lib-5.8.2.tgz#266a58c21c3ead1eb8434accca6cca7d7abd183d" - integrity sha512-gvNwZO8QIqMTek2ZK/CeYYupzdXnIym7ytOgy7ycE/UIeNzJh/STC62Pe44CNvL86Xh1wgS4wFnh0pF6QRkZFw== +cspell-trie-lib@^5.9.0: + version "5.9.0" + resolved "https://registry.yarnpkg.com/cspell-trie-lib/-/cspell-trie-lib-5.9.0.tgz#ca857a7468fa443bf6a9de4143849e770ca70a48" + integrity sha512-/m0kgxYuLyxeZGjajVC/oxrbi2zpv+1boKSjHBElPrE8MytDgdBgdCojsYAYNAl30QEF4GtxB+q0NlWV4laLdA== dependencies: fs-extra "^10.0.0" gensequence "^3.1.1" cspell@^5.5.2: - version "5.8.2" - resolved "https://registry.yarnpkg.com/cspell/-/cspell-5.8.2.tgz#708067660270f3900816d99c6b055dafa8ebd6d0" - integrity sha512-yamhOvEDXq/f0ko1icR3FUH/pfbGnz5LqtnkDKskVhm5tzv2kUxUNbmYwBAYzs7N1igE+AokL1G7D/Rw9LCLBg== + version "5.9.0" + resolved "https://registry.yarnpkg.com/cspell/-/cspell-5.9.0.tgz#2db3c85a9b0bf68bb4d49b0f72e35325a68170c3" + integrity sha512-TrPg5fmdd09S+alS8HjRvYPFBd8Qoxb8XxWGrH3JDsQGA7m6EljGcNjR6Mh19mMP5cQVOv7XmwEMy/EqwaHWTA== dependencies: chalk "^4.1.2" commander "^8.1.0" comment-json "^4.1.1" - cspell-glob "^5.8.2" - cspell-lib "^5.8.2" + cspell-glob "^5.9.0" + cspell-lib "^5.9.0" fs-extra "^10.0.0" get-stdin "^8.0.0" glob "^7.1.7" From f79ae9b58e82f4fddef640a34a1d7ff92b763e65 Mon Sep 17 00:00:00 2001 From: Yasar Siddiqui Date: Fri, 3 Sep 2021 22:59:38 +0530 Subject: [PATCH 08/19] feat(eslint-plugin): add extension rule `padding-line-between-statements` (#3418) --- .../src/unions/LeftHandSideExpression.ts | 2 + packages/eslint-plugin/README.md | 75 +- .../rules/padding-line-between-statements.md | 48 + packages/eslint-plugin/src/configs/all.ts | 2 + packages/eslint-plugin/src/rules/index.ts | 2 + .../rules/padding-line-between-statements.ts | 775 +++ .../padding-line-between-statements.test.ts | 5060 +++++++++++++++++ 7 files changed, 5927 insertions(+), 37 deletions(-) create mode 100644 packages/eslint-plugin/docs/rules/padding-line-between-statements.md create mode 100644 packages/eslint-plugin/src/rules/padding-line-between-statements.ts create mode 100644 packages/eslint-plugin/tests/rules/padding-line-between-statements.test.ts diff --git a/packages/ast-spec/src/unions/LeftHandSideExpression.ts b/packages/ast-spec/src/unions/LeftHandSideExpression.ts index 5d6922ed42d..fc3a80b2361 100644 --- a/packages/ast-spec/src/unions/LeftHandSideExpression.ts +++ b/packages/ast-spec/src/unions/LeftHandSideExpression.ts @@ -9,6 +9,7 @@ import type { JSXFragment } from '../expression/JSXFragment/spec'; import type { MemberExpression } from '../expression/MemberExpression/spec'; import type { MetaProperty } from '../expression/MetaProperty/spec'; import type { ObjectExpression } from '../expression/ObjectExpression/spec'; +import type { SequenceExpression } from '../expression/spec'; import type { Super } from '../expression/Super/spec'; import type { TaggedTemplateExpression } from '../expression/TaggedTemplateExpression/spec'; import type { ThisExpression } from '../expression/ThisExpression/spec'; @@ -34,6 +35,7 @@ export type LeftHandSideExpression = | MetaProperty | ObjectExpression | ObjectPattern + | SequenceExpression | Super | TaggedTemplateExpression | ThisExpression diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index 6f890d27256..a60d885093f 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -190,43 +190,44 @@ In these cases, we create what we call an extension rule; a rule within our plug **Key**: :white_check_mark: = recommended, :wrench: = fixable, :thought_balloon: = requires type information -| Name | Description | :white_check_mark: | :wrench: | :thought_balloon: | -| ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | ------------------ | -------- | ----------------- | -| [`@typescript-eslint/brace-style`](./docs/rules/brace-style.md) | Enforce consistent brace style for blocks | | :wrench: | | -| [`@typescript-eslint/comma-dangle`](./docs/rules/comma-dangle.md) | Require or disallow trailing comma | | :wrench: | | -| [`@typescript-eslint/comma-spacing`](./docs/rules/comma-spacing.md) | Enforces consistent spacing before and after commas | | :wrench: | | -| [`@typescript-eslint/default-param-last`](./docs/rules/default-param-last.md) | Enforce default parameters to be last | | | | -| [`@typescript-eslint/dot-notation`](./docs/rules/dot-notation.md) | enforce dot notation whenever possible | | :wrench: | :thought_balloon: | -| [`@typescript-eslint/func-call-spacing`](./docs/rules/func-call-spacing.md) | Require or disallow spacing between function identifiers and their invocations | | :wrench: | | -| [`@typescript-eslint/indent`](./docs/rules/indent.md) | Enforce consistent indentation | | :wrench: | | -| [`@typescript-eslint/init-declarations`](./docs/rules/init-declarations.md) | require or disallow initialization in variable declarations | | | | -| [`@typescript-eslint/keyword-spacing`](./docs/rules/keyword-spacing.md) | Enforce consistent spacing before and after keywords | | :wrench: | | -| [`@typescript-eslint/lines-between-class-members`](./docs/rules/lines-between-class-members.md) | Require or disallow an empty line between class members | | :wrench: | | -| [`@typescript-eslint/no-array-constructor`](./docs/rules/no-array-constructor.md) | Disallow generic `Array` constructors | :white_check_mark: | :wrench: | | -| [`@typescript-eslint/no-dupe-class-members`](./docs/rules/no-dupe-class-members.md) | Disallow duplicate class members | | | | -| [`@typescript-eslint/no-duplicate-imports`](./docs/rules/no-duplicate-imports.md) | Disallow duplicate imports | | | | -| [`@typescript-eslint/no-empty-function`](./docs/rules/no-empty-function.md) | Disallow empty functions | :white_check_mark: | | | -| [`@typescript-eslint/no-extra-parens`](./docs/rules/no-extra-parens.md) | Disallow unnecessary parentheses | | :wrench: | | -| [`@typescript-eslint/no-extra-semi`](./docs/rules/no-extra-semi.md) | Disallow unnecessary semicolons | :white_check_mark: | :wrench: | | -| [`@typescript-eslint/no-implied-eval`](./docs/rules/no-implied-eval.md) | Disallow the use of `eval()`-like methods | :white_check_mark: | | :thought_balloon: | -| [`@typescript-eslint/no-invalid-this`](./docs/rules/no-invalid-this.md) | Disallow `this` keywords outside of classes or class-like objects | | | | -| [`@typescript-eslint/no-loop-func`](./docs/rules/no-loop-func.md) | Disallow function declarations that contain unsafe references inside loop statements | | | | -| [`@typescript-eslint/no-loss-of-precision`](./docs/rules/no-loss-of-precision.md) | Disallow literal numbers that lose precision | | | | -| [`@typescript-eslint/no-magic-numbers`](./docs/rules/no-magic-numbers.md) | Disallow magic numbers | | | | -| [`@typescript-eslint/no-redeclare`](./docs/rules/no-redeclare.md) | Disallow variable redeclaration | | | | -| [`@typescript-eslint/no-shadow`](./docs/rules/no-shadow.md) | Disallow variable declarations from shadowing variables declared in the outer scope | | | | -| [`@typescript-eslint/no-throw-literal`](./docs/rules/no-throw-literal.md) | Disallow throwing literals as exceptions | | | :thought_balloon: | -| [`@typescript-eslint/no-unused-expressions`](./docs/rules/no-unused-expressions.md) | Disallow unused expressions | | | | -| [`@typescript-eslint/no-unused-vars`](./docs/rules/no-unused-vars.md) | Disallow unused variables | :white_check_mark: | | | -| [`@typescript-eslint/no-use-before-define`](./docs/rules/no-use-before-define.md) | Disallow the use of variables before they are defined | | | | -| [`@typescript-eslint/no-useless-constructor`](./docs/rules/no-useless-constructor.md) | Disallow unnecessary constructors | | | | -| [`@typescript-eslint/object-curly-spacing`](./docs/rules/object-curly-spacing.md) | Enforce consistent spacing inside braces | | :wrench: | | -| [`@typescript-eslint/quotes`](./docs/rules/quotes.md) | Enforce the consistent use of either backticks, double, or single quotes | | :wrench: | | -| [`@typescript-eslint/require-await`](./docs/rules/require-await.md) | Disallow async functions which have no `await` expression | :white_check_mark: | | :thought_balloon: | -| [`@typescript-eslint/return-await`](./docs/rules/return-await.md) | Enforces consistent returning of awaited values | | :wrench: | :thought_balloon: | -| [`@typescript-eslint/semi`](./docs/rules/semi.md) | Require or disallow semicolons instead of ASI | | :wrench: | | -| [`@typescript-eslint/space-before-function-paren`](./docs/rules/space-before-function-paren.md) | Enforces consistent spacing before function parenthesis | | :wrench: | | -| [`@typescript-eslint/space-infix-ops`](./docs/rules/space-infix-ops.md) | This rule is aimed at ensuring there are spaces around infix operators. | | :wrench: | | +| Name | Description | :white_check_mark: | :wrench: | :thought_balloon: | +| ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | ------------------ | -------- | ----------------- | +| [`@typescript-eslint/brace-style`](./docs/rules/brace-style.md) | Enforce consistent brace style for blocks | | :wrench: | | +| [`@typescript-eslint/comma-dangle`](./docs/rules/comma-dangle.md) | Require or disallow trailing comma | | :wrench: | | +| [`@typescript-eslint/comma-spacing`](./docs/rules/comma-spacing.md) | Enforces consistent spacing before and after commas | | :wrench: | | +| [`@typescript-eslint/default-param-last`](./docs/rules/default-param-last.md) | Enforce default parameters to be last | | | | +| [`@typescript-eslint/dot-notation`](./docs/rules/dot-notation.md) | enforce dot notation whenever possible | | :wrench: | :thought_balloon: | +| [`@typescript-eslint/func-call-spacing`](./docs/rules/func-call-spacing.md) | Require or disallow spacing between function identifiers and their invocations | | :wrench: | | +| [`@typescript-eslint/indent`](./docs/rules/indent.md) | Enforce consistent indentation | | :wrench: | | +| [`@typescript-eslint/init-declarations`](./docs/rules/init-declarations.md) | require or disallow initialization in variable declarations | | | | +| [`@typescript-eslint/keyword-spacing`](./docs/rules/keyword-spacing.md) | Enforce consistent spacing before and after keywords | | :wrench: | | +| [`@typescript-eslint/lines-between-class-members`](./docs/rules/lines-between-class-members.md) | Require or disallow an empty line between class members | | :wrench: | | +| [`@typescript-eslint/no-array-constructor`](./docs/rules/no-array-constructor.md) | Disallow generic `Array` constructors | :white_check_mark: | :wrench: | | +| [`@typescript-eslint/no-dupe-class-members`](./docs/rules/no-dupe-class-members.md) | Disallow duplicate class members | | | | +| [`@typescript-eslint/no-duplicate-imports`](./docs/rules/no-duplicate-imports.md) | Disallow duplicate imports | | | | +| [`@typescript-eslint/no-empty-function`](./docs/rules/no-empty-function.md) | Disallow empty functions | :white_check_mark: | | | +| [`@typescript-eslint/no-extra-parens`](./docs/rules/no-extra-parens.md) | Disallow unnecessary parentheses | | :wrench: | | +| [`@typescript-eslint/no-extra-semi`](./docs/rules/no-extra-semi.md) | Disallow unnecessary semicolons | :white_check_mark: | :wrench: | | +| [`@typescript-eslint/no-implied-eval`](./docs/rules/no-implied-eval.md) | Disallow the use of `eval()`-like methods | :white_check_mark: | | :thought_balloon: | +| [`@typescript-eslint/no-invalid-this`](./docs/rules/no-invalid-this.md) | Disallow `this` keywords outside of classes or class-like objects | | | | +| [`@typescript-eslint/no-loop-func`](./docs/rules/no-loop-func.md) | Disallow function declarations that contain unsafe references inside loop statements | | | | +| [`@typescript-eslint/no-loss-of-precision`](./docs/rules/no-loss-of-precision.md) | Disallow literal numbers that lose precision | | | | +| [`@typescript-eslint/no-magic-numbers`](./docs/rules/no-magic-numbers.md) | Disallow magic numbers | | | | +| [`@typescript-eslint/no-redeclare`](./docs/rules/no-redeclare.md) | Disallow variable redeclaration | | | | +| [`@typescript-eslint/no-shadow`](./docs/rules/no-shadow.md) | Disallow variable declarations from shadowing variables declared in the outer scope | | | | +| [`@typescript-eslint/no-throw-literal`](./docs/rules/no-throw-literal.md) | Disallow throwing literals as exceptions | | | :thought_balloon: | +| [`@typescript-eslint/no-unused-expressions`](./docs/rules/no-unused-expressions.md) | Disallow unused expressions | | | | +| [`@typescript-eslint/no-unused-vars`](./docs/rules/no-unused-vars.md) | Disallow unused variables | :white_check_mark: | | | +| [`@typescript-eslint/no-use-before-define`](./docs/rules/no-use-before-define.md) | Disallow the use of variables before they are defined | | | | +| [`@typescript-eslint/no-useless-constructor`](./docs/rules/no-useless-constructor.md) | Disallow unnecessary constructors | | | | +| [`@typescript-eslint/object-curly-spacing`](./docs/rules/object-curly-spacing.md) | Enforce consistent spacing inside braces | | :wrench: | | +| [`@typescript-eslint/padding-line-between-statements`](./docs/rules/padding-line-between-statements.md) | require or disallow padding lines between statements | | :wrench: | | +| [`@typescript-eslint/quotes`](./docs/rules/quotes.md) | Enforce the consistent use of either backticks, double, or single quotes | | :wrench: | | +| [`@typescript-eslint/require-await`](./docs/rules/require-await.md) | Disallow async functions which have no `await` expression | :white_check_mark: | | :thought_balloon: | +| [`@typescript-eslint/return-await`](./docs/rules/return-await.md) | Enforces consistent returning of awaited values | | :wrench: | :thought_balloon: | +| [`@typescript-eslint/semi`](./docs/rules/semi.md) | Require or disallow semicolons instead of ASI | | :wrench: | | +| [`@typescript-eslint/space-before-function-paren`](./docs/rules/space-before-function-paren.md) | Enforces consistent spacing before function parenthesis | | :wrench: | | +| [`@typescript-eslint/space-infix-ops`](./docs/rules/space-infix-ops.md) | This rule is aimed at ensuring there are spaces around infix operators. | | :wrench: | | diff --git a/packages/eslint-plugin/docs/rules/padding-line-between-statements.md b/packages/eslint-plugin/docs/rules/padding-line-between-statements.md new file mode 100644 index 00000000000..b23ce702b78 --- /dev/null +++ b/packages/eslint-plugin/docs/rules/padding-line-between-statements.md @@ -0,0 +1,48 @@ +# require or disallow padding lines between statements (`padding-line-between-statements`) + +## Rule Details + +This rule extends the base [`eslint/padding-line-between-statements`](https://eslint.org/docs/rules/padding-line-between-statements) rule. + +**It adds support for TypeScript constructs such as `interface` and `type`.** + +## How to use + +```jsonc +{ + // note you must disable the base rule as it can report incorrect errors + "padding-line-between-statements": "off", + "@typescript-eslint/padding-line-between-statements": [ + "error", + { + "blankLine": "always", + "prev": "var", + "next": "return" + } + ] +} +``` + +```jsonc +{ + // Example - Add blank lines before interface and type definitions. + // note you must disable the base rule as it can report incorrect errors + "padding-line-between-statements": "off", + "@typescript-eslint/padding-line-between-statements": [ + "error", + { + "blankLine": "always", + "prev": "*", + "next": ["interface", "type"] + } + ] +} +``` + +## Options + +See [`eslint/padding-line-between-statements` options](https://eslint.org/docs/rules/padding-line-between-statements#options). + +**Note** - In addition to options provided by ESLint, we have also added options for `interface` and `type`. + +Taken with ❤️ [from ESLint core](https://github.com/eslint/eslint/blob/master/docs/rules/padding-line-between-statements.md) diff --git a/packages/eslint-plugin/src/configs/all.ts b/packages/eslint-plugin/src/configs/all.ts index 66209b80623..4d94a83fa59 100644 --- a/packages/eslint-plugin/src/configs/all.ts +++ b/packages/eslint-plugin/src/configs/all.ts @@ -116,6 +116,8 @@ export = { '@typescript-eslint/non-nullable-type-assertion-style': 'error', 'object-curly-spacing': 'off', '@typescript-eslint/object-curly-spacing': 'error', + 'padding-line-between-statements': 'off', + '@typescript-eslint/padding-line-between-statements': 'error', '@typescript-eslint/prefer-as-const': 'error', '@typescript-eslint/prefer-enum-initializers': 'error', '@typescript-eslint/prefer-for-of': 'error', diff --git a/packages/eslint-plugin/src/rules/index.ts b/packages/eslint-plugin/src/rules/index.ts index 1b6fa0f6ea1..54dd9c24ac3 100644 --- a/packages/eslint-plugin/src/rules/index.ts +++ b/packages/eslint-plugin/src/rules/index.ts @@ -81,6 +81,7 @@ import noUselessConstructor from './no-useless-constructor'; import noVarRequires from './no-var-requires'; import nonNullableTypeAssertionStyle from './non-nullable-type-assertion-style'; import objectCurlySpacing from './object-curly-spacing'; +import paddingLineBetweenStatements from './padding-line-between-statements'; import preferAsConst from './prefer-as-const'; import preferEnumInitializers from './prefer-enum-initializers'; import preferForOf from './prefer-for-of'; @@ -200,6 +201,7 @@ export default { 'no-var-requires': noVarRequires, 'non-nullable-type-assertion-style': nonNullableTypeAssertionStyle, 'object-curly-spacing': objectCurlySpacing, + 'padding-line-between-statements': paddingLineBetweenStatements, 'prefer-as-const': preferAsConst, 'prefer-enum-initializers': preferEnumInitializers, 'prefer-for-of': preferForOf, diff --git a/packages/eslint-plugin/src/rules/padding-line-between-statements.ts b/packages/eslint-plugin/src/rules/padding-line-between-statements.ts new file mode 100644 index 00000000000..f686476e5de --- /dev/null +++ b/packages/eslint-plugin/src/rules/padding-line-between-statements.ts @@ -0,0 +1,775 @@ +import { + AST_NODE_TYPES, + TSESLint, + TSESTree, +} from '@typescript-eslint/experimental-utils'; +import * as util from '../util'; + +/** + * This rule is a replica of padding-line-between-statements. + * + * Ideally we would want to extend the rule support typescript specific support. + * But since not all the state is exposed by the eslint and eslint has frozen stylistic rules, + * (see - https://eslint.org/blog/2020/05/changes-to-rules-policies for details.) + * we are forced to re-implement the rule here. + * + * We have tried to keep the implementation as close as possible to the eslint implementation, to make + * patching easier for future contributors. + * + * Reference rule - https://github.com/eslint/eslint/blob/master/lib/rules/padding-line-between-statements.js + */ + +type NodeTest = ( + node: TSESTree.Node, + sourceCode: TSESLint.SourceCode, +) => boolean; + +interface NodeTestObject { + test: NodeTest; +} + +interface PaddingOption { + blankLine: keyof typeof PaddingTypes; + prev: string | string[]; + next: string | string[]; +} + +type MessageIds = 'expectedBlankLine' | 'unexpectedBlankLine'; +type Options = PaddingOption[]; + +const LT = `[${Array.from( + new Set(['\r\n', '\r', '\n', '\u2028', '\u2029']), +).join('')}]`; +const PADDING_LINE_SEQUENCE = new RegExp( + String.raw`^(\s*?${LT})\s*${LT}(\s*;?)$`, + 'u', +); + +/** + * Creates tester which check if a node starts with specific keyword. + * @param keyword The keyword to test. + * @returns the created tester. + * @private + */ +function newKeywordTester(keyword: string): NodeTestObject { + return { + test(node, sourceCode): boolean { + return sourceCode.getFirstToken(node)?.value === keyword; + }, + }; +} + +/** + * Creates tester which check if a node starts with specific keyword and spans a single line. + * @param keyword The keyword to test. + * @returns the created tester. + * @private + */ +function newSinglelineKeywordTester(keyword: string): NodeTestObject { + return { + test(node, sourceCode): boolean { + return ( + node.loc.start.line === node.loc.end.line && + sourceCode.getFirstToken(node)!.value === keyword + ); + }, + }; +} + +/** + * Creates tester which check if a node starts with specific keyword and spans multiple lines. + * @param keyword The keyword to test. + * @returns the created tester. + * @private + */ +function newMultilineKeywordTester(keyword: string): NodeTestObject { + return { + test(node, sourceCode): boolean { + return ( + node.loc.start.line !== node.loc.end.line && + sourceCode.getFirstToken(node)!.value === keyword + ); + }, + }; +} + +/** + * Creates tester which check if a node is specific type. + * @param type The node type to test. + * @returns the created tester. + * @private + */ +function newNodeTypeTester(type: AST_NODE_TYPES): NodeTestObject { + return { + test: (node): boolean => node.type === type, + }; +} + +/** + * Skips a chain expression node + * @paramnode The node to test + * @returnsA non-chain expression + * @private + */ +function skipChainExpression(node: TSESTree.Node): TSESTree.Node { + return node && node.type === AST_NODE_TYPES.ChainExpression + ? node.expression + : node; +} + +/** + * Checks the given node is an expression statement of IIFE. + * @paramnode The node to check. + * @returns `true` if the node is an expression statement of IIFE. + * @private + */ +function isIIFEStatement(node: TSESTree.Node): boolean { + if (node.type === AST_NODE_TYPES.ExpressionStatement) { + let expression = skipChainExpression(node.expression); + if (expression.type === AST_NODE_TYPES.UnaryExpression) { + expression = skipChainExpression(expression.argument); + } + if (expression.type === AST_NODE_TYPES.CallExpression) { + let node: TSESTree.Node = expression.callee; + while (node.type === AST_NODE_TYPES.SequenceExpression) { + node = node.expressions[node.expressions.length - 1]; + } + return util.isFunction(node); + } + } + return false; +} + +/** + * Checks the given node is a CommonJS require statement + * @paramnode The node to check. + * @returns `true` if the node is a CommonJS require statement. + * @private + */ +function isCJSRequire(node: TSESTree.Node): boolean { + if (node.type === AST_NODE_TYPES.VariableDeclaration) { + const declaration = node.declarations[0]; + if (declaration?.init) { + let call = declaration?.init; + while (call.type === AST_NODE_TYPES.MemberExpression) { + call = call.object; + } + if ( + call.type === AST_NODE_TYPES.CallExpression && + call.callee.type === AST_NODE_TYPES.Identifier + ) { + return call.callee.name === 'require'; + } + } + } + return false; +} + +/** + * Checks whether the given node is a block-like statement. + * This checks the last token of the node is the closing brace of a block. + * @param sourceCode The source code to get tokens. + * @paramnode The node to check. + * @returns `true` if the node is a block-like statement. + * @private + */ +function isBlockLikeStatement( + node: TSESTree.Node, + sourceCode: TSESLint.SourceCode, +): boolean { + // do-while with a block is a block-like statement. + if ( + node.type === AST_NODE_TYPES.DoWhileStatement && + node.body.type === AST_NODE_TYPES.BlockStatement + ) { + return true; + } + + /** + * IIFE is a block-like statement specially from + * JSCS#disallowPaddingNewLinesAfterBlocks. + */ + if (isIIFEStatement(node)) { + return true; + } + + // Checks the last token is a closing brace of blocks. + const lastToken = sourceCode.getLastToken(node, util.isNotSemicolonToken); + const belongingNode = + lastToken && util.isClosingBraceToken(lastToken) + ? sourceCode.getNodeByRangeIndex(lastToken.range[0]) + : null; + + return ( + !!belongingNode && + (belongingNode.type === AST_NODE_TYPES.BlockStatement || + belongingNode.type === AST_NODE_TYPES.SwitchStatement) + ); +} + +/** + * Check whether the given node is a directive or not. + * @paramnode The node to check. + * @param sourceCode The source code object to get tokens. + * @returns `true` if the node is a directive. + */ +function isDirective( + node: TSESTree.Node, + sourceCode: TSESLint.SourceCode, +): boolean { + return ( + node.type === AST_NODE_TYPES.ExpressionStatement && + (node.parent?.type === AST_NODE_TYPES.Program || + (node.parent?.type === AST_NODE_TYPES.BlockStatement && + util.isFunction(node.parent.parent))) && + node.expression.type === AST_NODE_TYPES.Literal && + typeof node.expression.value === 'string' && + !util.isParenthesized(node.expression, sourceCode) + ); +} + +/** + * Check whether the given node is a part of directive prologue or not. + * @paramnode The node to check. + * @param sourceCode The source code object to get tokens. + * @returns `true` if the node is a part of directive prologue. + */ +function isDirectivePrologue( + node: TSESTree.Node, + sourceCode: TSESLint.SourceCode, +): boolean { + if ( + isDirective(node, sourceCode) && + node.parent && + 'body' in node.parent && + Array.isArray(node.parent.body) + ) { + for (const sibling of node.parent.body) { + if (sibling === node) { + break; + } + if (!isDirective(sibling, sourceCode)) { + return false; + } + } + return true; + } + return false; +} + +/** + * Checks the given node is a CommonJS export statement + * @paramnode The node to check. + * @returns `true` if the node is a CommonJS export statement. + * @private + */ +function isCJSExport(node: TSESTree.Node): boolean { + if (node.type === AST_NODE_TYPES.ExpressionStatement) { + const expression = node.expression; + if (expression.type === AST_NODE_TYPES.AssignmentExpression) { + let left = expression.left; + if (left.type === AST_NODE_TYPES.MemberExpression) { + while (left.object.type === AST_NODE_TYPES.MemberExpression) { + left = left.object; + } + return ( + left.object.type === AST_NODE_TYPES.Identifier && + (left.object.name === 'exports' || + (left.object.name === 'module' && + left.property.type === AST_NODE_TYPES.Identifier && + left.property.name === 'exports')) + ); + } + } + } + return false; +} + +/** + * Check whether the given node is an expression + * @paramnode The node to check. + * @param sourceCode The source code object to get tokens. + * @returns `true` if the node is an expression + */ +function isExpression( + node: TSESTree.Node, + sourceCode: TSESLint.SourceCode, +): boolean { + return ( + node.type === AST_NODE_TYPES.ExpressionStatement && + !isDirectivePrologue(node, sourceCode) + ); +} + +/** + * Gets the actual last token. + * + * If a semicolon is semicolon-less style's semicolon, this ignores it. + * For example: + * + * foo() + * ;[1, 2, 3].forEach(bar) + * @param sourceCode The source code to get tokens. + * @paramnode The node to get. + * @returns The actual last token. + * @private + */ +function getActualLastToken( + node: TSESTree.Node, + sourceCode: TSESLint.SourceCode, +): TSESTree.Token | null { + const semiToken = sourceCode.getLastToken(node)!; + const prevToken = sourceCode.getTokenBefore(semiToken); + const nextToken = sourceCode.getTokenAfter(semiToken); + const isSemicolonLessStyle = + prevToken && + nextToken && + prevToken.range[0] >= node.range[0] && + util.isSemicolonToken(semiToken) && + semiToken.loc.start.line !== prevToken.loc.end.line && + semiToken.loc.end.line === nextToken.loc.start.line; + + return isSemicolonLessStyle ? prevToken : semiToken; +} + +/** + * This returns the concatenation of the first 2 captured strings. + * @param _ Unused. Whole matched string. + * @param trailingSpaces The trailing spaces of the first line. + * @param indentSpaces The indentation spaces of the last line. + * @returns The concatenation of trailingSpaces and indentSpaces. + * @private + */ +function replacerToRemovePaddingLines( + _: string, + trailingSpaces: string, + indentSpaces: string, +): string { + return trailingSpaces + indentSpaces; +} + +/** + * Check and report statements for `any` configuration. + * It does nothing. + * + * @private + */ +function verifyForAny(): void { + // Empty +} + +/** + * Check and report statements for `never` configuration. + * This autofix removes blank lines between the given 2 statements. + * However, if comments exist between 2 blank lines, it does not remove those + * blank lines automatically. + * @param context The rule context to report. + * @param_ Unused. The previous node to check. + * @paramnextNode The next node to check. + * @param paddingLines The array of token pairs that blank + * lines exist between the pair. + * + * @private + */ +function verifyForNever( + context: TSESLint.RuleContext, + _: TSESTree.Node, + nextNode: TSESTree.Node, + paddingLines: [TSESTree.Token, TSESTree.Token][], +): void { + if (paddingLines.length === 0) { + return; + } + + context.report({ + node: nextNode, + messageId: 'unexpectedBlankLine', + fix(fixer) { + if (paddingLines.length >= 2) { + return null; + } + + const prevToken = paddingLines[0][0]; + const nextToken = paddingLines[0][1]; + const start = prevToken.range[1]; + const end = nextToken.range[0]; + const text = context + .getSourceCode() + .text.slice(start, end) + .replace(PADDING_LINE_SEQUENCE, replacerToRemovePaddingLines); + + return fixer.replaceTextRange([start, end], text); + }, + }); +} + +/** + * Check and report statements for `always` configuration. + * This autofix inserts a blank line between the given 2 statements. + * If the `prevNode` has trailing comments, it inserts a blank line after the + * trailing comments. + * @param context The rule context to report. + * @paramprevNode The previous node to check. + * @paramnextNode The next node to check. + * @param paddingLines The array of token pairs that blank + * lines exist between the pair. + * + * @private + */ +function verifyForAlways( + context: TSESLint.RuleContext, + prevNode: TSESTree.Node, + nextNode: TSESTree.Node, + paddingLines: [TSESTree.Token, TSESTree.Token][], +): void { + if (paddingLines.length > 0) { + return; + } + + context.report({ + node: nextNode, + messageId: 'expectedBlankLine', + fix(fixer) { + const sourceCode = context.getSourceCode(); + let prevToken = getActualLastToken( + prevNode, + sourceCode, + ) as TSESTree.Token; + const nextToken = + (sourceCode.getFirstTokenBetween(prevToken, nextNode, { + includeComments: true, + + /** + * Skip the trailing comments of the previous node. + * This inserts a blank line after the last trailing comment. + * + * For example: + * + * foo(); // trailing comment. + * // comment. + * bar(); + * + * Get fixed to: + * + * foo(); // trailing comment. + * + * // comment. + * bar(); + * @param token The token to check. + * @returns `true` if the token is not a trailing comment. + * @private + */ + filter(token) { + if (util.isTokenOnSameLine(prevToken, token)) { + prevToken = token; + return false; + } + return true; + }, + }) as TSESTree.Token) || nextNode; + const insertText = util.isTokenOnSameLine(prevToken, nextToken) + ? '\n\n' + : '\n'; + + return fixer.insertTextAfter(prevToken, insertText); + }, + }); +} + +/** + * Types of blank lines. + * `any`, `never`, and `always` are defined. + * Those have `verify` method to check and report statements. + * @private + */ +const PaddingTypes = { + any: { verify: verifyForAny }, + never: { verify: verifyForNever }, + always: { verify: verifyForAlways }, +}; + +/** + * Types of statements. + * Those have `test` method to check it matches to the given statement. + * @private + */ +const StatementTypes: Record = { + '*': { test: (): boolean => true }, + 'block-like': { test: isBlockLikeStatement }, + exports: { test: isCJSExport }, + require: { test: isCJSRequire }, + directive: { test: isDirectivePrologue }, + expression: { test: isExpression }, + iife: { test: isIIFEStatement }, + + 'multiline-block-like': { + test: (node, sourceCode) => + node.loc.start.line !== node.loc.end.line && + isBlockLikeStatement(node, sourceCode), + }, + 'multiline-expression': { + test: (node, sourceCode) => + node.loc.start.line !== node.loc.end.line && + node.type === AST_NODE_TYPES.ExpressionStatement && + !isDirectivePrologue(node, sourceCode), + }, + + 'multiline-const': newMultilineKeywordTester('const'), + 'multiline-let': newMultilineKeywordTester('let'), + 'multiline-var': newMultilineKeywordTester('var'), + 'singleline-const': newSinglelineKeywordTester('const'), + 'singleline-let': newSinglelineKeywordTester('let'), + 'singleline-var': newSinglelineKeywordTester('var'), + + block: newNodeTypeTester(AST_NODE_TYPES.BlockStatement), + empty: newNodeTypeTester(AST_NODE_TYPES.EmptyStatement), + function: newNodeTypeTester(AST_NODE_TYPES.FunctionDeclaration), + + break: newKeywordTester('break'), + case: newKeywordTester('case'), + class: newKeywordTester('class'), + const: newKeywordTester('const'), + continue: newKeywordTester('continue'), + debugger: newKeywordTester('debugger'), + default: newKeywordTester('default'), + do: newKeywordTester('do'), + export: newKeywordTester('export'), + for: newKeywordTester('for'), + if: newKeywordTester('if'), + import: newKeywordTester('import'), + let: newKeywordTester('let'), + return: newKeywordTester('return'), + switch: newKeywordTester('switch'), + throw: newKeywordTester('throw'), + try: newKeywordTester('try'), + var: newKeywordTester('var'), + while: newKeywordTester('while'), + with: newKeywordTester('with'), + + // Additional Typescript constructs + interface: newKeywordTester('interface'), + type: newKeywordTester('type'), +}; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +export default util.createRule({ + name: 'padding-line-between-statements', + meta: { + type: 'layout', + docs: { + description: 'require or disallow padding lines between statements', + category: 'Stylistic Issues', + recommended: false, + extendsBaseRule: true, + }, + fixable: 'whitespace', + schema: { + definitions: { + paddingType: { + enum: Object.keys(PaddingTypes), + }, + statementType: { + anyOf: [ + { enum: Object.keys(StatementTypes) }, + { + type: 'array', + items: { enum: Object.keys(StatementTypes) }, + minItems: 1, + uniqueItems: true, + additionalItems: false, + }, + ], + }, + }, + type: 'array', + items: { + type: 'object', + properties: { + blankLine: { $ref: '#/definitions/paddingType' }, + prev: { $ref: '#/definitions/statementType' }, + next: { $ref: '#/definitions/statementType' }, + }, + additionalProperties: false, + required: ['blankLine', 'prev', 'next'], + }, + additionalItems: false, + }, + messages: { + unexpectedBlankLine: 'Unexpected blank line before this statement.', + expectedBlankLine: 'Expected blank line before this statement.', + }, + }, + defaultOptions: [], + create(context) { + const sourceCode = context.getSourceCode(); + const configureList = context.options || []; + + type Scope = null | { + upper: Scope; + prevNode: TSESTree.Node | null; + }; + + let scopeInfo: Scope = null; + + /** + * Processes to enter to new scope. + * This manages the current previous statement. + * + * @private + */ + function enterScope(): void { + scopeInfo = { + upper: scopeInfo, + prevNode: null, + }; + } + + /** + * Processes to exit from the current scope. + * + * @private + */ + function exitScope(): void { + if (scopeInfo) { + scopeInfo = scopeInfo.upper; + } + } + + /** + * Checks whether the given node matches the given type. + * @paramnode The statement node to check. + * @param type The statement type to check. + * @returns `true` if the statement node matched the type. + * @private + */ + function match(node: TSESTree.Node, type: string | string[]): boolean { + let innerStatementNode = node; + + while (innerStatementNode.type === AST_NODE_TYPES.LabeledStatement) { + innerStatementNode = innerStatementNode.body; + } + + if (Array.isArray(type)) { + return type.some(match.bind(null, innerStatementNode)); + } + + return StatementTypes[type].test(innerStatementNode, sourceCode); + } + + /** + * Finds the last matched configure from configureList. + * @paramprevNode The previous statement to match. + * @paramnextNode The current statement to match. + * @returns The tester of the last matched configure. + * @private + */ + function getPaddingType( + prevNode: TSESTree.Node, + nextNode: TSESTree.Node, + ): typeof PaddingTypes[keyof typeof PaddingTypes] { + for (let i = configureList.length - 1; i >= 0; --i) { + const configure = configureList[i]; + if ( + match(prevNode, configure.prev) && + match(nextNode, configure.next) + ) { + return PaddingTypes[configure.blankLine]; + } + } + return PaddingTypes.any; + } + + /** + * Gets padding line sequences between the given 2 statements. + * Comments are separators of the padding line sequences. + * @paramprevNode The previous statement to count. + * @paramnextNode The current statement to count. + * @returns The array of token pairs. + * @private + */ + function getPaddingLineSequences( + prevNode: TSESTree.Node, + nextNode: TSESTree.Node, + ): [TSESTree.Token, TSESTree.Token][] { + const pairs: [TSESTree.Token, TSESTree.Token][] = []; + let prevToken: TSESTree.Token = getActualLastToken(prevNode, sourceCode)!; + + if (nextNode.loc.start.line - prevToken.loc.end.line >= 2) { + do { + const token: TSESTree.Token = sourceCode.getTokenAfter(prevToken, { + includeComments: true, + })!; + + if (token.loc.start.line - prevToken.loc.end.line >= 2) { + pairs.push([prevToken, token]); + } + prevToken = token; + } while (prevToken.range[0] < nextNode.range[0]); + } + + return pairs; + } + + /** + * Verify padding lines between the given node and the previous node. + * @paramnode The node to verify. + * + * @private + */ + function verify(node: TSESTree.Node): void { + if ( + !node.parent || + ![ + AST_NODE_TYPES.SwitchStatement, + AST_NODE_TYPES.BlockStatement, + AST_NODE_TYPES.Program, + AST_NODE_TYPES.SwitchCase, + ].includes(node.parent.type) + ) { + return; + } + + // Save this node as the current previous statement. + const prevNode = scopeInfo!.prevNode; + + // Verify. + if (prevNode) { + const type = getPaddingType(prevNode, node); + const paddingLines = getPaddingLineSequences(prevNode, node); + + type.verify(context, prevNode, node, paddingLines); + } + + scopeInfo!.prevNode = node; + } + + /** + * Verify padding lines between the given node and the previous node. + * Then process to enter to new scope. + * @paramnode The node to verify. + * + * @private + */ + function verifyThenEnterScope(node: TSESTree.Node): void { + verify(node); + enterScope(); + } + + return { + Program: enterScope, + BlockStatement: enterScope, + SwitchStatement: enterScope, + 'Program:exit': exitScope, + 'BlockStatement:exit': exitScope, + 'SwitchStatement:exit': exitScope, + + ':statement': verify, + + SwitchCase: verifyThenEnterScope, + 'SwitchCase:exit': exitScope, + }; + }, +}); diff --git a/packages/eslint-plugin/tests/rules/padding-line-between-statements.test.ts b/packages/eslint-plugin/tests/rules/padding-line-between-statements.test.ts new file mode 100644 index 00000000000..d018f189929 --- /dev/null +++ b/packages/eslint-plugin/tests/rules/padding-line-between-statements.test.ts @@ -0,0 +1,5060 @@ +/* eslint-disable eslint-comments/no-use */ +// this rule tests new lines which prettier tries to fix, breaking the tests +/* eslint "@typescript-eslint/internal/plugin-test-formatting": ["error", { formatWithPrettier: false }] */ +/* eslint-enable eslint-comments/no-use */ + +import rule from '../../src/rules/padding-line-between-statements'; +import { RuleTester } from '../RuleTester'; + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +const ruleTester = new RuleTester({ + parser: '@typescript-eslint/parser', +}); + +ruleTester.run('padding-line-between-statements', rule, { + valid: [ + // do nothing if no options. + "'use strict'; foo(); if (a) { bar(); }", + + // do nothing for single statement. + { + code: 'foo()', + options: [{ blankLine: 'never', prev: '*', next: '*' }], + }, + { + code: 'foo()', + options: [{ blankLine: 'always', prev: '*', next: '*' }], + }, + + //---------------------------------------------------------------------- + // wildcard + //---------------------------------------------------------------------- + + { + code: 'foo();bar();', + options: [{ blankLine: 'never', prev: '*', next: '*' }], + }, + { + code: 'foo();\nbar();', + options: [{ blankLine: 'never', prev: '*', next: '*' }], + }, + { + code: 'foo();\n//comment\nbar();', + options: [{ blankLine: 'never', prev: '*', next: '*' }], + }, + { + code: 'foo();\n/*comment*/\nbar();', + options: [{ blankLine: 'never', prev: '*', next: '*' }], + }, + { + code: 'foo();\n\nbar();', + options: [{ blankLine: 'always', prev: '*', next: '*' }], + }, + { + code: 'foo();\n\n//comment\nbar();', + options: [{ blankLine: 'always', prev: '*', next: '*' }], + }, + { + code: 'foo();\n//comment\n\nbar();', + options: [{ blankLine: 'always', prev: '*', next: '*' }], + }, + { + code: 'foo();\n//comment\n\n//comment\nbar();', + options: [{ blankLine: 'always', prev: '*', next: '*' }], + }, + { + code: 'if(a){}\n\n;[].map(b)', + options: [ + { blankLine: 'always', prev: 'if', next: '*' }, + { blankLine: 'never', prev: 'empty', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // block-like + //---------------------------------------------------------------------- + + { + code: 'foo();\n\n{ foo() }\n\nfoo();', + options: [ + { blankLine: 'always', prev: '*', next: '*' }, + { blankLine: 'never', prev: 'block-like', next: 'block-like' }, + ], + }, + { + code: '{ foo() } { foo() }', + options: [ + { blankLine: 'always', prev: '*', next: '*' }, + { blankLine: 'never', prev: 'block-like', next: 'block-like' }, + ], + }, + { + code: '{ foo() }\n{ foo() }', + options: [ + { blankLine: 'always', prev: '*', next: '*' }, + { blankLine: 'never', prev: 'block-like', next: 'block-like' }, + ], + }, + { + code: '{ foo() }\n\n{ foo() }', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'block-like', next: 'block-like' }, + ], + }, + { + code: '{ foo() }\n\n//comment\n{ foo() }', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'block-like', next: 'block-like' }, + ], + }, + { + code: 'if(a);\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'block-like', next: '*' }, + ], + }, + { + code: 'do;while(a);\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'block-like', next: '*' }, + ], + }, + { + code: 'do{}while(a);\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'block-like', next: '*' }, + ], + }, + { + code: 'a={}\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'block-like', next: '*' }, + ], + }, + { + code: 'let a={}\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'block-like', next: '*' }, + ], + }, + { + code: 'foo(function(){})\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'block-like', next: '*' }, + ], + }, + { + code: '(function(){})()\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'block-like', next: '*' }, + ], + }, + { + code: '!function(){}()\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'block-like', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // exports + //---------------------------------------------------------------------- + + { + code: 'module.exports=1', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'exports', next: '*' }, + ], + }, + { + code: 'module.exports=1\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'exports', next: '*' }, + ], + }, + { + code: 'module.exports.foo=1\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'exports', next: '*' }, + ], + }, + { + code: 'exports.foo=1\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'exports', next: '*' }, + ], + }, + { + code: 'm.exports=1\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'exports', next: '*' }, + ], + }, + { + code: 'module.foo=1\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'exports', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // require + //---------------------------------------------------------------------- + + { + code: 'foo=require("foo")\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'require', next: '*' }, + ], + }, + { + code: 'const foo=a.require("foo")\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'require', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // directive + //---------------------------------------------------------------------- + + { + code: '"use strict"\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'directive', next: '*' }, + ], + }, + { + code: 'function foo(){"use strict"\n\nfoo()}', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'directive', next: '*' }, + ], + }, + { + code: '(function foo(){"use strict"\n\nfoo()})', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'directive', next: '*' }, + ], + }, + { + code: '(()=>{"use strict"\n\nfoo()})', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'directive', next: '*' }, + ], + }, + { + code: "'use strict'\n\nfoo()", + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'directive', next: '*' }, + ], + }, + { + code: 'foo("use strict")\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'directive', next: '*' }, + ], + }, + { + code: '`use strict`\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'directive', next: '*' }, + ], + }, + { + code: '("use strict")\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'directive', next: '*' }, + ], + }, + { + code: "'use '+'strict'\nfoo()", + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'directive', next: '*' }, + ], + }, + { + code: 'foo()\n"use strict"\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'directive', next: '*' }, + ], + }, + { + code: '{"use strict"\nfoo()}', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'directive', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // multiline-block-like + //---------------------------------------------------------------------- + + { + code: '{}\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'multiline-block-like', next: '*' }, + ], + }, + { + code: 'if(a){}\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'multiline-block-like', next: '*' }, + ], + }, + { + code: 'while(a){}\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'multiline-block-like', next: '*' }, + ], + }, + { + code: '{\n}\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'multiline-block-like', next: '*' }, + ], + }, + { + code: 'if(a){\n}\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'multiline-block-like', next: '*' }, + ], + }, + { + code: 'while(a){\n}\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'multiline-block-like', next: '*' }, + ], + }, + { + code: 'do{\n}while(a)\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'multiline-block-like', next: '*' }, + ], + }, + { + code: 'for(;;){\n}\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'multiline-block-like', next: '*' }, + ], + }, + { + code: 'for(a in b){\n}\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'multiline-block-like', next: '*' }, + ], + }, + { + code: 'for(a of b){\n}\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'multiline-block-like', next: '*' }, + ], + }, + { + code: 'switch(a){\n}\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'multiline-block-like', next: '*' }, + ], + }, + { + code: 'function foo(a){\n}\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'multiline-block-like', next: '*' }, + ], + }, + { + code: 'var a=function foo(a){\n}\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'multiline-block-like', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // block + //---------------------------------------------------------------------- + + { + code: '{}\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'block', next: '*' }, + ], + }, + { + code: '{\n}\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'block', next: '*' }, + ], + }, + { + code: '{\nfoo()\n}\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'block', next: '*' }, + ], + }, + { + code: 'if(a){}\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'block', next: '*' }, + ], + }, + { + code: 'a={}\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'block', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // empty + //---------------------------------------------------------------------- + + { + code: ';\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'empty', next: '*' }, + ], + }, + { + code: '1;\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'empty', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // expression + //---------------------------------------------------------------------- + + { + code: 'foo()\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'expression', next: '*' }, + ], + }, + { + code: 'a=b+c\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'expression', next: '*' }, + ], + }, + { + code: 'var a=1\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'expression', next: '*' }, + ], + }, + { + code: "'use strict'\nfoo()", + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'expression', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // multiline-expression + //---------------------------------------------------------------------- + + { + code: 'foo()\n\nfoo(\n\tx,\n\ty\n)', + options: [ + { blankLine: 'always', prev: '*', next: 'multiline-expression' }, + ], + }, + { + code: 'foo()\nfoo()', + options: [ + { blankLine: 'always', prev: '*', next: 'multiline-expression' }, + ], + }, + { + code: '() => {\n\tsomeArray.forEach(x => doSomething(x));\n\treturn theThing;\n}', + options: [ + { blankLine: 'always', prev: 'multiline-expression', next: 'return' }, + ], + }, + { + code: '() => {\n\tsomeArray.forEach(\n\t\tx => doSomething(x)\n\t);\n\n\treturn theThing;\n}', + options: [ + { blankLine: 'always', prev: 'multiline-expression', next: 'return' }, + ], + }, + + //---------------------------------------------------------------------- + // break + //---------------------------------------------------------------------- + + { + code: 'A:{break A\n\nfoo()}', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'break', next: '*' }, + ], + }, + { + code: 'while(a){break\n\nfoo()}', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'break', next: '*' }, + ], + }, + { + code: 'switch(a){case 0:break\n\nfoo()}', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'break', next: '*' }, + ], + }, + { + code: 'switch(a){case 0:break\ncase 1:break}', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'break', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // case + //---------------------------------------------------------------------- + + { + code: 'switch(a){case 0:\nfoo()\n\ncase 1:\nfoo()}', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'case', next: '*' }, + ], + }, + { + code: 'switch(a){case 0:\nfoo()\n\ndefault:\nfoo()}', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'case', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // class + //---------------------------------------------------------------------- + + { + code: 'class A{}\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'class', next: '*' }, + ], + }, + { + code: 'var A = class{}\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'class', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // const + //---------------------------------------------------------------------- + + { + code: 'const a=1\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'const', next: '*' }, + ], + }, + { + code: 'let a=1\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'const', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // type + //---------------------------------------------------------------------- + + { + code: 'type a=number\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'type', next: '*' }, + ], + }, + { + code: 'let a=number\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'type', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // interface + //---------------------------------------------------------------------- + + { + code: 'interface Test{\na:number;\n}\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'interface', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // continue + //---------------------------------------------------------------------- + + { + code: 'while(a){continue\n\nfoo()}', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'continue', next: '*' }, + ], + }, + { + code: 'while(a){break\nfoo()}', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'continue', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // debugger + //---------------------------------------------------------------------- + + { + code: 'debugger\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'debugger', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // default + //---------------------------------------------------------------------- + + { + code: 'switch(a){default:\nfoo()\n\ncase 0:\nfoo()\ncase 1:}', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'default', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // do + //---------------------------------------------------------------------- + + { + code: 'do;while(a)\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'do', next: '*' }, + ], + }, + { + code: 'while(a);\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'do', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // export + //---------------------------------------------------------------------- + + { + code: 'export default 1\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'export', next: '*' }, + ], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + }, + { + code: 'export let a=1\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'export', next: '*' }, + ], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + }, + { + code: 'var a = 0; export {a}\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'export', next: '*' }, + ], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + }, + { + code: 'exports.foo=1\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'export', next: '*' }, + ], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + }, + { + code: 'module.exports={}\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'export', next: '*' }, + ], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + }, + + //---------------------------------------------------------------------- + // for + //---------------------------------------------------------------------- + + { + code: 'for(;;);\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'for', next: '*' }, + ], + }, + { + code: 'for(a in b);\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'for', next: '*' }, + ], + }, + { + code: 'for(a of b);\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'for', next: '*' }, + ], + }, + { + code: 'while(a);\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'for', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // function + //---------------------------------------------------------------------- + + { + code: 'function foo(){}\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'function', next: '*' }, + ], + }, + { + code: 'var foo=function(){}\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'function', next: '*' }, + ], + }, + { + code: 'async function foo(){}\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'function', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // if + //---------------------------------------------------------------------- + + { + code: 'if(a);\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'if', next: '*' }, + ], + }, + { + code: 'if(a);else;\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'if', next: '*' }, + ], + }, + { + code: 'if(a);else if(b);else;\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'if', next: '*' }, + ], + }, + { + code: 'for(;;);\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'if', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // iife + //---------------------------------------------------------------------- + + { + code: '(function(){\n})()\n\nvar a = 2;', + options: [{ blankLine: 'always', prev: 'iife', next: '*' }], + }, + { + code: '+(function(){\n})()\n\nvar a = 2;', + options: [{ blankLine: 'always', prev: 'iife', next: '*' }], + }, + { + code: '(function(){\n})()\nvar a = 2;', + options: [{ blankLine: 'never', prev: 'iife', next: '*' }], + }, + { + code: '+(function(){\n})()\nvar a = 2;', + options: [{ blankLine: 'never', prev: 'iife', next: '*' }], + }, + { + code: '(1, 2, 3, function(){\n})()\n\nvar a = 2;', + options: [{ blankLine: 'always', prev: 'iife', next: '*' }], + }, + + //---------------------------------------------------------------------- + // import + //---------------------------------------------------------------------- + + { + code: "import 'a'\n\nfoo()", + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'import', next: '*' }, + ], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + }, + { + code: "import a from 'a'\n\nfoo()", + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'import', next: '*' }, + ], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + }, + { + code: "import * as a from 'a'\n\nfoo()", + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'import', next: '*' }, + ], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + }, + { + code: "import {a} from 'a'\n\nfoo()", + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'import', next: '*' }, + ], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + }, + { + code: "const a=require('a')\nfoo()", + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'import', next: '*' }, + ], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + }, + + //---------------------------------------------------------------------- + // let + //---------------------------------------------------------------------- + + { + code: 'let a=1\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'let', next: '*' }, + ], + }, + { + code: 'var a=1\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'let', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // return + //---------------------------------------------------------------------- + + { + code: 'function foo(){return\n\nfoo()}', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'return', next: '*' }, + ], + }, + { + code: 'throw a\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'return', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // switch + //---------------------------------------------------------------------- + + { + code: 'switch(a){}\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'switch', next: '*' }, + ], + }, + { + code: 'if(a){}\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'switch', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // throw + //---------------------------------------------------------------------- + + { + code: 'throw a\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'throw', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // try + //---------------------------------------------------------------------- + + { + code: 'try{}catch(e){}\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'try', next: '*' }, + ], + }, + { + code: 'try{}finally{}\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'try', next: '*' }, + ], + }, + { + code: 'try{}catch(e){}finally{}\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'try', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // var + //---------------------------------------------------------------------- + + { + code: 'var a=1\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'var', next: '*' }, + ], + }, + { + code: 'const a=1\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'var', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // while + //---------------------------------------------------------------------- + + { + code: 'while(a);\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'while', next: '*' }, + ], + }, + { + code: 'do;while(a)\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'while', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // with + //---------------------------------------------------------------------- + + { + code: 'with(a);\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'with', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // multiline-const + //---------------------------------------------------------------------- + + { + code: 'const a={\nb:1,\nc:2\n}\n\nconst d=3', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'multiline-const', next: '*' }, + ], + }, + { + code: 'const a=1\n\nconst b={\nc:2,\nd:3\n}', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: '*', next: 'multiline-const' }, + ], + }, + { + code: 'const a=1\nconst b=2', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'multiline-const', next: '*' }, + ], + }, + { + code: 'const a=1\nconst b=2', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: '*', next: 'multiline-const' }, + ], + }, + + //---------------------------------------------------------------------- + // multiline-let + //---------------------------------------------------------------------- + + { + code: 'let a={\nb:1,\nc:2\n}\n\nlet d=3', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'multiline-let', next: '*' }, + ], + }, + { + code: 'let a=1\n\nlet b={\nc:2,\nd:3\n}', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: '*', next: 'multiline-let' }, + ], + }, + { + code: 'let a=1\nlet b=2', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'multiline-let', next: '*' }, + ], + }, + { + code: 'let a=1\nlet b=2', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: '*', next: 'multiline-let' }, + ], + }, + + //---------------------------------------------------------------------- + // multiline-var + //---------------------------------------------------------------------- + + { + code: 'var a={\nb:1,\nc:2\n}\n\nvar d=3', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'multiline-var', next: '*' }, + ], + }, + { + code: 'var a=1\n\nvar b={\nc:2,\nd:3\n}', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: '*', next: 'multiline-var' }, + ], + }, + { + code: 'var a=1\nvar b=2', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'multiline-var', next: '*' }, + ], + }, + { + code: 'var a=1\nvar b=2', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: '*', next: 'multiline-var' }, + ], + }, + + //---------------------------------------------------------------------- + // single line const + //---------------------------------------------------------------------- + + { + code: 'const a=1\n\nconst b=2', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'singleline-const', next: '*' }, + ], + }, + { + code: 'const a=1\n\nconst b=2', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: '*', next: 'singleline-const' }, + ], + }, + { + code: 'const a={\nb:1,\nc:2\n}\nconst d={\ne:3,\nf:4\n}', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'singleline-const', next: '*' }, + ], + }, + { + code: 'const a={\nb:1,\nc:2\n}\nconst d={\ne:3,\nf:4\n}', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: '*', next: 'singleline-const' }, + ], + }, + + //---------------------------------------------------------------------- + // single line let + //---------------------------------------------------------------------- + + { + code: 'let a=1\n\nlet b=2', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'singleline-let', next: '*' }, + ], + }, + { + code: 'let a=1\n\nlet b=2', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: '*', next: 'singleline-let' }, + ], + }, + { + code: 'let a={\nb:1,\nc:2\n}\nlet d={\ne:3,\nf:4\n}', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'singleline-let', next: '*' }, + ], + }, + { + code: 'let a={\nb:1,\nc:2\n}\nlet d={\ne:3,\nf:4\n}', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: '*', next: 'singleline-let' }, + ], + }, + + //---------------------------------------------------------------------- + // single line var + //---------------------------------------------------------------------- + + { + code: 'var a=1\n\nvar b=2', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'singleline-var', next: '*' }, + ], + }, + { + code: 'var a=1\n\nvar b=2', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: '*', next: 'singleline-var' }, + ], + }, + { + code: 'var a={\nb:1,\nc:2\n}\nvar d={\ne:3,\nf:4\n}', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'singleline-var', next: '*' }, + ], + }, + { + code: 'var a={\nb:1,\nc:2\n}\nvar d={\ne:3,\nf:4\n}', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: '*', next: 'singleline-var' }, + ], + }, + + //---------------------------------------------------------------------- + // Tests from newline-after-var + //---------------------------------------------------------------------- + + // should skip rule entirely + { + code: 'console.log(greet);', + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: 'console.log(greet);', + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + // should ignore a `var` with no following token + { + code: "var greet = 'hello';", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var greet = 'hello';", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + // should allow no line break in "never" mode + { + code: "var greet = 'hello';console.log(greet);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + // should allow no blank line in "never" mode + { + code: "var greet = 'hello';\nconsole.log(greet);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + // should allow one blank line in "always" mode + { + code: "var greet = 'hello';\n\nconsole.log(greet);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + // should allow two or more blank lines in "always" mode + { + code: "var greet = 'hello';\n\n\nconsole.log(greet);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var greet = 'hello';\n\n\n\nconsole.log(greet);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + // should allow trailing whitespace after the `var` + { + code: "var greet = 'hello'; \n\nconsole.log(greet);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var greet = 'hello'; \nconsole.log(greet);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + // should allow inline comments after the `var` + { + code: "var greet = 'hello'; // inline comment\n\nconsole.log(greet);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var greet = 'hello'; // inline comment\nconsole.log(greet);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + // should allow a comment on the next line in "never" mode + { + code: "var greet = 'hello';\n// next-line comment\nconsole.log(greet);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var greet = 'hello';\n/* block comment\nblock comment */\nconsole.log(greet);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + // should allow comments on the next line followed by a blank in "always" mode + { + code: "var greet = 'hello';\n// next-line comment\n\nconsole.log(greet);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var greet = 'hello';\n/* block comment\nblock comment */\n\nconsole.log(greet);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var greet = 'hello';\n// next-line comment\n// second-line comment\n\nconsole.log(greet);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + // should allow comments on the next line followed by no blank in "never" mode + { + code: "var greet = 'hello';\n// next-line comment\n// second-line comment\nconsole.log(greet);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var greet = 'hello';\n// next-line comment\n/* block comment\nblock comment */\nconsole.log(greet);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + // should allow another `var` statement to follow without blank line + { + code: "var greet = 'hello';var name = 'world';console.log(greet, name);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var greet = 'hello';\nvar name = 'world';\nconsole.log(greet, name);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var greet = 'hello';\nvar name = 'world';\n\nconsole.log(greet, name);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + // should allow a comment directly between `var` statements + { + code: "var greet = 'hello';\n// inline comment\nvar name = 'world';\n\nconsole.log(greet, name);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var greet = 'hello';\n/* block comment\nblock comment */\nvar name = 'world';\n\nconsole.log(greet, name);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var greet = 'hello';\n// inline comment\nvar name = 'world';\nconsole.log(greet, name);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var greet = 'hello';\n/* block comment\nblock comment */\nvar name = 'world';\nconsole.log(greet, name);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + // should handle single `var` statement with multiple declarations + { + code: "var greet = 'hello', name = 'world';console.log(greet, name);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var greet = 'hello', name = 'world';\nconsole.log(greet, name);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var greet = 'hello', name = 'world';\n\nconsole.log(greet, name);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + // should handle single `var` statement with multi-line declaration + { + code: "var greet = 'hello',\nname = 'world';\n\nconsole.log(greet, name);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var greet = 'hello',\nname = 'world';\nconsole.log(greet, name);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var greet = 'hello', // inline comment\nname = 'world'; // inline comment\n\nconsole.log(greet, name);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var greet = 'hello', // inline comment\nname = 'world'; // inline comment\nconsole.log(greet, name);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var greet = 'hello',\nname = 'world';\n// next-line comment\nconsole.log(greet);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var greet = 'hello',\nname = 'world';\n/* block comment\nblock comment */\nconsole.log(greet);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + // should handle ES6 `let` block binding + { + code: "let greet = 'hello';\n\nconsole.log(greet);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "let greet = 'hello';\nconsole.log(greet);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + // should handle ES6 `const` block binding + { + code: "const greet = 'hello';\n\nconsole.log(greet);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "const greet = 'hello';\nconsole.log(greet);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + // should handle a mix of `var`, `let`, or `const` + { + code: "let greet = 'hello';\nvar name = 'world';\n\nconsole.log(greet, name);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "const greet = 'hello';\nvar name = 'world';\n\nconsole.log(greet, name);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "let greet = 'hello';\nconst name = 'world';\n\nconsole.log(greet, name);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + // should handle a mix of `var` or `let` inside for variations + { + code: 'for(let a = 1; a < 1; a++){\n break;\n}', + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: 'for(var a = 1; a < 1; a++){\n break;\n}', + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: 'for(let a = 1; a < 1; a++){\n break;\n}', + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: 'for(var a = 1; a < 1; a++){\n break;\n}', + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: 'for(let a in obj){\n break;\n}', + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: 'for(var a in obj){\n break;\n}', + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: 'for(let a in obj){\n break;\n}', + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: 'for(var a in obj){\n break;\n}', + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + // should handle export specifiers + { + code: 'export let a = 1;\nexport let b = 2;', + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + }, + { + code: 'export let a = 1;\nexport let b = 2;', + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + }, + { + code: 'export var a = 1;\nexport var b = 2;', + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + }, + { + code: 'export var a = 1;\nexport var b = 2;', + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + }, + { + code: 'export const a = 1;\nexport const b = 2;', + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + }, + { + code: 'export const a = 1;\nexport const b = 2;', + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + }, + + // should allow no blank line at end of block + { + code: "function example() {\nvar greet = 'hello'\n}", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "function example() {\nvar greet = 'hello'\n}", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "function example() {\nvar greet = 'hello';\nconsole.log(greet);\n}", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var f = function() {\nvar greet = 'hello'\n};", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var f = function() {\nvar greet = 'hello'\n};", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "var f = function() {\nvar greet = 'hello';\nconsole.log(greet);\n};", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "() => {\nvar greet = 'hello';\n}", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "() => {\nvar greet = 'hello';\n}", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: "() => {\nvar greet = 'hello';\nconsole.log(greet);\n}", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: '{\nvar foo;\n}', + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: '{\nvar foo;\n}', + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: 'if(true) {\nvar foo;\n}', + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: 'if(true) {\nvar foo;\n}', + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: 'switch(a) {\ncase 0:\nvar foo;\n}', + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: 'switch(a) {\ncase 0:\nvar foo;\n}', + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + // should handle one/no blank before case. + { + code: 'switch(a) {\ncase 0:\nvar foo;\n\ncase 1:}', + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: 'switch(a) {\ncase 0:\nvar foo;\ncase 1:}', + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + // https://github.com/eslint/eslint/issues/6834 + { + code: ` +var a = 1 + +;(b || c).doSomething() + `, + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: ` +var a = 1 +;(b || c).doSomething() + `, + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: ` +var a = 1 +; +(b || c).doSomething(); + `, + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + { + code: 'switch(a) {\ncase 0:\nvar foo;\n\ncase 1:}', + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: 'switch(a) {\ncase 0:\nvar foo;\ncase 1:}', + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + { + code: ` +var a = 1 + +; +(b || c).doSomething(); + `, + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + }, + + //---------------------------------------------------------------------- + // Tests from newline-before-return + //---------------------------------------------------------------------- + + { + code: 'function a() {\nreturn;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\n\nreturn;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nvar b;\n\nreturn;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nif (b) return;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nif (b) { return; }\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nif (b) {\nreturn;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nif (b) {\n\nreturn;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nif (b) {\nreturn;\n}\n\nreturn c;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nif (b) {\n\nreturn;\n}\n\nreturn c;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nif (!b) {\nreturn;\n} else {\nreturn b;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nif (!b) {\nreturn;\n} else {\n\nreturn b;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nif (b) {\nreturn b;\n} else if (c) {\nreturn c;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nif (b) {\nreturn b;\n} else if (c) {\nreturn c;\n} else {\nreturn d;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nif (b) {\nreturn b;\n} else if (c) {\nreturn c;\n} else {\nreturn d;\n}\n\nreturn a;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nif (b) return b;\nelse if (c) return c;\nelse return d;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nif (b) return b;\nelse if (c) return c;\nelse {\nreturn d;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nif (b) return b;\nelse if (c) return c;\nelse {\ne();\n\nreturn d;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nwhile (b) return;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\n while (b) \nreturn;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\n while (b) { return; }\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\n while (b) {\nreturn;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\n while (b) {\nc();\n\nreturn;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nvar c;\nwhile (b) {\n c = d; //comment\n}\n\nreturn c;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\ndo return;\nwhile (b);\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\ndo \nreturn;\nwhile (b);\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\ndo { return; } while (b);\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\ndo { return; }\nwhile (b);\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\ndo {\nreturn;\n} while (b);\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\ndo {\nc();\n\nreturn;\n} while (b);\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nfor (var b; b < c; b++) return;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nfor (var b; b < c; b++)\nreturn;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nfor (var b; b < c; b++) {\nreturn;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nfor (var b; b < c; b++) {\nc();\n\nreturn;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nfor (var b; b < c; b++) {\nif (d) {\nbreak; //comment\n}\n\nreturn;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nfor (b in c)\nreturn;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nfor (b in c) { return; }\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nfor (b in c) {\nreturn;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nfor (b in c) {\nd();\n\nreturn;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nfor (b of c) return;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nfor (b of c)\nreturn;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nfor (b of c) {\nreturn;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nfor (b of c) {\nd();\n\nreturn;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: "function a() {\nswitch (b) {\ncase 'b': return;\n}\n}", + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: "function a() {\nswitch (b) {\ncase 'b':\nreturn;\n}\n}", + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: "function a() {\nswitch (b) {\ncase 'b': {\nreturn;\n}\n}\n}", + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\n//comment\nreturn b;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\n{\n//comment\n}\n\nreturn\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nvar b = {\n//comment\n};\n\nreturn;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {/*multi-line\ncomment*/return b;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\n/*comment\ncomment*/\n//comment\nreturn b;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\n/*comment\ncomment*/\n//comment\nif (b) return;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\n/*comment\ncomment*/\n//comment\nif (b) {\nc();\n\nreturn b;\n} else {\n//comment\nreturn d;\n}\n\n/*multi-line\ncomment*/\nreturn e;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nif (b) { //comment\nreturn;\n}\n\nreturn c;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nif (b) { return; } //comment\n\nreturn c;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nif (b) { return; } /*multi-line\ncomment*/\n\nreturn c;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'function a() {\nif (b) { return; }\n\n/*multi-line\ncomment*/ return c;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + }, + { + code: 'return;', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + parserOptions: { ecmaFeatures: { globalReturn: true } }, + }, + { + code: 'var a;\n\nreturn;', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + parserOptions: { ecmaFeatures: { globalReturn: true } }, + }, + { + code: '// comment\nreturn;', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + parserOptions: { ecmaFeatures: { globalReturn: true } }, + }, + { + code: '/* comment */\nreturn;', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + parserOptions: { ecmaFeatures: { globalReturn: true } }, + }, + { + code: '/* multi-line\ncomment */\nreturn;', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + parserOptions: { ecmaFeatures: { globalReturn: true } }, + }, + + //---------------------------------------------------------------------- + // From JSCS disallowPaddingNewLinesAfterBlocks + // https://github.com/jscs-dev/node-jscs/blob/44f9b86eb0757fd4ca05a81a50450c5f1b25c37b/test/specs/rules/disallow-padding-newlines-after-blocks.js + //---------------------------------------------------------------------- + + { + code: 'if(true){}', + options: [{ blankLine: 'never', prev: 'block-like', next: '*' }], + }, + { + code: 'if(true){}\n', + options: [{ blankLine: 'never', prev: 'block-like', next: '*' }], + }, + { + code: 'if(true){}\nvar a = 2;', + options: [{ blankLine: 'never', prev: 'block-like', next: '*' }], + }, + { + code: 'if(true){\nif(true) {}\n}', + options: [{ blankLine: 'never', prev: 'block-like', next: '*' }], + }, + { + code: 'var a = {\nfoo: function() {\n},\nbar: function() {\n}}', + options: [{ blankLine: 'never', prev: 'block-like', next: '*' }], + }, + { + code: '(function(){\n})()\nvar a = 2;', + options: [{ blankLine: 'never', prev: 'block-like', next: '*' }], + }, + { + code: 'if(true) {\n}\nelse\n{\n}', + options: [{ blankLine: 'never', prev: 'block-like', next: '*' }], + }, + { + code: 'if(true) {\n} else {\n var a = 2; }', + options: [{ blankLine: 'never', prev: 'block-like', next: '*' }], + }, + { + code: 'if(true) {\n}\nelse if(true)\n{\n}\nelse {\n}', + options: [{ blankLine: 'never', prev: 'block-like', next: '*' }], + }, + { + code: 'do{\n}\nwhile(true)', + options: [{ blankLine: 'never', prev: 'block-like', next: '*' }], + }, + { + code: 'try{\n}\ncatch(e) {}', + options: [{ blankLine: 'never', prev: 'block-like', next: '*' }], + }, + { + code: 'try{\n}\nfinally {}', + options: [{ blankLine: 'never', prev: 'block-like', next: '*' }], + }, + { + code: 'try{\n}\ncatch(e) {\n}\nfinally {\n}', + options: [{ blankLine: 'never', prev: 'block-like', next: '*' }], + }, + { + code: '[].map(function() {})\n.filter(function(){})', + options: [{ blankLine: 'never', prev: 'block-like', next: '*' }], + }, + + //---------------------------------------------------------------------- + // From JSCS disallowPaddingNewLinesBeforeExport + // https://github.com/jscs-dev/node-jscs/blob/44f9b86eb0757fd4ca05a81a50450c5f1b25c37b/test/specs/rules/disallow-padding-newlines-before-export.js + //---------------------------------------------------------------------- + + { + code: 'var a = 2;\nmodule.exports = a;', + options: [{ blankLine: 'never', prev: '*', next: 'exports' }], + }, + { + code: 'module.exports = 2;', + options: [{ blankLine: 'never', prev: '*', next: 'exports' }], + }, + { + code: 'var a = 2;\n// foo\nmodule.exports = a;', + options: [{ blankLine: 'never', prev: '*', next: 'exports' }], + }, + + /* + * TODO: May it need an option to ignore blank lines followed by comments? + * { + * code: "var a = 2;\n\n// foo\nmodule.exports = a;", + * options: [ + * { blankLine: "never", prev: "*", next: "exports" } + * ] + * }, + */ + { + code: 'var a = 2;\n\nfoo.exports = a;', + options: [{ blankLine: 'never', prev: '*', next: 'exports' }], + }, + { + code: 'var a = 2;\n\nmodule.foo = a;', + options: [{ blankLine: 'never', prev: '*', next: 'exports' }], + }, + { + code: 'var a = 2;\n\nfoo = a;', + options: [{ blankLine: 'never', prev: '*', next: 'exports' }], + }, + + //---------------------------------------------------------------------- + // From JSCS requirePaddingNewLinesAfterBlocks + // https://github.com/jscs-dev/node-jscs/blob/44f9b86eb0757fd4ca05a81a50450c5f1b25c37b/test/specs/rules/require-padding-newlines-after-blocks.js + //---------------------------------------------------------------------- + + { + code: '{}', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + }, + { + code: 'if(true){}', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + }, + { + code: 'if(true){}\n', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + }, + { + code: 'if(true){}\n\nvar a = 2;', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + }, + { + code: 'if(true){}\n\n\nvar a = 2;', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + }, + { + code: 'if(true){\nif(true) {}\n}', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + }, + { + code: 'var a = {\nfoo: function() {\n},\n\nbar: function() {\n}}', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + }, + { + code: '(function(){\n})()\n\nvar a = 2;', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + }, + { + code: 'if(true) {\n}\nelse\n{\n}', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + }, + { + code: 'if(true) {\n} else {\n var a = 2; }', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + }, + { + code: 'if(true) {\n}\nelse if(true)\n{\n}\nelse {\n}', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + }, + { + code: 'do{\n}\nwhile(true)', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + }, + { + code: 'try{\n}\ncatch(e) {}', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + }, + { + code: 'try{\n}\nfinally {}', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + }, + { + code: 'try{\n}\ncatch(e) {\n}\nfinally {\n}', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + }, + { + code: '[].map(function() {})\n.filter(function(){})', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + }, + { + code: 'func(\n2,\n3,\nfunction() {\n}\n)', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + }, + { + code: '[\n2,\n3,\nfunction() {\n}\n]', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + }, + { + code: 'a(res => {\n})\n.b();', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + }, + { + code: 'var foo = (\n\nfoo\n\n);', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + parserOptions: { ecmaFeatures: { jsx: true } }, + }, + { + code: 'var i = 0;\nwhile (i < 100) {\nif(i % 2 === 0) {continue;}\n++i;\n}', + options: [ + { blankLine: 'always', prev: 'multiline-block-like', next: '*' }, + ], + }, + { + code: 'var i = 0;\nwhile (i < 100) {\nif(i % 2 === 0) {if(i === 4) {continue;}}\n++i;\n}', + options: [ + { blankLine: 'always', prev: 'multiline-block-like', next: '*' }, + ], + }, + + //---------------------------------------------------------------------- + // From JSCS requirePaddingNewLinesBeforeExport + // https://github.com/jscs-dev/node-jscs/blob/44f9b86eb0757fd4ca05a81a50450c5f1b25c37b/test/specs/rules/require-padding-newlines-before-export.js + //---------------------------------------------------------------------- + + { + code: 'module.exports = 2;', + options: [{ blankLine: 'always', prev: '*', next: 'exports' }], + }, + { + code: 'var a = 2;\n\nmodule.exports = a;', + options: [{ blankLine: 'always', prev: '*', next: 'exports' }], + }, + { + code: 'var a = 2;\nfoo.exports = a;', + options: [{ blankLine: 'always', prev: '*', next: 'exports' }], + }, + { + code: 'var a = 2;\nmodule.foo = a;', + options: [{ blankLine: 'always', prev: '*', next: 'exports' }], + }, + { + code: 'if (true) {\nmodule.exports = a;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'exports' }], + }, + + //---------------------------------------------------------------------- + // From JSCS requirePaddingNewlinesBeforeKeywords + // https://github.com/jscs-dev/node-jscs/blob/44f9b86eb0757fd4ca05a81a50450c5f1b25c37b/test/specs/rules/require-padding-newlines-before-keywords.js + //---------------------------------------------------------------------- + + { + code: 'function x() { return; }', + options: [ + { + blankLine: 'always', + prev: '*', + next: [ + 'if', + 'for', + 'return', + 'switch', + 'case', + 'break', + 'throw', + 'while', + 'default', + ], + }, + ], + }, + { + code: 'if (true) {} else if (false) {}', + options: [ + { + blankLine: 'always', + prev: '*', + next: [ + 'if', + 'for', + 'return', + 'switch', + 'case', + 'break', + 'throw', + 'while', + 'default', + ], + }, + ], + }, + { + code: 'function x() { var a = true; do { a = !a; } while (a); }', + options: [ + { + blankLine: 'always', + prev: '*', + next: [ + 'if', + 'for', + 'return', + 'switch', + 'case', + 'break', + 'throw', + 'while', + 'default', + ], + }, + ], + }, + { + code: 'function x() { if (true) return; }', + options: [ + { + blankLine: 'always', + prev: '*', + next: [ + 'if', + 'for', + 'return', + 'switch', + 'case', + 'break', + 'throw', + 'while', + 'default', + ], + }, + ], + }, + { + code: 'function test() {};', + options: [ + { blankLine: 'always', prev: 'block-like', next: 'block-like' }, + ], + }, + ], + invalid: [ + //---------------------------------------------------------------------- + // wildcard + //---------------------------------------------------------------------- + + { + code: 'foo();\n\nfoo();', + output: 'foo();\nfoo();', + options: [{ blankLine: 'never', prev: '*', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'foo();\n\n//comment\nfoo();', + output: 'foo();\n//comment\nfoo();', + options: [{ blankLine: 'never', prev: '*', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: ' foo();\n \n //comment\n foo();', + output: ' foo();\n //comment\n foo();', + options: [{ blankLine: 'never', prev: '*', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'if (a) {}\n\nfor (;;) {}', + output: 'if (a) {}\nfor (;;) {}', + options: [{ blankLine: 'never', prev: '*', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'foo();\nfoo();', + output: 'foo();\n\nfoo();', + options: [{ blankLine: 'always', prev: '*', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: ' function a() {}\n do {} while (a)', + output: ' function a() {}\n\n do {} while (a)', + options: [{ blankLine: 'always', prev: '*', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'foo();//trailing-comment\n//comment\n//comment\nfoo();', + output: 'foo();//trailing-comment\n\n//comment\n//comment\nfoo();', + options: [{ blankLine: 'always', prev: '*', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // block-like + //---------------------------------------------------------------------- + + { + code: '{}\n\nfoo()', + output: '{}\nfoo()', + options: [{ blankLine: 'never', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: '{}\nfoo()', + output: '{}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'if(a){}\nfoo()', + output: 'if(a){}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'if(a){}else{}\nfoo()', + output: 'if(a){}else{}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'if(a){}else if(b){}\nfoo()', + output: 'if(a){}else if(b){}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'if(a){}else if(b){}else{}\nfoo()', + output: 'if(a){}else if(b){}else{}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'switch(a){}\nfoo()', + output: 'switch(a){}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'switch(a){case 0:}\nfoo()', + output: 'switch(a){case 0:}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'try{}catch(e){}\nfoo()', + output: 'try{}catch(e){}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'try{}finally{}\nfoo()', + output: 'try{}finally{}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'try{}catch(e){}finally{}\nfoo()', + output: 'try{}catch(e){}finally{}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'while(a){}\nfoo()', + output: 'while(a){}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'do{}while(a)\nfoo()', + output: 'do{}while(a)\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'for(;;){}\nfoo()', + output: 'for(;;){}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'for(a in b){}\nfoo()', + output: 'for(a in b){}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'for(a of b){}\nfoo()', + output: 'for(a of b){}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'a=function(){}\nfoo()', + output: 'a=function(){}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'a=()=>{}\nfoo()', + output: 'a=()=>{}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a(){}\nfoo()', + output: 'function a(){}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'let a=function(){}\nfoo()', + output: 'let a=function(){}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // exports + //---------------------------------------------------------------------- + + { + code: 'module.exports=1\n\nfoo()', + output: 'module.exports=1\nfoo()', + options: [{ blankLine: 'never', prev: 'exports', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'module.exports=1\nfoo()', + output: 'module.exports=1\n\nfoo()', + options: [{ blankLine: 'always', prev: 'exports', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'module.exports.foo=1\nfoo()', + output: 'module.exports.foo=1\n\nfoo()', + options: [{ blankLine: 'always', prev: 'exports', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'module.exports[foo]=1\nfoo()', + output: 'module.exports[foo]=1\n\nfoo()', + options: [{ blankLine: 'always', prev: 'exports', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'exports.foo=1\nfoo()', + output: 'exports.foo=1\n\nfoo()', + options: [{ blankLine: 'always', prev: 'exports', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'exports[foo]=1\nfoo()', + output: 'exports[foo]=1\n\nfoo()', + options: [{ blankLine: 'always', prev: 'exports', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // require + //---------------------------------------------------------------------- + + { + code: 'const foo=require("foo")\n\nfoo()', + output: 'const foo=require("foo")\nfoo()', + options: [{ blankLine: 'never', prev: 'require', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'const foo=require("foo")\nfoo()', + output: 'const foo=require("foo")\n\nfoo()', + options: [{ blankLine: 'always', prev: 'require', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'const foo=require("foo").Foo\nfoo()', + output: 'const foo=require("foo").Foo\n\nfoo()', + options: [{ blankLine: 'always', prev: 'require', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'const foo=require("foo")[a]\nfoo()', + output: 'const foo=require("foo")[a]\n\nfoo()', + options: [{ blankLine: 'always', prev: 'require', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // directive + //---------------------------------------------------------------------- + + { + code: '"use strict"\n\nfoo()', + output: '"use strict"\nfoo()', + options: [{ blankLine: 'never', prev: 'directive', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: '"use strict"\nfoo()', + output: '"use strict"\n\nfoo()', + options: [{ blankLine: 'always', prev: 'directive', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: "'use strict'\nfoo()", + output: "'use strict'\n\nfoo()", + options: [{ blankLine: 'always', prev: 'directive', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: "'use asm'\nfoo()", + output: "'use asm'\n\nfoo()", + options: [{ blankLine: 'always', prev: 'directive', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // multiline-block-like + //---------------------------------------------------------------------- + + { + code: '{\n}\n\nfoo()', + output: '{\n}\nfoo()', + options: [{ blankLine: 'never', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: '{\n}\nfoo()', + output: '{\n}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'if(a){\n}\nfoo()', + output: 'if(a){\n}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'if(a){\n}else{\n}\nfoo()', + output: 'if(a){\n}else{\n}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'if(a){\n}else if(b){\n}\nfoo()', + output: 'if(a){\n}else if(b){\n}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'if(a){\n}else if(b){\n}else{\n}\nfoo()', + output: 'if(a){\n}else if(b){\n}else{\n}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'switch(a){\n}\nfoo()', + output: 'switch(a){\n}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'try{\n}catch(e){\n}\nfoo()', + output: 'try{\n}catch(e){\n}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'try{\n}finally{\n}\nfoo()', + output: 'try{\n}finally{\n}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'try{\n}catch(e){\n}finally{\n}\nfoo()', + output: 'try{\n}catch(e){\n}finally{\n}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'while(a){\n}\nfoo()', + output: 'while(a){\n}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'do{\n}while(a)\nfoo()', + output: 'do{\n}while(a)\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'for(;;){\n}\nfoo()', + output: 'for(;;){\n}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'for(a in b){\n}\nfoo()', + output: 'for(a in b){\n}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'for(a of b){\n}\nfoo()', + output: 'for(a of b){\n}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'a=function(){\n}\nfoo()', + output: 'a=function(){\n}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'a=()=>{\n}\nfoo()', + output: 'a=()=>{\n}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a(){\n}\nfoo()', + output: 'function a(){\n}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'let a=function(){\n}\nfoo()', + output: 'let a=function(){\n}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // block + //---------------------------------------------------------------------- + + { + code: '{}\n\nfoo()', + output: '{}\nfoo()', + options: [{ blankLine: 'never', prev: 'block', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: '{}\nfoo()', + output: '{}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'block', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // empty + //---------------------------------------------------------------------- + + { + code: ';\n\nfoo()', + output: ';\nfoo()', + options: [{ blankLine: 'never', prev: 'empty', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: ';\nfoo()', + output: ';\n\nfoo()', + options: [{ blankLine: 'always', prev: 'empty', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // expression + //---------------------------------------------------------------------- + + { + code: 'foo()\n\nfoo()', + output: 'foo()\nfoo()', + options: [{ blankLine: 'never', prev: 'expression', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'foo()\nfoo()', + output: 'foo()\n\nfoo()', + options: [{ blankLine: 'always', prev: 'expression', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // multiline-expression + //---------------------------------------------------------------------- + + { + code: 'foo()\n\nfoo(\n\tx,\n\ty\n)', + output: 'foo()\nfoo(\n\tx,\n\ty\n)', + options: [ + { blankLine: 'never', prev: '*', next: 'multiline-expression' }, + ], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'foo()\nfoo(\n\tx,\n\ty\n)', + output: 'foo()\n\nfoo(\n\tx,\n\ty\n)', + options: [ + { blankLine: 'always', prev: '*', next: 'multiline-expression' }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: '() => {\n\tsomeArray.forEach(\n\t\tx => doSomething(x)\n\t);\n\treturn theThing;\n}', + output: + '() => {\n\tsomeArray.forEach(\n\t\tx => doSomething(x)\n\t);\n\n\treturn theThing;\n}', + options: [ + { blankLine: 'always', prev: 'multiline-expression', next: 'return' }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // break + //---------------------------------------------------------------------- + + { + code: 'while(a){break\n\nfoo()}', + output: 'while(a){break\nfoo()}', + options: [{ blankLine: 'never', prev: 'break', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'switch(a){case 0:break\n\nfoo()}', + output: 'switch(a){case 0:break\nfoo()}', + options: [{ blankLine: 'never', prev: 'break', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'while(a){break\nfoo()}', + output: 'while(a){break\n\nfoo()}', + options: [{ blankLine: 'always', prev: 'break', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'switch(a){case 0:break\nfoo()}', + output: 'switch(a){case 0:break\n\nfoo()}', + options: [{ blankLine: 'always', prev: 'break', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // case + //---------------------------------------------------------------------- + + { + code: 'switch(a){case 0:\nfoo()\n\ndefault:}', + output: 'switch(a){case 0:\nfoo()\ndefault:}', + options: [{ blankLine: 'never', prev: 'case', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'switch(a){case 0:\nfoo()\ndefault:}', + output: 'switch(a){case 0:\nfoo()\n\ndefault:}', + options: [{ blankLine: 'always', prev: 'case', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // class + //---------------------------------------------------------------------- + + { + code: 'class A{}\n\nfoo()', + output: 'class A{}\nfoo()', + options: [{ blankLine: 'never', prev: 'class', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'class A{}\nfoo()', + output: 'class A{}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'class', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // const + //---------------------------------------------------------------------- + + { + code: 'const a=1\n\nfoo()', + output: 'const a=1\nfoo()', + options: [{ blankLine: 'never', prev: 'const', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'const a=1\nfoo()', + output: 'const a=1\n\nfoo()', + options: [{ blankLine: 'always', prev: 'const', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // type + //---------------------------------------------------------------------- + + { + code: 'type a=number\n\nfoo()', + output: 'type a=number\nfoo()', + options: [{ blankLine: 'never', prev: 'type', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'type a=number\nfoo()', + output: 'type a=number\n\nfoo()', + options: [{ blankLine: 'always', prev: 'type', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // interface + //---------------------------------------------------------------------- + + { + code: 'interface Test{\na:number;\n}\nfoo()', + output: 'interface Test{\na:number;\n}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'interface', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // continue + //---------------------------------------------------------------------- + + { + code: 'while(a){continue\n\nfoo()}', + output: 'while(a){continue\nfoo()}', + options: [{ blankLine: 'never', prev: 'continue', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'while(a){continue\nfoo()}', + output: 'while(a){continue\n\nfoo()}', + options: [{ blankLine: 'always', prev: 'continue', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // debugger + //---------------------------------------------------------------------- + + { + code: 'debugger\n\nfoo()', + output: 'debugger\nfoo()', + options: [{ blankLine: 'never', prev: 'debugger', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'debugger\nfoo()', + output: 'debugger\n\nfoo()', + options: [{ blankLine: 'always', prev: 'debugger', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // default + //---------------------------------------------------------------------- + + { + code: 'switch(a){default:\nfoo()\n\ncase 0:}', + output: 'switch(a){default:\nfoo()\ncase 0:}', + options: [{ blankLine: 'never', prev: 'default', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'switch(a){default:\nfoo()\ncase 0:}', + output: 'switch(a){default:\nfoo()\n\ncase 0:}', + options: [{ blankLine: 'always', prev: 'default', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // do + //---------------------------------------------------------------------- + + { + code: 'do;while(a)\n\nfoo()', + output: 'do;while(a)\nfoo()', + options: [{ blankLine: 'never', prev: 'do', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'do;while(a)\nfoo()', + output: 'do;while(a)\n\nfoo()', + options: [{ blankLine: 'always', prev: 'do', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // export + //---------------------------------------------------------------------- + + { + code: 'export default 1\n\nfoo()', + output: 'export default 1\nfoo()', + options: [{ blankLine: 'never', prev: 'export', next: '*' }], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'export let a=1\n\nfoo()', + output: 'export let a=1\nfoo()', + options: [{ blankLine: 'never', prev: 'export', next: '*' }], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'var a = 0;export {a}\n\nfoo()', + output: 'var a = 0;export {a}\nfoo()', + options: [{ blankLine: 'never', prev: 'export', next: '*' }], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'export default 1\nfoo()', + output: 'export default 1\n\nfoo()', + options: [{ blankLine: 'always', prev: 'export', next: '*' }], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'export let a=1\nfoo()', + output: 'export let a=1\n\nfoo()', + options: [{ blankLine: 'always', prev: 'export', next: '*' }], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'var a = 0;export {a}\nfoo()', + output: 'var a = 0;export {a}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'export', next: '*' }], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // for + //---------------------------------------------------------------------- + + { + code: 'for(;;);\n\nfoo()', + output: 'for(;;);\nfoo()', + options: [{ blankLine: 'never', prev: 'for', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'for(a in b);\n\nfoo()', + output: 'for(a in b);\nfoo()', + options: [{ blankLine: 'never', prev: 'for', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'for(a of b);\n\nfoo()', + output: 'for(a of b);\nfoo()', + options: [{ blankLine: 'never', prev: 'for', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'for(;;);\nfoo()', + output: 'for(;;);\n\nfoo()', + options: [{ blankLine: 'always', prev: 'for', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'for(a in b);\nfoo()', + output: 'for(a in b);\n\nfoo()', + options: [{ blankLine: 'always', prev: 'for', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'for(a of b);\nfoo()', + output: 'for(a of b);\n\nfoo()', + options: [{ blankLine: 'always', prev: 'for', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // function + //---------------------------------------------------------------------- + + { + code: 'function foo(){}\n\nfoo()', + output: 'function foo(){}\nfoo()', + options: [{ blankLine: 'never', prev: 'function', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'function foo(){}\nfoo()', + output: 'function foo(){}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'function', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'async function foo(){}\nfoo()', + output: 'async function foo(){}\n\nfoo()', + options: [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'function', next: '*' }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // if + //---------------------------------------------------------------------- + + { + code: 'if(a);\n\nfoo()', + output: 'if(a);\nfoo()', + options: [{ blankLine: 'never', prev: 'if', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'if(a);else;\n\nfoo()', + output: 'if(a);else;\nfoo()', + options: [{ blankLine: 'never', prev: 'if', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'if(a);\nfoo()', + output: 'if(a);\n\nfoo()', + options: [{ blankLine: 'always', prev: 'if', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'if(a);else;\nfoo()', + output: 'if(a);else;\n\nfoo()', + options: [{ blankLine: 'always', prev: 'if', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // iife + //---------------------------------------------------------------------- + + { + code: '(function(){\n})()\n\nvar a = 2;', + output: '(function(){\n})()\nvar a = 2;', + options: [{ blankLine: 'never', prev: 'iife', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: '+(function(){\n})()\n\nvar a = 2;', + output: '+(function(){\n})()\nvar a = 2;', + options: [{ blankLine: 'never', prev: 'iife', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: '(function(){\n})()\nvar a = 2;', + output: '(function(){\n})()\n\nvar a = 2;', + options: [{ blankLine: 'always', prev: 'iife', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: '+(function(){\n})()\nvar a = 2;', + output: '+(function(){\n})()\n\nvar a = 2;', + options: [{ blankLine: 'always', prev: 'iife', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + // Optional chaining + { + code: '(function(){\n})?.()\nvar a = 2;', + output: '(function(){\n})?.()\n\nvar a = 2;', + options: [{ blankLine: 'always', prev: 'iife', next: '*' }], + parserOptions: { ecmaVersion: 2020 }, + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'void (function(){\n})?.()\nvar a = 2;', + output: 'void (function(){\n})?.()\n\nvar a = 2;', + options: [{ blankLine: 'always', prev: 'iife', next: '*' }], + parserOptions: { ecmaVersion: 2020 }, + errors: [{ messageId: 'expectedBlankLine' }], + }, + + // Sequenced function + { + code: '(1,2,3,function(){\n})()\nvar a = 2;', + output: '(1,2,3,function(){\n})()\n\nvar a = 2;', + options: [{ blankLine: 'always', prev: 'iife', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // import + //---------------------------------------------------------------------- + + { + code: "import a from 'a'\n\nfoo()", + output: "import a from 'a'\nfoo()", + options: [{ blankLine: 'never', prev: 'import', next: '*' }], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: "import * as a from 'a'\n\nfoo()", + output: "import * as a from 'a'\nfoo()", + options: [{ blankLine: 'never', prev: 'import', next: '*' }], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: "import {a} from 'a'\n\nfoo()", + output: "import {a} from 'a'\nfoo()", + options: [{ blankLine: 'never', prev: 'import', next: '*' }], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: "import a from 'a'\nfoo()", + output: "import a from 'a'\n\nfoo()", + options: [{ blankLine: 'always', prev: 'import', next: '*' }], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: "import * as a from 'a'\nfoo()", + output: "import * as a from 'a'\n\nfoo()", + options: [{ blankLine: 'always', prev: 'import', next: '*' }], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: "import {a} from 'a'\nfoo()", + output: "import {a} from 'a'\n\nfoo()", + options: [{ blankLine: 'always', prev: 'import', next: '*' }], + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // let + //---------------------------------------------------------------------- + + { + code: 'let a\n\nfoo()', + output: 'let a\nfoo()', + options: [{ blankLine: 'never', prev: 'let', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'let a\nfoo()', + output: 'let a\n\nfoo()', + options: [{ blankLine: 'always', prev: 'let', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // return + //---------------------------------------------------------------------- + + { + code: 'function foo(){return\n\nfoo()}', + output: 'function foo(){return\nfoo()}', + options: [{ blankLine: 'never', prev: 'return', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'function foo(){return\nfoo()}', + output: 'function foo(){return\n\nfoo()}', + options: [{ blankLine: 'always', prev: 'return', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // switch + //---------------------------------------------------------------------- + + { + code: 'switch(a){}\n\nfoo()', + output: 'switch(a){}\nfoo()', + options: [{ blankLine: 'never', prev: 'switch', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'switch(a){}\nfoo()', + output: 'switch(a){}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'switch', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // throw + //---------------------------------------------------------------------- + + { + code: 'throw a\n\nfoo()', + output: 'throw a\nfoo()', + options: [{ blankLine: 'never', prev: 'throw', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'throw a\nfoo()', + output: 'throw a\n\nfoo()', + options: [{ blankLine: 'always', prev: 'throw', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // try + //---------------------------------------------------------------------- + + { + code: 'try{}catch(e){}\n\nfoo()', + output: 'try{}catch(e){}\nfoo()', + options: [{ blankLine: 'never', prev: 'try', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'try{}finally{}\n\nfoo()', + output: 'try{}finally{}\nfoo()', + options: [{ blankLine: 'never', prev: 'try', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'try{}catch(e){}finally{}\n\nfoo()', + output: 'try{}catch(e){}finally{}\nfoo()', + options: [{ blankLine: 'never', prev: 'try', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'try{}catch(e){}\nfoo()', + output: 'try{}catch(e){}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'try', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'try{}finally{}\nfoo()', + output: 'try{}finally{}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'try', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'try{}catch(e){}finally{}\nfoo()', + output: 'try{}catch(e){}finally{}\n\nfoo()', + options: [{ blankLine: 'always', prev: 'try', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // var + //---------------------------------------------------------------------- + + { + code: 'var a\n\nfoo()', + output: 'var a\nfoo()', + options: [{ blankLine: 'never', prev: 'var', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'var a\nfoo()', + output: 'var a\n\nfoo()', + options: [{ blankLine: 'always', prev: 'var', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // while + //---------------------------------------------------------------------- + + { + code: 'while(a);\n\nfoo()', + output: 'while(a);\nfoo()', + options: [{ blankLine: 'never', prev: 'while', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'while(a);\nfoo()', + output: 'while(a);\n\nfoo()', + options: [{ blankLine: 'always', prev: 'while', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // with + //---------------------------------------------------------------------- + + { + code: 'with(a);\n\nfoo()', + output: 'with(a);\nfoo()', + options: [{ blankLine: 'never', prev: 'with', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'with(a);\nfoo()', + output: 'with(a);\n\nfoo()', + options: [{ blankLine: 'always', prev: 'with', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // multiline-const + //---------------------------------------------------------------------- + + { + code: 'const a={\nb:1,\nc:2\n}\n\nconst d=3', + output: 'const a={\nb:1,\nc:2\n}\nconst d=3', + options: [{ blankLine: 'never', prev: 'multiline-const', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'const a={\nb:1,\nc:2\n}\nconst d=3', + output: 'const a={\nb:1,\nc:2\n}\n\nconst d=3', + options: [{ blankLine: 'always', prev: 'multiline-const', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'const a=1\n\nconst b={\nc:2,\nd:3\n}', + output: 'const a=1\nconst b={\nc:2,\nd:3\n}', + options: [{ blankLine: 'never', prev: '*', next: 'multiline-const' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'const a=1\nconst b={\nc:2,\nd:3\n}', + output: 'const a=1\n\nconst b={\nc:2,\nd:3\n}', + options: [{ blankLine: 'always', prev: '*', next: 'multiline-const' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // multiline-let + //---------------------------------------------------------------------- + + { + code: 'let a={\nb:1,\nc:2\n}\n\nlet d=3', + output: 'let a={\nb:1,\nc:2\n}\nlet d=3', + options: [{ blankLine: 'never', prev: 'multiline-let', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'let a={\nb:1,\nc:2\n}\nlet d=3', + output: 'let a={\nb:1,\nc:2\n}\n\nlet d=3', + options: [{ blankLine: 'always', prev: 'multiline-let', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'let a=1\n\nlet b={\nc:2,\nd:3\n}', + output: 'let a=1\nlet b={\nc:2,\nd:3\n}', + options: [{ blankLine: 'never', prev: '*', next: 'multiline-let' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'let a=1\nlet b={\nc:2,\nd:3\n}', + output: 'let a=1\n\nlet b={\nc:2,\nd:3\n}', + options: [{ blankLine: 'always', prev: '*', next: 'multiline-let' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // multiline-var + //---------------------------------------------------------------------- + + { + code: 'var a={\nb:1,\nc:2\n}\n\nvar d=3', + output: 'var a={\nb:1,\nc:2\n}\nvar d=3', + options: [{ blankLine: 'never', prev: 'multiline-var', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'var a={\nb:1,\nc:2\n}\nvar d=3', + output: 'var a={\nb:1,\nc:2\n}\n\nvar d=3', + options: [{ blankLine: 'always', prev: 'multiline-var', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'var a=1\n\nvar b={\nc:2,\nd:3\n}', + output: 'var a=1\nvar b={\nc:2,\nd:3\n}', + options: [{ blankLine: 'never', prev: '*', next: 'multiline-var' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'var a=1\nvar b={\nc:2,\nd:3\n}', + output: 'var a=1\n\nvar b={\nc:2,\nd:3\n}', + options: [{ blankLine: 'always', prev: '*', next: 'multiline-var' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // single line const + //---------------------------------------------------------------------- + + { + code: 'const a=1\n\nconst b=2', + output: 'const a=1\nconst b=2', + options: [{ blankLine: 'never', prev: 'singleline-const', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'const a=1\nconst b=2', + output: 'const a=1\n\nconst b=2', + options: [{ blankLine: 'always', prev: 'singleline-const', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'const a=1\n\nconst b=2', + output: 'const a=1\nconst b=2', + options: [{ blankLine: 'never', prev: '*', next: 'singleline-const' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'const a=1\nconst b=2', + output: 'const a=1\n\nconst b=2', + options: [{ blankLine: 'always', prev: '*', next: 'singleline-const' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // single line let + //---------------------------------------------------------------------- + + { + code: 'let a=1\n\nlet b=2', + output: 'let a=1\nlet b=2', + options: [{ blankLine: 'never', prev: 'singleline-let', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'let a=1\nlet b=2', + output: 'let a=1\n\nlet b=2', + options: [{ blankLine: 'always', prev: 'singleline-let', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'let a=1\n\nlet b=2', + output: 'let a=1\nlet b=2', + options: [{ blankLine: 'never', prev: '*', next: 'singleline-let' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'let a=1\nlet b=2', + output: 'let a=1\n\nlet b=2', + options: [{ blankLine: 'always', prev: '*', next: 'singleline-let' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // single line var + //---------------------------------------------------------------------- + + { + code: 'var a=1\n\nvar b=2', + output: 'var a=1\nvar b=2', + options: [{ blankLine: 'never', prev: 'singleline-var', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'var a=1\nvar b=2', + output: 'var a=1\n\nvar b=2', + options: [{ blankLine: 'always', prev: 'singleline-var', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'var a=1\n\nvar b=2', + output: 'var a=1\nvar b=2', + options: [{ blankLine: 'never', prev: '*', next: 'singleline-var' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'var a=1\nvar b=2', + output: 'var a=1\n\nvar b=2', + options: [{ blankLine: 'always', prev: '*', next: 'singleline-var' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // Tests from newline-after-var + //---------------------------------------------------------------------- + + // should disallow no line break in "always" mode + { + code: "var greet = 'hello';console.log(greet);", + output: "var greet = 'hello';\n\nconsole.log(greet);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: "var greet = 'hello';var name = 'world';console.log(greet, name);", + output: + "var greet = 'hello';var name = 'world';\n\nconsole.log(greet, name);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: "var greet = 'hello', name = 'world';console.log(greet, name);", + output: + "var greet = 'hello', name = 'world';\n\nconsole.log(greet, name);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + // should disallow no blank line in "always" mode + { + code: "var greet = 'hello';\nconsole.log(greet);", + output: "var greet = 'hello';\n\nconsole.log(greet);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: "var greet = 'hello'; \nconsole.log(greet);", + output: "var greet = 'hello';\n \nconsole.log(greet);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: "var greet = 'hello'; // inline comment\nconsole.log(greet);", + output: "var greet = 'hello'; // inline comment\n\nconsole.log(greet);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: "var greet = 'hello';\nvar name = 'world';\nconsole.log(greet, name);", + output: + "var greet = 'hello';\nvar name = 'world';\n\nconsole.log(greet, name);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: "var greet = 'hello', name = 'world';\nconsole.log(greet, name);", + output: + "var greet = 'hello', name = 'world';\n\nconsole.log(greet, name);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: "var greet = 'hello',\nname = 'world';\nconsole.log(greet, name);", + output: + "var greet = 'hello',\nname = 'world';\n\nconsole.log(greet, name);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: "let greet = 'hello';\nconsole.log(greet);", + output: "let greet = 'hello';\n\nconsole.log(greet);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: "const greet = 'hello';\nconsole.log(greet);", + output: "const greet = 'hello';\n\nconsole.log(greet);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: "function example() {\nvar greet = 'hello';\nconsole.log(greet);\n}", + output: + "function example() {\nvar greet = 'hello';\n\nconsole.log(greet);\n}", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: "var f = function() {\nvar greet = 'hello';\nconsole.log(greet);\n};", + output: + "var f = function() {\nvar greet = 'hello';\n\nconsole.log(greet);\n};", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: "() => {\nvar greet = 'hello';\nconsole.log(greet);\n}", + output: "() => {\nvar greet = 'hello';\n\nconsole.log(greet);\n}", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + // should disallow blank lines in "never" mode + { + code: "var greet = 'hello';\n\nconsole.log(greet);", + output: "var greet = 'hello';\nconsole.log(greet);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: "var greet = 'hello';\n\n\nconsole.log(greet);", + output: "var greet = 'hello';\nconsole.log(greet);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: "var greet = 'hello';\n\n\n\nconsole.log(greet);", + output: "var greet = 'hello';\nconsole.log(greet);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: "var greet = 'hello'; \n\nconsole.log(greet);", + output: "var greet = 'hello'; \nconsole.log(greet);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: "var greet = 'hello'; // inline comment\n\nconsole.log(greet);", + output: "var greet = 'hello'; // inline comment\nconsole.log(greet);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: "var greet = 'hello';\nvar name = 'world';\n\nconsole.log(greet, name);", + output: + "var greet = 'hello';\nvar name = 'world';\nconsole.log(greet, name);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: "var greet = 'hello', name = 'world';\n\nconsole.log(greet, name);", + output: "var greet = 'hello', name = 'world';\nconsole.log(greet, name);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: "var greet = 'hello',\nname = 'world';\n\nconsole.log(greet, name);", + output: + "var greet = 'hello',\nname = 'world';\nconsole.log(greet, name);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: "var greet = 'hello', // inline comment\nname = 'world'; // inline comment\n\nconsole.log(greet, name);", + output: + "var greet = 'hello', // inline comment\nname = 'world'; // inline comment\nconsole.log(greet, name);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: "let greet = 'hello';\n\nconsole.log(greet);", + output: "let greet = 'hello';\nconsole.log(greet);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: "const greet = 'hello';\n\nconsole.log(greet);", + output: "const greet = 'hello';\nconsole.log(greet);", + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + + // should disallow a comment on the next line that's not in turn followed by a blank in "always" mode + { + code: "var greet = 'hello';\n// next-line comment\nconsole.log(greet);", + output: + "var greet = 'hello';\n\n// next-line comment\nconsole.log(greet);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: "var greet = 'hello';\n/* block comment\nblock comment */\nconsole.log(greet);", + output: + "var greet = 'hello';\n\n/* block comment\nblock comment */\nconsole.log(greet);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: "var greet = 'hello',\nname = 'world';\n// next-line comment\nconsole.log(greet);", + output: + "var greet = 'hello',\nname = 'world';\n\n// next-line comment\nconsole.log(greet);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: "var greet = 'hello',\nname = 'world';\n/* block comment\nblock comment */\nconsole.log(greet);", + output: + "var greet = 'hello',\nname = 'world';\n\n/* block comment\nblock comment */\nconsole.log(greet);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: "var greet = 'hello';\n// next-line comment\n// second-line comment\nconsole.log(greet);", + output: + "var greet = 'hello';\n\n// next-line comment\n// second-line comment\nconsole.log(greet);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: "var greet = 'hello';\n// next-line comment\n/* block comment\nblock comment */\nconsole.log(greet);", + output: + "var greet = 'hello';\n\n// next-line comment\n/* block comment\nblock comment */\nconsole.log(greet);", + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + // https://github.com/eslint/eslint/issues/6834 + { + code: ` +var a = 1 +;(b || c).doSomething() + `, + output: ` +var a = 1 + +;(b || c).doSomething() + `, + options: [ + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: ` +var a = 1 + +;(b || c).doSomething() + `, + output: ` +var a = 1 +;(b || c).doSomething() + `, + options: [ + { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // Tests from newline-before-return + //---------------------------------------------------------------------- + + { + code: 'function a() {\nvar b; return;\n}', + output: 'function a() {\nvar b;\n\n return;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nvar b;\nreturn;\n}', + output: 'function a() {\nvar b;\n\nreturn;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nif (b) return b;\nelse if (c) return c;\nelse {\ne();\nreturn d;\n}\n}', + output: + 'function a() {\nif (b) return b;\nelse if (c) return c;\nelse {\ne();\n\nreturn d;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nif (b) return b;\nelse if (c) return c;\nelse {\ne(); return d;\n}\n}', + output: + 'function a() {\nif (b) return b;\nelse if (c) return c;\nelse {\ne();\n\n return d;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\n while (b) {\nc();\nreturn;\n}\n}', + output: 'function a() {\n while (b) {\nc();\n\nreturn;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\ndo {\nc();\nreturn;\n} while (b);\n}', + output: 'function a() {\ndo {\nc();\n\nreturn;\n} while (b);\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nfor (var b; b < c; b++) {\nc();\nreturn;\n}\n}', + output: + 'function a() {\nfor (var b; b < c; b++) {\nc();\n\nreturn;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nfor (b in c) {\nd();\nreturn;\n}\n}', + output: 'function a() {\nfor (b in c) {\nd();\n\nreturn;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nfor (b of c) {\nd();\nreturn;\n}\n}', + output: 'function a() {\nfor (b of c) {\nd();\n\nreturn;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nif (b) {\nc();\n}\n//comment\nreturn b;\n}', + output: 'function a() {\nif (b) {\nc();\n}\n\n//comment\nreturn b;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\n/*comment\ncomment*/\nif (b) {\nc();\nreturn b;\n} else {\n//comment\n\nreturn d;\n}\n/*multi-line\ncomment*/\nreturn e;\n}', + output: + 'function a() {\n/*comment\ncomment*/\nif (b) {\nc();\n\nreturn b;\n} else {\n//comment\n\nreturn d;\n}\n\n/*multi-line\ncomment*/\nreturn e;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [ + { messageId: 'expectedBlankLine' }, + { messageId: 'expectedBlankLine' }, + ], + }, + { + code: 'function a() {\nif (b) { return; } //comment\nreturn c;\n}', + output: 'function a() {\nif (b) { return; } //comment\n\nreturn c;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nif (b) { return; } /*multi-line\ncomment*/\nreturn c;\n}', + output: + 'function a() {\nif (b) { return; } /*multi-line\ncomment*/\n\nreturn c;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nif (b) { return; }\n/*multi-line\ncomment*/ return c;\n}', + output: + 'function a() {\nif (b) { return; }\n\n/*multi-line\ncomment*/ return c;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nif (b) { return; } /*multi-line\ncomment*/ return c;\n}', + output: + 'function a() {\nif (b) { return; } /*multi-line\ncomment*/\n\n return c;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'var a;\nreturn;', + output: 'var a;\n\nreturn;', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + parserOptions: { ecmaFeatures: { globalReturn: true } }, + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'var a; return;', + output: 'var a;\n\n return;', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + parserOptions: { ecmaFeatures: { globalReturn: true } }, + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\n{\n//comment\n}\nreturn\n}', + output: 'function a() {\n{\n//comment\n}\n\nreturn\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\n{\n//comment\n} return\n}', + output: 'function a() {\n{\n//comment\n}\n\n return\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nvar c;\nwhile (b) {\n c = d; //comment\n}\nreturn c;\n}', + output: + 'function a() {\nvar c;\nwhile (b) {\n c = d; //comment\n}\n\nreturn c;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nfor (var b; b < c; b++) {\nif (d) {\nbreak; //comment\n}\nreturn;\n}\n}', + output: + 'function a() {\nfor (var b; b < c; b++) {\nif (d) {\nbreak; //comment\n}\n\nreturn;\n}\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nvar b; /*multi-line\ncomment*/\nreturn c;\n}', + output: 'function a() {\nvar b; /*multi-line\ncomment*/\n\nreturn c;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nvar b;\n/*multi-line\ncomment*/ return c;\n}', + output: 'function a() {\nvar b;\n\n/*multi-line\ncomment*/ return c;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nvar b; /*multi-line\ncomment*/ return c;\n}', + output: 'function a() {\nvar b; /*multi-line\ncomment*/\n\n return c;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nvar b;\n//comment\nreturn;\n}', + output: 'function a() {\nvar b;\n\n//comment\nreturn;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nvar b; //comment\nreturn;\n}', + output: 'function a() {\nvar b; //comment\n\nreturn;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nvar b;\n/* comment */ return;\n}', + output: 'function a() {\nvar b;\n\n/* comment */ return;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nvar b;\n//comment\n/* comment */ return;\n}', + output: 'function a() {\nvar b;\n\n//comment\n/* comment */ return;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nvar b; /* comment */ return;\n}', + output: 'function a() {\nvar b; /* comment */\n\n return;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nvar b; /* comment */\nreturn;\n}', + output: 'function a() {\nvar b; /* comment */\n\nreturn;\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nvar b;\nreturn; //comment\n}', + output: 'function a() {\nvar b;\n\nreturn; //comment\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function a() {\nvar b; return; //comment\n}', + output: 'function a() {\nvar b;\n\n return; //comment\n}', + options: [{ blankLine: 'always', prev: '*', next: 'return' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // From JSCS disallowPaddingNewLinesAfterBlocks + // https://github.com/jscs-dev/node-jscs/blob/44f9b86eb0757fd4ca05a81a50450c5f1b25c37b/test/specs/rules/disallow-padding-newlines-after-blocks.js + //---------------------------------------------------------------------- + + { + code: 'if(true){}\n\nvar a = 2;', + output: 'if(true){}\nvar a = 2;', + options: [{ blankLine: 'never', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'if(true){\nif(true) {}\n\nvar a = 2;}', + output: 'if(true){\nif(true) {}\nvar a = 2;}', + options: [{ blankLine: 'never', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: '(function(){\n})()\n\nvar a = 2;', + output: '(function(){\n})()\nvar a = 2;', + options: [{ blankLine: 'never', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: '+(function(){\n})()\n\nvar a = 2;', + output: '+(function(){\n})()\nvar a = 2;', + options: [{ blankLine: 'never', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'var a = function() {};\n\nvar b = 2;', + output: 'var a = function() {};\nvar b = 2;', + options: [{ blankLine: 'never', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // From JSCS disallowPaddingNewLinesBeforeExport + // https://github.com/jscs-dev/node-jscs/blob/44f9b86eb0757fd4ca05a81a50450c5f1b25c37b/test/specs/rules/disallow-padding-newlines-before-export.js + //---------------------------------------------------------------------- + + { + code: 'var a = 2;\n\nmodule.exports = a;', + output: 'var a = 2;\nmodule.exports = a;', + options: [{ blankLine: 'never', prev: '*', next: 'exports' }], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // From JSCS disallowPaddingNewLinesBeforeExport + // https://github.com/jscs-dev/node-jscs/blob/44f9b86eb0757fd4ca05a81a50450c5f1b25c37b/test/specs/rules/disallow-padding-newlines-before-keywords.js + //---------------------------------------------------------------------- + + { + code: 'function x() { var a;\n\nreturn; }', + output: 'function x() { var a;\nreturn; }', + options: [ + { + blankLine: 'never', + prev: '*', + next: ['if', 'for', 'return', 'switch', 'case', 'break', 'throw'], + }, + ], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'function x() { var a = true;\n\nif (a) { a = !a; }; }', + output: 'function x() { var a = true;\nif (a) { a = !a; }; }', + options: [ + { + blankLine: 'never', + prev: '*', + next: ['if', 'for', 'return', 'switch', 'case', 'break', 'throw'], + }, + ], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'function x() { var a = true;\n\nfor (var i = 0; i < 10; i++) { a = !a; }; }', + output: + 'function x() { var a = true;\nfor (var i = 0; i < 10; i++) { a = !a; }; }', + options: [ + { + blankLine: 'never', + prev: '*', + next: ['if', 'for', 'return', 'switch', 'case', 'break', 'throw'], + }, + ], + errors: [{ messageId: 'unexpectedBlankLine' }], + }, + { + code: 'function x() { var y = true;\n\nswitch ("Oranges") { case "Oranges": y = !y;\n\nbreak;\n\ncase "Apples": y = !y;\n\nbreak; default: y = !y; } }', + output: + 'function x() { var y = true;\nswitch ("Oranges") { case "Oranges": y = !y;\nbreak;\ncase "Apples": y = !y;\nbreak; default: y = !y; } }', + options: [ + { + blankLine: 'never', + prev: '*', + next: ['if', 'for', 'return', 'switch', 'case', 'break', 'throw'], + }, + ], + errors: [ + { messageId: 'unexpectedBlankLine' }, + { messageId: 'unexpectedBlankLine' }, + { messageId: 'unexpectedBlankLine' }, + { messageId: 'unexpectedBlankLine' }, + ], + }, + { + code: 'function x() {try { var a;\n\nthrow 0; } catch (e) { var b = 0;\n\nthrow e; } }', + output: + 'function x() {try { var a;\nthrow 0; } catch (e) { var b = 0;\nthrow e; } }', + options: [ + { + blankLine: 'never', + prev: '*', + next: ['if', 'for', 'return', 'switch', 'case', 'break', 'throw'], + }, + ], + errors: [ + { messageId: 'unexpectedBlankLine' }, + { messageId: 'unexpectedBlankLine' }, + ], + }, + { + code: 'function x(a) { var b = 0;\n\nif (!a) { return false; };\n\nfor (var i = 0; i < b; i++) { if (!a[i]) return false; }\n\nreturn true; }', + output: + 'function x(a) { var b = 0;\nif (!a) { return false; };\nfor (var i = 0; i < b; i++) { if (!a[i]) return false; }\nreturn true; }', + options: [ + { + blankLine: 'never', + prev: '*', + next: ['if', 'for', 'return', 'switch', 'case', 'break', 'throw'], + }, + ], + errors: [ + { messageId: 'unexpectedBlankLine' }, + { messageId: 'unexpectedBlankLine' }, + { messageId: 'unexpectedBlankLine' }, + ], + }, + + //---------------------------------------------------------------------- + // From JSCS requirePaddingNewLinesAfterBlocks + // https://github.com/jscs-dev/node-jscs/blob/44f9b86eb0757fd4ca05a81a50450c5f1b25c37b/test/specs/rules/require-padding-newlines-after-blocks.js + //---------------------------------------------------------------------- + + { + code: 'if(true){}\nvar a = 2;', + output: 'if(true){}\n\nvar a = 2;', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'var a = function() {\n};\nvar b = 2;', + output: 'var a = function() {\n};\n\nvar b = 2;', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'if(true){\nif(true) {}\nvar a = 2;}', + output: 'if(true){\nif(true) {}\n\nvar a = 2;}', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: '(function(){\n})()\nvar a = 2;', + output: '(function(){\n})()\n\nvar a = 2;', + options: [{ blankLine: 'always', prev: 'block-like', next: '*' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'var a = function() {\n};\nvar b = 2;', + output: 'var a = function() {\n};\n\nvar b = 2;', + options: [ + { blankLine: 'always', prev: 'multiline-block-like', next: '*' }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: '(function(){\n})()\nvar a = 2;', + output: '(function(){\n})()\n\nvar a = 2;', + options: [ + { blankLine: 'always', prev: 'multiline-block-like', next: '*' }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // From JSCS requirePaddingNewLinesBeforeExport + // https://github.com/jscs-dev/node-jscs/blob/44f9b86eb0757fd4ca05a81a50450c5f1b25c37b/test/specs/rules/require-padding-newlines-before-export.js + //---------------------------------------------------------------------- + + { + code: 'var a = 2;\nmodule.exports = a;', + output: 'var a = 2;\n\nmodule.exports = a;', + options: [{ blankLine: 'always', prev: '*', next: 'exports' }], + errors: [{ messageId: 'expectedBlankLine' }], + }, + + //---------------------------------------------------------------------- + // From JSCS requirePaddingNewlinesBeforeKeywords + // https://github.com/jscs-dev/node-jscs/blob/44f9b86eb0757fd4ca05a81a50450c5f1b25c37b/test/specs/rules/require-padding-newlines-before-keywords.js + //---------------------------------------------------------------------- + + { + code: 'function x() { var a; return; }', + output: 'function x() { var a;\n\n return; }', + options: [ + { + blankLine: 'always', + prev: '*', + next: [ + 'if', + 'for', + 'return', + 'switch', + 'case', + 'break', + 'throw', + 'while', + 'default', + ], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function x() { var a = true; for (var i = 0; i < 10; i++) { a = !a; }; }', + output: + 'function x() { var a = true;\n\n for (var i = 0; i < 10; i++) { a = !a; }; }', + options: [ + { + blankLine: 'always', + prev: '*', + next: [ + 'if', + 'for', + 'return', + 'switch', + 'case', + 'break', + 'throw', + 'while', + 'default', + ], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function x() { var y = true; switch ("Oranges") { case "Oranges": y = !y; break; case "Apples": y = !y; break; default: y = !y; } }', + output: + 'function x() { var y = true;\n\n switch ("Oranges") { case "Oranges": y = !y;\n\n break;\n\n case "Apples": y = !y;\n\n break;\n\n default: y = !y; } }', + options: [ + { + blankLine: 'always', + prev: '*', + next: [ + 'if', + 'for', + 'return', + 'switch', + 'case', + 'break', + 'throw', + 'while', + 'default', + ], + }, + ], + errors: [ + { messageId: 'expectedBlankLine' }, + { messageId: 'expectedBlankLine' }, + { messageId: 'expectedBlankLine' }, + { messageId: 'expectedBlankLine' }, + { messageId: 'expectedBlankLine' }, + ], + }, + { + code: 'function x() { var a = true; while (!a) { a = !a; }; }', + output: 'function x() { var a = true;\n\n while (!a) { a = !a; }; }', + options: [ + { + blankLine: 'always', + prev: '*', + next: [ + 'if', + 'for', + 'return', + 'switch', + 'case', + 'break', + 'throw', + 'while', + 'default', + ], + }, + ], + errors: [{ messageId: 'expectedBlankLine' }], + }, + { + code: 'function x() {try { var a; throw 0; } catch (e) { var b = 0; throw e; } }', + output: + 'function x() {try { var a;\n\n throw 0; } catch (e) { var b = 0;\n\n throw e; } }', + options: [ + { + blankLine: 'always', + prev: '*', + next: [ + 'if', + 'for', + 'return', + 'switch', + 'case', + 'break', + 'throw', + 'while', + 'default', + ], + }, + ], + errors: [ + { messageId: 'expectedBlankLine' }, + { messageId: 'expectedBlankLine' }, + ], + }, + { + code: 'function x(a) { var b = 0; if (!a) { return false; }; for (var i = 0; i < b; i++) { if (!a[i]) return false; } return true; }', + output: + 'function x(a) { var b = 0;\n\n if (!a) { return false; };\n\n for (var i = 0; i < b; i++) { if (!a[i]) return false; }\n\n return true; }', + options: [ + { + blankLine: 'always', + prev: '*', + next: [ + 'if', + 'for', + 'return', + 'switch', + 'case', + 'break', + 'throw', + 'while', + 'default', + ], + }, + ], + errors: [ + { messageId: 'expectedBlankLine' }, + { messageId: 'expectedBlankLine' }, + { messageId: 'expectedBlankLine' }, + ], + }, + ], +}); From ea40ab659351ae7cf7235ea063d42ac155b11e5f Mon Sep 17 00:00:00 2001 From: Jacob Bandes-Storch Date: Fri, 3 Sep 2021 10:41:35 -0700 Subject: [PATCH 09/19] feat(eslint-plugin): add `no-meaningless-void-operator` rule (#3641) --- packages/eslint-plugin/README.md | 1 + .../rules/no-meaningless-void-operator.md | 50 +++++++++ packages/eslint-plugin/src/configs/all.ts | 1 + packages/eslint-plugin/src/rules/index.ts | 2 + .../src/rules/no-meaningless-void-operator.ts | 100 ++++++++++++++++++ .../no-meaningless-void-operator.test.ts | 90 ++++++++++++++++ 6 files changed, 244 insertions(+) create mode 100644 packages/eslint-plugin/docs/rules/no-meaningless-void-operator.md create mode 100644 packages/eslint-plugin/src/rules/no-meaningless-void-operator.ts create mode 100644 packages/eslint-plugin/tests/rules/no-meaningless-void-operator.test.ts diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index a60d885093f..5b32c4ef29e 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -128,6 +128,7 @@ Pro Tip: For larger codebases you may want to consider splitting our linting int | [`@typescript-eslint/no-implicit-any-catch`](./docs/rules/no-implicit-any-catch.md) | Disallow usage of the implicit `any` type in catch clauses | | :wrench: | | | [`@typescript-eslint/no-inferrable-types`](./docs/rules/no-inferrable-types.md) | Disallows explicit type declarations for variables or parameters initialized to a number, string, or boolean | :white_check_mark: | :wrench: | | | [`@typescript-eslint/no-invalid-void-type`](./docs/rules/no-invalid-void-type.md) | Disallows usage of `void` type outside of generic or return types | | | | +| [`@typescript-eslint/no-meaningless-void-operator`](./docs/rules/no-meaningless-void-operator.md) | Disallow the `void` operator except when used to discard a value | | :wrench: | :thought_balloon: | | [`@typescript-eslint/no-misused-new`](./docs/rules/no-misused-new.md) | Enforce valid definition of `new` and `constructor` | :white_check_mark: | | | | [`@typescript-eslint/no-misused-promises`](./docs/rules/no-misused-promises.md) | Avoid using promises in places not designed to handle them | :white_check_mark: | | :thought_balloon: | | [`@typescript-eslint/no-namespace`](./docs/rules/no-namespace.md) | Disallow the use of custom TypeScript modules and namespaces | :white_check_mark: | | | diff --git a/packages/eslint-plugin/docs/rules/no-meaningless-void-operator.md b/packages/eslint-plugin/docs/rules/no-meaningless-void-operator.md new file mode 100644 index 00000000000..4aa69e5714b --- /dev/null +++ b/packages/eslint-plugin/docs/rules/no-meaningless-void-operator.md @@ -0,0 +1,50 @@ +# Disallow the `void` operator except when used to discard a value (`no-meaningless-void-operator`) + +Disallow the `void` operator when its argument is already of type `void` or `undefined`. + +## Rule Details + +The `void` operator is a useful tool to convey the programmer's intent to discard a value. For example, it is recommended as one way of suppressing [`@typescript-eslint/no-floating-promises`](./no-floating-promises.md) instead of adding `.catch()` to a promise. + +This rule helps an author catch API changes where previously a value was being discarded at a call site, but the callee changed so it no longer returns a value. When combined with [no-unused-expressions](https://eslint.org/docs/rules/no-unused-expressions), it also helps _readers_ of the code by ensuring consistency: a statement that looks like `void foo();` is **always** discarding a return value, and a statement that looks like `foo();` is **never** discarding a return value. + +Examples of **incorrect** code for this rule: + +```ts +void (() => {})(); + +function foo() {} +void foo(); +``` + +Examples of **correct** code for this rule: + +```ts +(() => {})(); + +function foo() {} +foo(); // nothing to discard + +function bar(x: number) { + void x; // discarding a number + return 2; +} +void bar(); // discarding a number +``` + +### Options + +This rule accepts a single object option with the following default configuration: + +```json +{ + "@typescript-eslint/no-meaningless-void-operator": [ + "error", + { + "checkNever": false + } + ] +} +``` + +- `checkNever: true` will suggest removing `void` when the argument has type `never`. diff --git a/packages/eslint-plugin/src/configs/all.ts b/packages/eslint-plugin/src/configs/all.ts index 4d94a83fa59..9d7fde81314 100644 --- a/packages/eslint-plugin/src/configs/all.ts +++ b/packages/eslint-plugin/src/configs/all.ts @@ -78,6 +78,7 @@ export = { '@typescript-eslint/no-loss-of-precision': 'error', 'no-magic-numbers': 'off', '@typescript-eslint/no-magic-numbers': 'error', + '@typescript-eslint/no-meaningless-void-operator': 'error', '@typescript-eslint/no-misused-new': 'error', '@typescript-eslint/no-misused-promises': 'error', '@typescript-eslint/no-namespace': 'error', diff --git a/packages/eslint-plugin/src/rules/index.ts b/packages/eslint-plugin/src/rules/index.ts index 54dd9c24ac3..1f6aa56c7cb 100644 --- a/packages/eslint-plugin/src/rules/index.ts +++ b/packages/eslint-plugin/src/rules/index.ts @@ -50,6 +50,7 @@ import noInvalidVoidType from './no-invalid-void-type'; import noLoopFunc from './no-loop-func'; import noLossOfPrecision from './no-loss-of-precision'; import noMagicNumbers from './no-magic-numbers'; +import noMeaninglessVoidOperator from './no-meaningless-void-operator'; import noMisusedNew from './no-misused-new'; import noMisusedPromises from './no-misused-promises'; import noNamespace from './no-namespace'; @@ -170,6 +171,7 @@ export default { 'no-loop-func': noLoopFunc, 'no-loss-of-precision': noLossOfPrecision, 'no-magic-numbers': noMagicNumbers, + 'no-meaningless-void-operator': noMeaninglessVoidOperator, 'no-misused-new': noMisusedNew, 'no-misused-promises': noMisusedPromises, 'no-namespace': noNamespace, diff --git a/packages/eslint-plugin/src/rules/no-meaningless-void-operator.ts b/packages/eslint-plugin/src/rules/no-meaningless-void-operator.ts new file mode 100644 index 00000000000..3640cb34630 --- /dev/null +++ b/packages/eslint-plugin/src/rules/no-meaningless-void-operator.ts @@ -0,0 +1,100 @@ +import { + ESLintUtils, + TSESLint, + TSESTree, +} from '@typescript-eslint/experimental-utils'; +import * as tsutils from 'tsutils'; +import * as util from '../util'; +import * as ts from 'typescript'; + +type Options = [ + { + checkNever: boolean; + }, +]; + +export default util.createRule< + Options, + 'meaninglessVoidOperator' | 'removeVoid' +>({ + name: 'no-meaningless-void-operator', + meta: { + type: 'suggestion', + docs: { + description: + 'Disallow the `void` operator except when used to discard a value', + category: 'Best Practices', + recommended: false, + suggestion: true, + requiresTypeChecking: true, + }, + fixable: 'code', + messages: { + meaninglessVoidOperator: + "void operator shouldn't be used on {{type}}; it should convey that a return value is being ignored", + removeVoid: "Remove 'void'", + }, + schema: [ + { + type: 'object', + properties: { + checkNever: { + type: 'boolean', + default: false, + }, + }, + additionalProperties: false, + }, + ], + }, + defaultOptions: [{ checkNever: false }], + + create(context, [{ checkNever }]) { + const parserServices = ESLintUtils.getParserServices(context); + const checker = parserServices.program.getTypeChecker(); + const sourceCode = context.getSourceCode(); + + return { + 'UnaryExpression[operator="void"]'(node: TSESTree.UnaryExpression): void { + const fix = (fixer: TSESLint.RuleFixer): TSESLint.RuleFix => { + return fixer.removeRange([ + sourceCode.getTokens(node)[0].range[0], + sourceCode.getTokens(node)[1].range[0], + ]); + }; + + const argTsNode = parserServices.esTreeNodeToTSNodeMap.get( + node.argument, + ); + const argType = checker.getTypeAtLocation(argTsNode); + const unionParts = tsutils.unionTypeParts(argType); + if ( + unionParts.every( + part => part.flags & (ts.TypeFlags.Void | ts.TypeFlags.Undefined), + ) + ) { + context.report({ + node, + messageId: 'meaninglessVoidOperator', + data: { type: checker.typeToString(argType) }, + fix, + }); + } else if ( + checkNever && + unionParts.every( + part => + part.flags & + (ts.TypeFlags.Void | ts.TypeFlags.Undefined | ts.TypeFlags.Never), + ) + ) { + context.report({ + node, + messageId: 'meaninglessVoidOperator', + data: { type: checker.typeToString(argType) }, + suggest: [{ messageId: 'removeVoid', fix }], + }); + } + }, + }; + }, +}); diff --git a/packages/eslint-plugin/tests/rules/no-meaningless-void-operator.test.ts b/packages/eslint-plugin/tests/rules/no-meaningless-void-operator.test.ts new file mode 100644 index 00000000000..5e034f2904b --- /dev/null +++ b/packages/eslint-plugin/tests/rules/no-meaningless-void-operator.test.ts @@ -0,0 +1,90 @@ +import rule from '../../src/rules/no-meaningless-void-operator'; +import { RuleTester, getFixturesRootDir } from '../RuleTester'; + +const rootDir = getFixturesRootDir(); + +const ruleTester = new RuleTester({ + parserOptions: { + ecmaVersion: 2018, + tsconfigRootDir: rootDir, + project: './tsconfig.json', + }, + parser: '@typescript-eslint/parser', +}); + +ruleTester.run('no-meaningless-void-operator', rule, { + valid: [ + ` +(() => {})(); + +function foo() {} +foo(); // nothing to discard + +function bar(x: number) { + void x; + return 2; +} +void bar(); // discarding a number + `, + ` +function bar(x: never) { + void x; +} + `, + ], + invalid: [ + { + code: 'void (() => {})();', + output: '(() => {})();', + errors: [ + { + messageId: 'meaninglessVoidOperator', + line: 1, + column: 1, + }, + ], + }, + { + code: ` +function foo() {} +void foo(); + `, + output: ` +function foo() {} +foo(); + `, + errors: [ + { + messageId: 'meaninglessVoidOperator', + line: 3, + column: 1, + }, + ], + }, + { + options: [{ checkNever: true }], + code: ` +function bar(x: never) { + void x; +} + `.trimRight(), + errors: [ + { + messageId: 'meaninglessVoidOperator', + line: 3, + column: 3, + suggestions: [ + { + messageId: 'removeVoid', + output: ` +function bar(x: never) { + x; +} + `.trimRight(), + }, + ], + }, + ], + }, + ], +}); From 4bfa4375aff8f65057d4aa116e435803cbc6b464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20De=20Boey?= Date: Fri, 3 Sep 2021 19:43:05 +0200 Subject: [PATCH 10/19] feat(experimental-utils): extract `isNodeOfType` out of `ast-utils`' `predicates` (#3677) --- .../src/ast-utils/predicates.ts | 37 ++++++------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/packages/experimental-utils/src/ast-utils/predicates.ts b/packages/experimental-utils/src/ast-utils/predicates.ts index 919820d7653..7a7bcf520b1 100644 --- a/packages/experimental-utils/src/ast-utils/predicates.ts +++ b/packages/experimental-utils/src/ast-utils/predicates.ts @@ -1,5 +1,12 @@ import { AST_NODE_TYPES, AST_TOKEN_TYPES, TSESTree } from '../ts-estree'; +const isNodeOfType = + (nodeType: NodeType) => + ( + node: TSESTree.Node | null | undefined, + ): node is TSESTree.Node & { type: NodeType } => + node?.type === nodeType; + function isOptionalChainPunctuator( token: TSESTree.Token, ): token is TSESTree.PunctuatorToken & { value: '?.' } { @@ -69,11 +76,7 @@ function isTypeAssertion( ); } -function isVariableDeclarator( - node: TSESTree.Node | undefined, -): node is TSESTree.VariableDeclarator { - return node?.type === AST_NODE_TYPES.VariableDeclarator; -} +const isVariableDeclarator = isNodeOfType(AST_NODE_TYPES.VariableDeclarator); function isFunction( node: TSESTree.Node | undefined, @@ -130,17 +133,9 @@ function isFunctionOrFunctionType( return isFunction(node) || isFunctionType(node); } -function isTSFunctionType( - node: TSESTree.Node | undefined, -): node is TSESTree.TSFunctionType { - return node?.type === AST_NODE_TYPES.TSFunctionType; -} +const isTSFunctionType = isNodeOfType(AST_NODE_TYPES.TSFunctionType); -function isTSConstructorType( - node: TSESTree.Node | undefined, -): node is TSESTree.TSConstructorType { - return node?.type === AST_NODE_TYPES.TSConstructorType; -} +const isTSConstructorType = isNodeOfType(AST_NODE_TYPES.TSConstructorType); function isClassOrTypeElement( node: TSESTree.Node | undefined, @@ -193,20 +188,12 @@ function isSetter( ); } -function isIdentifier( - node: TSESTree.Node | undefined, -): node is TSESTree.Identifier { - return node?.type === AST_NODE_TYPES.Identifier; -} +const isIdentifier = isNodeOfType(AST_NODE_TYPES.Identifier); /** * Checks if a node represents an `await …` expression. */ -function isAwaitExpression( - node: TSESTree.Node | undefined | null, -): node is TSESTree.AwaitExpression { - return node?.type === AST_NODE_TYPES.AwaitExpression; -} +const isAwaitExpression = isNodeOfType(AST_NODE_TYPES.AwaitExpression); /** * Checks if a possible token is the `await` keyword. From 363b3dc4dd0dc343311c729d75935b10f9d2fd5e Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Fri, 3 Sep 2021 20:44:40 +0300 Subject: [PATCH 11/19] feat(eslint-plugin): [restrict-template-expressions] add option to allow RegExp (#3709) --- .../rules/restrict-template-expressions.md | 17 ++++ .../rules/restrict-template-expressions.ts | 9 +++ .../restrict-template-expressions.test.ts | 79 ++++++++++++++++++- 3 files changed, 103 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/restrict-template-expressions.md b/packages/eslint-plugin/docs/rules/restrict-template-expressions.md index 0ee7427ddac..e567b6571b6 100644 --- a/packages/eslint-plugin/docs/rules/restrict-template-expressions.md +++ b/packages/eslint-plugin/docs/rules/restrict-template-expressions.md @@ -35,6 +35,8 @@ type Options = { allowAny?: boolean; // if true, also allow null and undefined in template expressions allowNullish?: boolean; + // if true, also allow RegExp in template expressions + allowRegExp?: boolean; }; const defaults = { @@ -42,6 +44,7 @@ const defaults = { allowBoolean: false, allowAny: false, allowNullish: false, + allowRegExp: false, }; ``` @@ -83,3 +86,17 @@ Examples of additional **correct** code for this rule with `{ allowNullish: true const arg = condition ? 'ok' : null; const msg1 = `arg = ${arg}`; ``` + +### `allowRegExp` + +Examples of additional **correct** code for this rule with `{ allowRegExp: true }`: + +```ts +const arg = new RegExp('foo'); +const msg1 = `arg = ${arg}`; +``` + +```ts +const arg = /foo/; +const msg1 = `arg = ${arg}`; +``` diff --git a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts index a4756266ffc..b20bd5c62bc 100644 --- a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts +++ b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts @@ -11,6 +11,7 @@ type Options = [ allowBoolean?: boolean; allowAny?: boolean; allowNullish?: boolean; + allowRegExp?: boolean; }, ]; @@ -37,6 +38,7 @@ export default util.createRule({ allowBoolean: { type: 'boolean' }, allowAny: { type: 'boolean' }, allowNullish: { type: 'boolean' }, + allowRegExp: { type: 'boolean' }, }, }, ], @@ -76,6 +78,13 @@ export default util.createRule({ return true; } + if ( + options.allowRegExp && + util.getTypeName(typeChecker, type) === 'RegExp' + ) { + return true; + } + if ( options.allowNullish && util.isTypeFlagSet(type, ts.TypeFlags.Null | ts.TypeFlags.Undefined) diff --git a/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts b/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts index df5d5aefb25..fea8b82501a 100644 --- a/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts +++ b/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts @@ -189,11 +189,56 @@ ruleTester.run('restrict-template-expressions', rule, { } `, }, + // allowRegExp + { + options: [{ allowRegExp: true }], + code: ` + const arg = new RegExp('foo'); + const msg = \`arg = \${arg}\`; + `, + }, + { + options: [{ allowRegExp: true }], + code: ` + const arg = /foo/; + const msg = \`arg = \${arg}\`; + `, + }, + { + options: [{ allowRegExp: true }], + code: ` + declare const arg: string | RegExp; + const msg = \`arg = \${arg}\`; + `, + }, + { + options: [{ allowRegExp: true }], + code: ` + function test(arg: T) { + return \`arg = \${arg}\`; + } + `, + }, + { + options: [{ allowRegExp: true }], + code: ` + function test(arg: T) { + return \`arg = \${arg}\`; + } + `, + }, // allow ALL { - options: [{ allowNumber: true, allowBoolean: true, allowNullish: true }], + options: [ + { + allowNumber: true, + allowBoolean: true, + allowNullish: true, + allowRegExp: true, + }, + ], code: ` - type All = string | number | boolean | null | undefined; + type All = string | number | boolean | null | undefined | RegExp; function test(arg: T) { return \`arg = \${arg}\`; } @@ -338,6 +383,36 @@ ruleTester.run('restrict-template-expressions', rule, { }, ], }, + { + options: [{ allowRegExp: false }], + code: ` + const arg = new RegExp('foo'); + const msg = \`arg = \${arg}\`; + `, + errors: [ + { + messageId: 'invalidType', + data: { type: 'RegExp' }, + line: 3, + column: 30, + }, + ], + }, + { + options: [{ allowRegExp: false }], + code: ` + const arg = /foo/; + const msg = \`arg = \${arg}\`; + `, + errors: [ + { + messageId: 'invalidType', + data: { type: 'RegExp' }, + line: 3, + column: 30, + }, + ], + }, // TS 3.9 change { options: [{ allowAny: true }], From a46e3182c8a0b07c914605d6d9fe28ef36a7c32a Mon Sep 17 00:00:00 2001 From: Rebecca Stevens Date: Sat, 4 Sep 2021 05:46:35 +1200 Subject: [PATCH 12/19] feat(eslint-plugin): [prefer-readonly-parameter-types] add option treatMethodsAsReadonly (#3733) --- .../rules/prefer-readonly-parameter-types.md | 41 +++++++++ .../rules/prefer-readonly-parameter-types.ts | 12 ++- .../eslint-plugin/src/util/isTypeReadonly.ts | 68 +++++++++++++-- .../prefer-readonly-parameter-types.test.ts | 86 +++++++++++++++++++ 4 files changed, 196 insertions(+), 11 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/prefer-readonly-parameter-types.md b/packages/eslint-plugin/docs/rules/prefer-readonly-parameter-types.md index 34544456f09..3b6f1346d7c 100644 --- a/packages/eslint-plugin/docs/rules/prefer-readonly-parameter-types.md +++ b/packages/eslint-plugin/docs/rules/prefer-readonly-parameter-types.md @@ -130,6 +130,7 @@ interface Options { const defaultOptions: Options = { checkParameterProperties: true, ignoreInferredTypes: false, + treatMethodsAsReadonly: false, }; ``` @@ -214,3 +215,43 @@ export const acceptsCallback: AcceptsCallback; ``` + +### `treatMethodsAsReadonly` + +This option allows you to treat all mutable methods as though they were readonly. This may be desirable in when you are never reassigning methods. + +Examples of **incorrect** code for this rule with `{treatMethodsAsReadonly: false}`: + +```ts +type MyType = { + readonly prop: string; + method(): string; // note: this method is mutable +}; +function foo(arg: MyType) {} +``` + +Examples of **correct** code for this rule with `{treatMethodsAsReadonly: false}`: + +```ts +type MyType = Readonly<{ + prop: string; + method(): string; +}>; +function foo(arg: MyType) {} + +type MyOtherType = { + readonly prop: string; + readonly method: () => string; +}; +function bar(arg: MyOtherType) {} +``` + +Examples of **correct** code for this rule with `{treatMethodsAsReadonly: true}`: + +```ts +type MyType = { + readonly prop: string; + method(): string; // note: this method is mutable +}; +function foo(arg: MyType) {} +``` diff --git a/packages/eslint-plugin/src/rules/prefer-readonly-parameter-types.ts b/packages/eslint-plugin/src/rules/prefer-readonly-parameter-types.ts index a36020e93d3..fdf48395eae 100644 --- a/packages/eslint-plugin/src/rules/prefer-readonly-parameter-types.ts +++ b/packages/eslint-plugin/src/rules/prefer-readonly-parameter-types.ts @@ -8,7 +8,7 @@ type Options = [ { checkParameterProperties?: boolean; ignoreInferredTypes?: boolean; - }, + } & util.ReadonlynessOptions, ]; type MessageIds = 'shouldBeReadonly'; @@ -34,6 +34,7 @@ export default util.createRule({ ignoreInferredTypes: { type: 'boolean', }, + ...util.readonlynessOptionsSchema.properties, }, }, ], @@ -45,10 +46,13 @@ export default util.createRule({ { checkParameterProperties: true, ignoreInferredTypes: false, + ...util.readonlynessOptionsDefaults, }, ], create(context, options) { - const [{ checkParameterProperties, ignoreInferredTypes }] = options; + const [ + { checkParameterProperties, ignoreInferredTypes, treatMethodsAsReadonly }, + ] = options; const { esTreeNodeToTSNodeMap, program } = util.getParserServices(context); const checker = program.getTypeChecker(); @@ -94,7 +98,9 @@ export default util.createRule({ const tsNode = esTreeNodeToTSNodeMap.get(actualParam); const type = checker.getTypeAtLocation(tsNode); - const isReadOnly = util.isTypeReadonly(checker, type); + const isReadOnly = util.isTypeReadonly(checker, type, { + treatMethodsAsReadonly: treatMethodsAsReadonly!, + }); if (!isReadOnly) { context.report({ diff --git a/packages/eslint-plugin/src/util/isTypeReadonly.ts b/packages/eslint-plugin/src/util/isTypeReadonly.ts index 4a42c90c1e0..8b3efc27856 100644 --- a/packages/eslint-plugin/src/util/isTypeReadonly.ts +++ b/packages/eslint-plugin/src/util/isTypeReadonly.ts @@ -4,6 +4,7 @@ import { isUnionOrIntersectionType, unionTypeParts, isPropertyReadonlyInType, + isSymbolFlagSet, } from 'tsutils'; import * as ts from 'typescript'; import { getTypeOfPropertyOfType, nullThrows, NullThrowsReasons } from '.'; @@ -17,9 +18,32 @@ const enum Readonlyness { Readonly = 3, } +export interface ReadonlynessOptions { + readonly treatMethodsAsReadonly?: boolean; +} + +export const readonlynessOptionsSchema = { + type: 'object', + additionalProperties: false, + properties: { + treatMethodsAsReadonly: { + type: 'boolean', + }, + }, +}; + +export const readonlynessOptionsDefaults: ReadonlynessOptions = { + treatMethodsAsReadonly: false, +}; + +function hasSymbol(node: ts.Node): node is ts.Node & { symbol: ts.Symbol } { + return Object.prototype.hasOwnProperty.call(node, 'symbol'); +} + function isTypeReadonlyArrayOrTuple( checker: ts.TypeChecker, type: ts.Type, + options: ReadonlynessOptions, seenTypes: Set, ): Readonlyness { function checkTypeArguments(arrayType: ts.TypeReference): Readonlyness { @@ -40,7 +64,7 @@ function isTypeReadonlyArrayOrTuple( if ( typeArguments.some( typeArg => - isTypeReadonlyRecurser(checker, typeArg, seenTypes) === + isTypeReadonlyRecurser(checker, typeArg, options, seenTypes) === Readonlyness.Mutable, ) ) { @@ -76,6 +100,7 @@ function isTypeReadonlyArrayOrTuple( function isTypeReadonlyObject( checker: ts.TypeChecker, type: ts.Type, + options: ReadonlynessOptions, seenTypes: Set, ): Readonlyness { function checkIndexSignature(kind: ts.IndexKind): Readonlyness { @@ -93,7 +118,18 @@ function isTypeReadonlyObject( if (properties.length) { // ensure the properties are marked as readonly for (const property of properties) { - if (!isPropertyReadonlyInType(type, property.getEscapedName(), checker)) { + if ( + !( + isPropertyReadonlyInType(type, property.getEscapedName(), checker) || + (options.treatMethodsAsReadonly && + property.valueDeclaration !== undefined && + hasSymbol(property.valueDeclaration) && + isSymbolFlagSet( + property.valueDeclaration.symbol, + ts.SymbolFlags.Method, + )) + ) + ) { return Readonlyness.Mutable; } } @@ -117,7 +153,7 @@ function isTypeReadonlyObject( } if ( - isTypeReadonlyRecurser(checker, propertyType, seenTypes) === + isTypeReadonlyRecurser(checker, propertyType, options, seenTypes) === Readonlyness.Mutable ) { return Readonlyness.Mutable; @@ -142,6 +178,7 @@ function isTypeReadonlyObject( function isTypeReadonlyRecurser( checker: ts.TypeChecker, type: ts.Type, + options: ReadonlynessOptions, seenTypes: Set, ): Readonlyness.Readonly | Readonlyness.Mutable { seenTypes.add(type); @@ -149,7 +186,7 @@ function isTypeReadonlyRecurser( if (isUnionType(type)) { // all types in the union must be readonly const result = unionTypeParts(type).every(t => - isTypeReadonlyRecurser(checker, t, seenTypes), + isTypeReadonlyRecurser(checker, t, options, seenTypes), ); const readonlyness = result ? Readonlyness.Readonly : Readonlyness.Mutable; return readonlyness; @@ -169,12 +206,22 @@ function isTypeReadonlyRecurser( return Readonlyness.Readonly; } - const isReadonlyArray = isTypeReadonlyArrayOrTuple(checker, type, seenTypes); + const isReadonlyArray = isTypeReadonlyArrayOrTuple( + checker, + type, + options, + seenTypes, + ); if (isReadonlyArray !== Readonlyness.UnknownType) { return isReadonlyArray; } - const isReadonlyObject = isTypeReadonlyObject(checker, type, seenTypes); + const isReadonlyObject = isTypeReadonlyObject( + checker, + type, + options, + seenTypes, + ); /* istanbul ignore else */ if ( isReadonlyObject !== Readonlyness.UnknownType ) { @@ -187,9 +234,14 @@ function isTypeReadonlyRecurser( /** * Checks if the given type is readonly */ -function isTypeReadonly(checker: ts.TypeChecker, type: ts.Type): boolean { +function isTypeReadonly( + checker: ts.TypeChecker, + type: ts.Type, + options: ReadonlynessOptions, +): boolean { return ( - isTypeReadonlyRecurser(checker, type, new Set()) === Readonlyness.Readonly + isTypeReadonlyRecurser(checker, type, options, new Set()) === + Readonlyness.Readonly ); } diff --git a/packages/eslint-plugin/tests/rules/prefer-readonly-parameter-types.test.ts b/packages/eslint-plugin/tests/rules/prefer-readonly-parameter-types.test.ts index 9278420a764..0a6ee103807 100644 --- a/packages/eslint-plugin/tests/rules/prefer-readonly-parameter-types.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-readonly-parameter-types.test.ts @@ -154,6 +154,74 @@ ruleTester.run('prefer-readonly-parameter-types', rule, { } function foo(arg: Readonly) {} `, + // immutable methods + ` + type MyType = Readonly<{ + prop: string; + method(): string; + }>; + function foo(arg: MyType) {} + `, + ` + type MyType = { + readonly prop: string; + readonly method: () => string; + }; + function bar(arg: MyType) {} + `, + // methods treated as readonly + { + code: ` + type MyType = { + readonly prop: string; + method(): string; + }; + function foo(arg: MyType) {} + `, + options: [ + { + treatMethodsAsReadonly: true, + }, + ], + }, + { + code: ` + class Foo { + method() {} + } + function foo(arg: Foo) {} + `, + options: [ + { + treatMethodsAsReadonly: true, + }, + ], + }, + { + code: ` + interface Foo { + method(): void; + } + function foo(arg: Foo) {} + `, + options: [ + { + treatMethodsAsReadonly: true, + }, + ], + }, + // ReadonlySet and ReadonlyMap are seen as readonly when methods are treated as readonly + { + code: ` + function foo(arg: ReadonlySet) {} + function bar(arg: ReadonlyMap) {} + `, + options: [ + { + treatMethodsAsReadonly: true, + }, + ], + }, // parameter properties should work fine { @@ -715,5 +783,23 @@ ruleTester.run('prefer-readonly-parameter-types', rule, { }, ], }, + // Mutable methods. + { + code: ` + type MyType = { + readonly prop: string; + method(): string; + }; + function foo(arg: MyType) {} + `, + errors: [ + { + messageId: 'shouldBeReadonly', + line: 6, + column: 22, + endColumn: 33, + }, + ], + }, ], }); From f62baec3a6a848739fddbcb2c4073c5ab5f7f774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20De=20Boey?= Date: Fri, 3 Sep 2021 19:47:26 +0200 Subject: [PATCH 13/19] chore(ast-spec): simplify `Literal` types (#3769) --- packages/ast-spec/src/base/LiteralBase.ts | 2 ++ packages/ast-spec/src/expression/literal/BigIntLiteral/spec.ts | 2 -- packages/ast-spec/src/expression/literal/BooleanLiteral/spec.ts | 2 -- packages/ast-spec/src/expression/literal/NullLiteral/spec.ts | 2 -- packages/ast-spec/src/expression/literal/NumberLiteral/spec.ts | 2 -- packages/ast-spec/src/expression/literal/RegExpLiteral/spec.ts | 2 -- packages/ast-spec/src/expression/literal/StringLiteral/spec.ts | 2 -- 7 files changed, 2 insertions(+), 12 deletions(-) diff --git a/packages/ast-spec/src/base/LiteralBase.ts b/packages/ast-spec/src/base/LiteralBase.ts index 01a480ddc3c..c878fe7b7aa 100644 --- a/packages/ast-spec/src/base/LiteralBase.ts +++ b/packages/ast-spec/src/base/LiteralBase.ts @@ -1,6 +1,8 @@ +import type { AST_NODE_TYPES } from '../ast-node-types'; import type { BaseNode } from './BaseNode'; export interface LiteralBase extends BaseNode { + type: AST_NODE_TYPES.Literal; raw: string; value: RegExp | bigint | boolean | number | string | null; } diff --git a/packages/ast-spec/src/expression/literal/BigIntLiteral/spec.ts b/packages/ast-spec/src/expression/literal/BigIntLiteral/spec.ts index c27a85543ff..2df33369cf7 100644 --- a/packages/ast-spec/src/expression/literal/BigIntLiteral/spec.ts +++ b/packages/ast-spec/src/expression/literal/BigIntLiteral/spec.ts @@ -1,8 +1,6 @@ -import type { AST_NODE_TYPES } from '../../../ast-node-types'; import type { LiteralBase } from '../../../base/LiteralBase'; export interface BigIntLiteral extends LiteralBase { - type: AST_NODE_TYPES.Literal; value: bigint | null; bigint: string; } diff --git a/packages/ast-spec/src/expression/literal/BooleanLiteral/spec.ts b/packages/ast-spec/src/expression/literal/BooleanLiteral/spec.ts index a2310a698d0..be7477f015c 100644 --- a/packages/ast-spec/src/expression/literal/BooleanLiteral/spec.ts +++ b/packages/ast-spec/src/expression/literal/BooleanLiteral/spec.ts @@ -1,8 +1,6 @@ -import type { AST_NODE_TYPES } from '../../../ast-node-types'; import type { LiteralBase } from '../../../base/LiteralBase'; export interface BooleanLiteral extends LiteralBase { - type: AST_NODE_TYPES.Literal; value: boolean; raw: 'false' | 'true'; } diff --git a/packages/ast-spec/src/expression/literal/NullLiteral/spec.ts b/packages/ast-spec/src/expression/literal/NullLiteral/spec.ts index f520b7b3d45..03ff8a43c86 100644 --- a/packages/ast-spec/src/expression/literal/NullLiteral/spec.ts +++ b/packages/ast-spec/src/expression/literal/NullLiteral/spec.ts @@ -1,8 +1,6 @@ -import type { AST_NODE_TYPES } from '../../../ast-node-types'; import type { LiteralBase } from '../../../base/LiteralBase'; export interface NullLiteral extends LiteralBase { - type: AST_NODE_TYPES.Literal; value: null; raw: 'null'; } diff --git a/packages/ast-spec/src/expression/literal/NumberLiteral/spec.ts b/packages/ast-spec/src/expression/literal/NumberLiteral/spec.ts index 8155bb45caf..5a6cc12a59c 100644 --- a/packages/ast-spec/src/expression/literal/NumberLiteral/spec.ts +++ b/packages/ast-spec/src/expression/literal/NumberLiteral/spec.ts @@ -1,7 +1,5 @@ -import type { AST_NODE_TYPES } from '../../../ast-node-types'; import type { LiteralBase } from '../../../base/LiteralBase'; export interface NumberLiteral extends LiteralBase { - type: AST_NODE_TYPES.Literal; value: number; } diff --git a/packages/ast-spec/src/expression/literal/RegExpLiteral/spec.ts b/packages/ast-spec/src/expression/literal/RegExpLiteral/spec.ts index ab45f651b76..f72b53c7956 100644 --- a/packages/ast-spec/src/expression/literal/RegExpLiteral/spec.ts +++ b/packages/ast-spec/src/expression/literal/RegExpLiteral/spec.ts @@ -1,8 +1,6 @@ -import type { AST_NODE_TYPES } from '../../../ast-node-types'; import type { LiteralBase } from '../../../base/LiteralBase'; export interface RegExpLiteral extends LiteralBase { - type: AST_NODE_TYPES.Literal; value: RegExp | null; regex: { pattern: string; diff --git a/packages/ast-spec/src/expression/literal/StringLiteral/spec.ts b/packages/ast-spec/src/expression/literal/StringLiteral/spec.ts index de83d9d20e1..32734f443e2 100644 --- a/packages/ast-spec/src/expression/literal/StringLiteral/spec.ts +++ b/packages/ast-spec/src/expression/literal/StringLiteral/spec.ts @@ -1,7 +1,5 @@ -import type { AST_NODE_TYPES } from '../../../ast-node-types'; import type { LiteralBase } from '../../../base/LiteralBase'; export interface StringLiteral extends LiteralBase { - type: AST_NODE_TYPES.Literal; value: string; } From 463e768978731d019345f6552d7fd7a073a80192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20De=20Boey?= Date: Fri, 3 Sep 2021 19:47:46 +0200 Subject: [PATCH 14/19] fix(ast-spec): remove duplicate union types from `Expression` (#3770) --- packages/ast-spec/src/unions/Expression.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/ast-spec/src/unions/Expression.ts b/packages/ast-spec/src/unions/Expression.ts index fd1a14b114e..5359dc9c69c 100644 --- a/packages/ast-spec/src/unions/Expression.ts +++ b/packages/ast-spec/src/unions/Expression.ts @@ -50,10 +50,8 @@ export type Expression = | CallExpression | ChainExpression | ClassExpression - | ClassExpression | ConditionalExpression | FunctionExpression - | FunctionExpression | Identifier | ImportExpression | JSXElement From bb72fd64157260289dd6941da122d6c2ae91bba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Strnad?= <43024885+vostrnad@users.noreply.github.com> Date: Fri, 3 Sep 2021 19:52:47 +0200 Subject: [PATCH 15/19] chore(eslint-plugin): fix missing periods in rule messages (#3789) --- .../src/rules/consistent-indexed-object-style.ts | 2 +- .../src/rules/consistent-type-imports.ts | 11 ++++++----- .../src/rules/no-confusing-non-null-assertion.ts | 10 +++++----- .../src/rules/no-confusing-void-expression.ts | 2 +- .../eslint-plugin/src/rules/no-duplicate-imports.ts | 8 ++++---- .../eslint-plugin/src/rules/no-implicit-any-catch.ts | 4 ++-- .../eslint-plugin/src/rules/no-invalid-void-type.ts | 10 +++++----- .../src/rules/no-unnecessary-condition.ts | 8 ++++---- .../src/rules/prefer-enum-initializers.ts | 2 +- .../src/rules/prefer-return-this-type.ts | 2 +- 10 files changed, 30 insertions(+), 29 deletions(-) diff --git a/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts b/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts index a30102dd123..fcce191b2b5 100644 --- a/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts +++ b/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts @@ -19,7 +19,7 @@ export default createRule({ recommended: false, }, messages: { - preferRecord: 'A record is preferred over an index signature', + preferRecord: 'A record is preferred over an index signature.', preferIndexSignature: 'An index signature is preferred over a record.', }, fixable: 'code', diff --git a/packages/eslint-plugin/src/rules/consistent-type-imports.ts b/packages/eslint-plugin/src/rules/consistent-type-imports.ts index 795014507d0..34f264ff0c7 100644 --- a/packages/eslint-plugin/src/rules/consistent-type-imports.ts +++ b/packages/eslint-plugin/src/rules/consistent-type-imports.ts @@ -61,13 +61,14 @@ export default util.createRule({ }, messages: { typeOverValue: - 'All imports in the declaration are only used as types. Use `import type`', - someImportsAreOnlyTypes: 'Imports {{typeImports}} are only used as types', - aImportIsOnlyTypes: 'Import {{typeImports}} is only used as types', + 'All imports in the declaration are only used as types. Use `import type`.', + someImportsAreOnlyTypes: + 'Imports {{typeImports}} are only used as types.', + aImportIsOnlyTypes: 'Import {{typeImports}} is only used as types.', someImportsInDecoMeta: - 'Type imports {{typeImports}} are used by decorator metadata', + 'Type imports {{typeImports}} are used by decorator metadata.', aImportInDecoMeta: - 'Type import {{typeImports}} is used by decorator metadata', + 'Type import {{typeImports}} is used by decorator metadata.', valueOverType: 'Use an `import` instead of an `import type`.', noImportTypeAnnotations: '`import()` type annotations are forbidden.', }, diff --git a/packages/eslint-plugin/src/rules/no-confusing-non-null-assertion.ts b/packages/eslint-plugin/src/rules/no-confusing-non-null-assertion.ts index bcf561b5856..446bdd25932 100644 --- a/packages/eslint-plugin/src/rules/no-confusing-non-null-assertion.ts +++ b/packages/eslint-plugin/src/rules/no-confusing-non-null-assertion.ts @@ -19,14 +19,14 @@ export default util.createRule({ fixable: 'code', messages: { confusingEqual: - 'Confusing combinations of non-null assertion and equal test like "a! == b", which looks very similar to not equal "a !== b"', + 'Confusing combinations of non-null assertion and equal test like "a! == b", which looks very similar to not equal "a !== b".', confusingAssign: - 'Confusing combinations of non-null assertion and equal test like "a! = b", which looks very similar to not equal "a != b"', - notNeedInEqualTest: 'Unnecessary non-null assertion (!) in equal test', + 'Confusing combinations of non-null assertion and equal test like "a! = b", which looks very similar to not equal "a != b".', + notNeedInEqualTest: 'Unnecessary non-null assertion (!) in equal test.', notNeedInAssign: - 'Unnecessary non-null assertion (!) in assignment left hand', + 'Unnecessary non-null assertion (!) in assignment left hand.', wrapUpLeft: - 'Wrap up left hand to avoid putting non-null assertion "!" and "=" together', + 'Wrap up left hand to avoid putting non-null assertion "!" and "=" together.', }, schema: [], }, diff --git a/packages/eslint-plugin/src/rules/no-confusing-void-expression.ts b/packages/eslint-plugin/src/rules/no-confusing-void-expression.ts index a9b715350e9..fd4e97e7360 100644 --- a/packages/eslint-plugin/src/rules/no-confusing-void-expression.ts +++ b/packages/eslint-plugin/src/rules/no-confusing-void-expression.ts @@ -57,7 +57,7 @@ export default util.createRule({ invalidVoidExprReturnWrapVoid: 'Void expressions returned from a function ' + 'must be marked explicitly with the `void` operator.', - voidExprWrapVoid: 'Mark with an explicit `void` operator', + voidExprWrapVoid: 'Mark with an explicit `void` operator.', }, schema: [ { diff --git a/packages/eslint-plugin/src/rules/no-duplicate-imports.ts b/packages/eslint-plugin/src/rules/no-duplicate-imports.ts index a6f368902e3..f58ef76e5fc 100644 --- a/packages/eslint-plugin/src/rules/no-duplicate-imports.ts +++ b/packages/eslint-plugin/src/rules/no-duplicate-imports.ts @@ -21,10 +21,10 @@ export default util.createRule({ schema: baseRule.meta.schema, messages: { ...baseRule.meta.messages, - importType: '{{module}} type import is duplicated', - importTypeAs: '{{module}} type import is duplicated as type export', - exportType: '{{module}} type export is duplicated', - exportTypeAs: '{{module}} type export is duplicated as type import', + importType: '{{module}} type import is duplicated.', + importTypeAs: '{{module}} type import is duplicated as type export.', + exportType: '{{module}} type export is duplicated.', + exportTypeAs: '{{module}} type export is duplicated as type import.', }, }, defaultOptions: [ diff --git a/packages/eslint-plugin/src/rules/no-implicit-any-catch.ts b/packages/eslint-plugin/src/rules/no-implicit-any-catch.ts index aed526f8ab0..fbbdf59eb31 100644 --- a/packages/eslint-plugin/src/rules/no-implicit-any-catch.ts +++ b/packages/eslint-plugin/src/rules/no-implicit-any-catch.ts @@ -26,8 +26,8 @@ export default util.createRule({ }, fixable: 'code', messages: { - implicitAnyInCatch: 'Implicit any in catch clause', - explicitAnyInCatch: 'Explicit any in catch clause', + implicitAnyInCatch: 'Implicit any in catch clause.', + explicitAnyInCatch: 'Explicit any in catch clause.', suggestExplicitUnknown: 'Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct.', }, diff --git a/packages/eslint-plugin/src/rules/no-invalid-void-type.ts b/packages/eslint-plugin/src/rules/no-invalid-void-type.ts index 0dff489e585..62c1aa679cf 100644 --- a/packages/eslint-plugin/src/rules/no-invalid-void-type.ts +++ b/packages/eslint-plugin/src/rules/no-invalid-void-type.ts @@ -28,14 +28,14 @@ export default util.createRule<[Options], MessageIds>({ }, messages: { invalidVoidForGeneric: - '{{ generic }} may not have void as a type variable', + '{{ generic }} may not have void as a type variable.', invalidVoidNotReturnOrGeneric: - 'void is only valid as a return type or generic type variable', - invalidVoidNotReturn: 'void is only valid as a return type', + 'void is only valid as a return type or generic type variable.', + invalidVoidNotReturn: 'void is only valid as a return type.', invalidVoidNotReturnOrThisParam: - 'void is only valid as return type or type of `this` parameter', + 'void is only valid as return type or type of `this` parameter.', invalidVoidNotReturnOrThisParamOrGeneric: - 'void is only valid as a return type or generic type variable or the type of a `this` parameter', + 'void is only valid as a return type or generic type variable or the type of a `this` parameter.', }, schema: [ { diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts b/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts index 9079769c216..5ae3f93408a 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts @@ -121,11 +121,11 @@ export default createRule({ alwaysNullish: 'Unnecessary conditional, left-hand side of `??` operator is always `null` or `undefined`.', literalBooleanExpression: - 'Unnecessary conditional, both sides of the expression are literal values', + 'Unnecessary conditional, both sides of the expression are literal values.', noOverlapBooleanExpression: - 'Unnecessary conditional, the types have no overlap', - never: 'Unnecessary conditional, value is `never`', - neverOptionalChain: 'Unnecessary optional chain on a non-nullish value', + 'Unnecessary conditional, the types have no overlap.', + never: 'Unnecessary conditional, value is `never`.', + neverOptionalChain: 'Unnecessary optional chain on a non-nullish value.', noStrictNullCheck: 'This rule requires the `strictNullChecks` compiler option to be turned on to function correctly.', }, diff --git a/packages/eslint-plugin/src/rules/prefer-enum-initializers.ts b/packages/eslint-plugin/src/rules/prefer-enum-initializers.ts index 1a5c1248c89..d87b38f7d3a 100644 --- a/packages/eslint-plugin/src/rules/prefer-enum-initializers.ts +++ b/packages/eslint-plugin/src/rules/prefer-enum-initializers.ts @@ -16,7 +16,7 @@ export default util.createRule<[], MessageIds>({ }, messages: { defineInitializer: - "The value of the member '{{ name }}' should be explicitly defined", + "The value of the member '{{ name }}' should be explicitly defined.", defineInitializerSuggestion: 'Can be fixed to {{ name }} = {{ suggested }}', }, diff --git a/packages/eslint-plugin/src/rules/prefer-return-this-type.ts b/packages/eslint-plugin/src/rules/prefer-return-this-type.ts index 4287d6c5dfa..5a41a29d0a0 100644 --- a/packages/eslint-plugin/src/rules/prefer-return-this-type.ts +++ b/packages/eslint-plugin/src/rules/prefer-return-this-type.ts @@ -27,7 +27,7 @@ export default createRule({ requiresTypeChecking: true, }, messages: { - useThisType: 'use `this` type instead.', + useThisType: 'Use `this` type instead.', }, schema: [], fixable: 'code', From b33a2ea55babc573d88d844177f4db8696f651ac Mon Sep 17 00:00:00 2001 From: Edmundo Santos Date: Fri, 3 Sep 2021 14:54:22 -0300 Subject: [PATCH 16/19] docs(typescript-estree): fix plural name for parserOptions.programs option (#3799) --- packages/typescript-estree/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/typescript-estree/README.md b/packages/typescript-estree/README.md index 9cbcb2727cf..605836b3c69 100644 --- a/packages/typescript-estree/README.md +++ b/packages/typescript-estree/README.md @@ -209,11 +209,11 @@ interface ParseAndGenerateServicesOptions extends ParseOptions { tsconfigRootDir?: string; /** - * Instance of a TypeScript Program object to be used for type information. + * An array of one or more instances of TypeScript Program objects to be used for type information. * This overrides any program or programs that would have been computed from the `project` option. - * All linted files must be part of the provided program. + * All linted files must be part of the provided program(s). */ - program?: import('typescript').Program; + programs?: Program[]; /** *************************************************************************************** @@ -333,7 +333,7 @@ Types for the AST produced by the parse functions. #### `createProgram(configFile, projectDirectory)` -This serves as a utility method for users of the `ParseOptions.program` feature to create a TypeScript program instance from a config file. +This serves as a utility method for users of the `ParseOptions.programs` feature to create a TypeScript program instance from a config file. ```ts declare function createProgram( From e59a17c076ea3803507369116ad15191e1e3ada8 Mon Sep 17 00:00:00 2001 From: Rafael Santana Date: Fri, 3 Sep 2021 14:55:16 -0300 Subject: [PATCH 17/19] docs(eslint-plugin): fix incorrect quote (#3810) --- .../eslint-plugin/docs/rules/no-unnecessary-type-assertion.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/docs/rules/no-unnecessary-type-assertion.md b/packages/eslint-plugin/docs/rules/no-unnecessary-type-assertion.md index 4464b6483ef..2851791f0b0 100644 --- a/packages/eslint-plugin/docs/rules/no-unnecessary-type-assertion.md +++ b/packages/eslint-plugin/docs/rules/no-unnecessary-type-assertion.md @@ -70,4 +70,4 @@ If you don't care about having no-op type assertions in your code, then you can ## Related to -- TSLint: ['no-unnecessary-type-assertion`](https://palantir.github.io/tslint/rules/no-unnecessary-type-assertion/) +- TSLint: [`no-unnecessary-type-assertion`](https://palantir.github.io/tslint/rules/no-unnecessary-type-assertion/) From 8218055d6dfd94c9e6c8645848f981d9d51ce08c Mon Sep 17 00:00:00 2001 From: Rafael Santana Date: Fri, 3 Sep 2021 14:57:19 -0300 Subject: [PATCH 18/19] fix(utils): support immutable arrays in `ReportFixFunction` (#3830) --- packages/eslint-plugin/src/rules/no-explicit-any.ts | 8 ++++---- .../eslint-plugin/src/rules/prefer-enum-initializers.ts | 3 +-- packages/experimental-utils/src/ts-eslint/Rule.ts | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-explicit-any.ts b/packages/eslint-plugin/src/rules/no-explicit-any.ts index 4e6b8c34fc1..9df51ba3d52 100644 --- a/packages/eslint-plugin/src/rules/no-explicit-any.ts +++ b/packages/eslint-plugin/src/rules/no-explicit-any.ts @@ -1,9 +1,9 @@ import { - TSESTree, AST_NODE_TYPES, + TSESLint, + TSESTree, } from '@typescript-eslint/experimental-utils'; import * as util from '../util'; -import { TSESLint } from '@typescript-eslint/experimental-utils'; export type Options = [ { @@ -199,8 +199,8 @@ export default util.createRule({ }; if (fixToUnknown) { - fixOrSuggest.fix = (fixer => - fixer.replaceText(node, 'unknown')) as TSESLint.ReportFixFunction; + fixOrSuggest.fix = (fixer): TSESLint.RuleFix => + fixer.replaceText(node, 'unknown'); } context.report({ diff --git a/packages/eslint-plugin/src/rules/prefer-enum-initializers.ts b/packages/eslint-plugin/src/rules/prefer-enum-initializers.ts index d87b38f7d3a..663caa5bedd 100644 --- a/packages/eslint-plugin/src/rules/prefer-enum-initializers.ts +++ b/packages/eslint-plugin/src/rules/prefer-enum-initializers.ts @@ -1,6 +1,5 @@ -import { TSESTree } from '@typescript-eslint/experimental-utils'; +import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils'; import * as util from '../util'; -import { TSESLint } from '@typescript-eslint/experimental-utils'; type MessageIds = 'defineInitializer' | 'defineInitializerSuggestion'; diff --git a/packages/experimental-utils/src/ts-eslint/Rule.ts b/packages/experimental-utils/src/ts-eslint/Rule.ts index f813b9d1730..24b8fd4fa11 100644 --- a/packages/experimental-utils/src/ts-eslint/Rule.ts +++ b/packages/experimental-utils/src/ts-eslint/Rule.ts @@ -114,7 +114,7 @@ interface RuleFixer { type ReportFixFunction = ( fixer: RuleFixer, -) => null | RuleFix | RuleFix[] | IterableIterator; +) => null | RuleFix | readonly RuleFix[] | IterableIterator; type ReportSuggestionArray = ReportDescriptorBase[]; From 4a88de2c621ae645c070d995768006df8cb7e4df Mon Sep 17 00:00:00 2001 From: James Henry Date: Mon, 6 Sep 2021 17:03:22 +0000 Subject: [PATCH 19/19] chore: publish v4.31.0 --- CHANGELOG.md | 21 ++++++++++++++++++++ lerna.json | 2 +- packages/ast-spec/CHANGELOG.md | 16 +++++++++++++++ packages/ast-spec/package.json | 2 +- packages/eslint-plugin-internal/CHANGELOG.md | 8 ++++++++ packages/eslint-plugin-internal/package.json | 4 ++-- packages/eslint-plugin-tslint/CHANGELOG.md | 8 ++++++++ packages/eslint-plugin-tslint/package.json | 6 +++--- packages/eslint-plugin/CHANGELOG.md | 19 ++++++++++++++++++ packages/eslint-plugin/package.json | 6 +++--- packages/experimental-utils/CHANGELOG.md | 16 +++++++++++++++ packages/experimental-utils/package.json | 8 ++++---- packages/parser/CHANGELOG.md | 8 ++++++++ packages/parser/package.json | 10 +++++----- 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/types/CHANGELOG.md | 8 ++++++++ packages/types/package.json | 2 +- packages/typescript-estree/CHANGELOG.md | 8 ++++++++ packages/typescript-estree/package.json | 8 ++++---- packages/visitor-keys/CHANGELOG.md | 8 ++++++++ packages/visitor-keys/package.json | 4 ++-- 24 files changed, 167 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e844a010246..587bb83aa71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,27 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.31.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.30.0...v4.31.0) (2021-09-06) + + +### Bug Fixes + +* **ast-spec:** remove duplicate union types from `Expression` ([#3770](https://github.com/typescript-eslint/typescript-eslint/issues/3770)) ([463e768](https://github.com/typescript-eslint/typescript-eslint/commit/463e768978731d019345f6552d7fd7a073a80192)) +* **utils:** support immutable arrays in `ReportFixFunction` ([#3830](https://github.com/typescript-eslint/typescript-eslint/issues/3830)) ([8218055](https://github.com/typescript-eslint/typescript-eslint/commit/8218055d6dfd94c9e6c8645848f981d9d51ce08c)) + + +### Features + +* **eslint-plugin:** [prefer-readonly-parameter-types] add option treatMethodsAsReadonly ([#3733](https://github.com/typescript-eslint/typescript-eslint/issues/3733)) ([a46e318](https://github.com/typescript-eslint/typescript-eslint/commit/a46e3182c8a0b07c914605d6d9fe28ef36a7c32a)) +* **eslint-plugin:** [restrict-template-expressions] add option to allow RegExp ([#3709](https://github.com/typescript-eslint/typescript-eslint/issues/3709)) ([363b3dc](https://github.com/typescript-eslint/typescript-eslint/commit/363b3dc4dd0dc343311c729d75935b10f9d2fd5e)) +* **eslint-plugin:** add `no-meaningless-void-operator` rule ([#3641](https://github.com/typescript-eslint/typescript-eslint/issues/3641)) ([ea40ab6](https://github.com/typescript-eslint/typescript-eslint/commit/ea40ab659351ae7cf7235ea063d42ac155b11e5f)) +* **eslint-plugin:** add extension rule `padding-line-between-statements` ([#3418](https://github.com/typescript-eslint/typescript-eslint/issues/3418)) ([f79ae9b](https://github.com/typescript-eslint/typescript-eslint/commit/f79ae9b58e82f4fddef640a34a1d7ff92b763e65)) +* **experimental-utils:** extract `isNodeOfType` out of `ast-utils`' `predicates` ([#3677](https://github.com/typescript-eslint/typescript-eslint/issues/3677)) ([4bfa437](https://github.com/typescript-eslint/typescript-eslint/commit/4bfa4375aff8f65057d4aa116e435803cbc6b464)) + + + + + # [4.30.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.29.3...v4.30.0) (2021-08-30) diff --git a/lerna.json b/lerna.json index 9a59e7c6919..bcd9745966f 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "4.30.0", + "version": "4.31.0", "npmClient": "yarn", "useWorkspaces": true, "stream": true diff --git a/packages/ast-spec/CHANGELOG.md b/packages/ast-spec/CHANGELOG.md index bec6a7f1f74..9383371e9b2 100644 --- a/packages/ast-spec/CHANGELOG.md +++ b/packages/ast-spec/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.31.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.30.0...v4.31.0) (2021-09-06) + + +### Bug Fixes + +* **ast-spec:** remove duplicate union types from `Expression` ([#3770](https://github.com/typescript-eslint/typescript-eslint/issues/3770)) ([463e768](https://github.com/typescript-eslint/typescript-eslint/commit/463e768978731d019345f6552d7fd7a073a80192)) + + +### Features + +* **eslint-plugin:** add extension rule `padding-line-between-statements` ([#3418](https://github.com/typescript-eslint/typescript-eslint/issues/3418)) ([f79ae9b](https://github.com/typescript-eslint/typescript-eslint/commit/f79ae9b58e82f4fddef640a34a1d7ff92b763e65)) + + + + + # [4.30.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.29.3...v4.30.0) (2021-08-30) diff --git a/packages/ast-spec/package.json b/packages/ast-spec/package.json index b0af29d0e95..b9b92b3361f 100644 --- a/packages/ast-spec/package.json +++ b/packages/ast-spec/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/ast-spec", - "version": "4.30.0", + "version": "4.31.0", "description": "TypeScript-ESTree AST spec", "private": true, "keywords": [ diff --git a/packages/eslint-plugin-internal/CHANGELOG.md b/packages/eslint-plugin-internal/CHANGELOG.md index a704b20f06e..73b587a0080 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. +# [4.31.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.30.0...v4.31.0) (2021-09-06) + +**Note:** Version bump only for package @typescript-eslint/eslint-plugin-internal + + + + + # [4.30.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.29.3...v4.30.0) (2021-08-30) **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 2b6a5a56a69..0364bccbc9b 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": "4.30.0", + "version": "4.31.0", "private": true, "main": "dist/index.js", "scripts": { @@ -14,7 +14,7 @@ }, "dependencies": { "@types/prettier": "*", - "@typescript-eslint/experimental-utils": "4.30.0", + "@typescript-eslint/experimental-utils": "4.31.0", "prettier": "*" } } diff --git a/packages/eslint-plugin-tslint/CHANGELOG.md b/packages/eslint-plugin-tslint/CHANGELOG.md index ef836910ccf..c5e66c76933 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. +# [4.31.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.30.0...v4.31.0) (2021-09-06) + +**Note:** Version bump only for package @typescript-eslint/eslint-plugin-tslint + + + + + # [4.30.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.29.3...v4.30.0) (2021-08-30) **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 df35db55510..5f0f25a2d31 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": "4.30.0", + "version": "4.31.0", "main": "dist/index.js", "typings": "src/index.ts", "description": "TSLint wrapper plugin for ESLint", @@ -38,7 +38,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/experimental-utils": "4.30.0", + "@typescript-eslint/experimental-utils": "4.31.0", "lodash": "^4.17.21" }, "peerDependencies": { @@ -48,6 +48,6 @@ }, "devDependencies": { "@types/lodash": "*", - "@typescript-eslint/parser": "4.30.0" + "@typescript-eslint/parser": "4.31.0" } } diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index a433e2fc77e..caae41c1f91 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/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. +# [4.31.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.30.0...v4.31.0) (2021-09-06) + + +### Bug Fixes + +* **utils:** support immutable arrays in `ReportFixFunction` ([#3830](https://github.com/typescript-eslint/typescript-eslint/issues/3830)) ([8218055](https://github.com/typescript-eslint/typescript-eslint/commit/8218055d6dfd94c9e6c8645848f981d9d51ce08c)) + + +### Features + +* **eslint-plugin:** [prefer-readonly-parameter-types] add option treatMethodsAsReadonly ([#3733](https://github.com/typescript-eslint/typescript-eslint/issues/3733)) ([a46e318](https://github.com/typescript-eslint/typescript-eslint/commit/a46e3182c8a0b07c914605d6d9fe28ef36a7c32a)) +* **eslint-plugin:** [restrict-template-expressions] add option to allow RegExp ([#3709](https://github.com/typescript-eslint/typescript-eslint/issues/3709)) ([363b3dc](https://github.com/typescript-eslint/typescript-eslint/commit/363b3dc4dd0dc343311c729d75935b10f9d2fd5e)) +* **eslint-plugin:** add `no-meaningless-void-operator` rule ([#3641](https://github.com/typescript-eslint/typescript-eslint/issues/3641)) ([ea40ab6](https://github.com/typescript-eslint/typescript-eslint/commit/ea40ab659351ae7cf7235ea063d42ac155b11e5f)) +* **eslint-plugin:** add extension rule `padding-line-between-statements` ([#3418](https://github.com/typescript-eslint/typescript-eslint/issues/3418)) ([f79ae9b](https://github.com/typescript-eslint/typescript-eslint/commit/f79ae9b58e82f4fddef640a34a1d7ff92b763e65)) + + + + + # [4.30.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.29.3...v4.30.0) (2021-08-30) diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 9ac333083e5..c5c4b6a7680 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin", - "version": "4.30.0", + "version": "4.31.0", "description": "TypeScript plugin for ESLint", "keywords": [ "eslint", @@ -44,8 +44,8 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/experimental-utils": "4.30.0", - "@typescript-eslint/scope-manager": "4.30.0", + "@typescript-eslint/experimental-utils": "4.31.0", + "@typescript-eslint/scope-manager": "4.31.0", "debug": "^4.3.1", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.1.0", diff --git a/packages/experimental-utils/CHANGELOG.md b/packages/experimental-utils/CHANGELOG.md index 6c7d3f4676f..4124025771a 100644 --- a/packages/experimental-utils/CHANGELOG.md +++ b/packages/experimental-utils/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.31.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.30.0...v4.31.0) (2021-09-06) + + +### Bug Fixes + +* **utils:** support immutable arrays in `ReportFixFunction` ([#3830](https://github.com/typescript-eslint/typescript-eslint/issues/3830)) ([8218055](https://github.com/typescript-eslint/typescript-eslint/commit/8218055d6dfd94c9e6c8645848f981d9d51ce08c)) + + +### Features + +* **experimental-utils:** extract `isNodeOfType` out of `ast-utils`' `predicates` ([#3677](https://github.com/typescript-eslint/typescript-eslint/issues/3677)) ([4bfa437](https://github.com/typescript-eslint/typescript-eslint/commit/4bfa4375aff8f65057d4aa116e435803cbc6b464)) + + + + + # [4.30.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.29.3...v4.30.0) (2021-08-30) diff --git a/packages/experimental-utils/package.json b/packages/experimental-utils/package.json index 779d7f1e61b..911ef711290 100644 --- a/packages/experimental-utils/package.json +++ b/packages/experimental-utils/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/experimental-utils", - "version": "4.30.0", + "version": "4.31.0", "description": "(Experimental) Utilities for working with TypeScript + ESLint together", "keywords": [ "eslint", @@ -40,9 +40,9 @@ }, "dependencies": { "@types/json-schema": "^7.0.7", - "@typescript-eslint/scope-manager": "4.30.0", - "@typescript-eslint/types": "4.30.0", - "@typescript-eslint/typescript-estree": "4.30.0", + "@typescript-eslint/scope-manager": "4.31.0", + "@typescript-eslint/types": "4.31.0", + "@typescript-eslint/typescript-estree": "4.31.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" }, diff --git a/packages/parser/CHANGELOG.md b/packages/parser/CHANGELOG.md index 5f6f603f814..42187282c95 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. +# [4.31.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.30.0...v4.31.0) (2021-09-06) + +**Note:** Version bump only for package @typescript-eslint/parser + + + + + # [4.30.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.29.3...v4.30.0) (2021-08-30) diff --git a/packages/parser/package.json b/packages/parser/package.json index 5e802a17872..b5847320a1b 100644 --- a/packages/parser/package.json +++ b/packages/parser/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/parser", - "version": "4.30.0", + "version": "4.31.0", "description": "An ESLint custom parser which leverages TypeScript ESTree", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -44,14 +44,14 @@ "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" }, "dependencies": { - "@typescript-eslint/scope-manager": "4.30.0", - "@typescript-eslint/types": "4.30.0", - "@typescript-eslint/typescript-estree": "4.30.0", + "@typescript-eslint/scope-manager": "4.31.0", + "@typescript-eslint/types": "4.31.0", + "@typescript-eslint/typescript-estree": "4.31.0", "debug": "^4.3.1" }, "devDependencies": { "@types/glob": "*", - "@typescript-eslint/experimental-utils": "4.30.0", + "@typescript-eslint/experimental-utils": "4.31.0", "glob": "*", "typescript": "*" }, diff --git a/packages/scope-manager/CHANGELOG.md b/packages/scope-manager/CHANGELOG.md index 23932d87940..f7221c1ec4c 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. +# [4.31.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.30.0...v4.31.0) (2021-09-06) + +**Note:** Version bump only for package @typescript-eslint/scope-manager + + + + + # [4.30.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.29.3...v4.30.0) (2021-08-30) diff --git a/packages/scope-manager/package.json b/packages/scope-manager/package.json index 63d3a69cecb..bf054505fe2 100644 --- a/packages/scope-manager/package.json +++ b/packages/scope-manager/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/scope-manager", - "version": "4.30.0", + "version": "4.31.0", "description": "TypeScript scope analyser for ESLint", "keywords": [ "eslint", @@ -39,12 +39,12 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/types": "4.30.0", - "@typescript-eslint/visitor-keys": "4.30.0" + "@typescript-eslint/types": "4.31.0", + "@typescript-eslint/visitor-keys": "4.31.0" }, "devDependencies": { "@types/glob": "*", - "@typescript-eslint/typescript-estree": "4.30.0", + "@typescript-eslint/typescript-estree": "4.31.0", "glob": "*", "jest-specific-snapshot": "*", "make-dir": "*", diff --git a/packages/shared-fixtures/CHANGELOG.md b/packages/shared-fixtures/CHANGELOG.md index 52a786b215f..8c0f70d151a 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. +# [4.31.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.30.0...v4.31.0) (2021-09-06) + +**Note:** Version bump only for package @typescript-eslint/shared-fixtures + + + + + # [4.30.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.29.3...v4.30.0) (2021-08-30) diff --git a/packages/shared-fixtures/package.json b/packages/shared-fixtures/package.json index b5610cdd437..83939580e4e 100644 --- a/packages/shared-fixtures/package.json +++ b/packages/shared-fixtures/package.json @@ -1,5 +1,5 @@ { "name": "@typescript-eslint/shared-fixtures", - "version": "4.30.0", + "version": "4.31.0", "private": true } diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index cb86be96ec3..50538a768c5 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. +# [4.31.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.30.0...v4.31.0) (2021-09-06) + +**Note:** Version bump only for package @typescript-eslint/types + + + + + # [4.30.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.29.3...v4.30.0) (2021-08-30) **Note:** Version bump only for package @typescript-eslint/types diff --git a/packages/types/package.json b/packages/types/package.json index 6e23a521e74..18aba8b01bc 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/types", - "version": "4.30.0", + "version": "4.31.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 94a9165463b..7406d424d1e 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. +# [4.31.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.30.0...v4.31.0) (2021-09-06) + +**Note:** Version bump only for package @typescript-eslint/typescript-estree + + + + + # [4.30.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.29.3...v4.30.0) (2021-08-30) diff --git a/packages/typescript-estree/package.json b/packages/typescript-estree/package.json index 4366789dfa3..dbe7db1d75f 100644 --- a/packages/typescript-estree/package.json +++ b/packages/typescript-estree/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/typescript-estree", - "version": "4.30.0", + "version": "4.31.0", "description": "A parser that converts TypeScript source code into an ESTree compatible form", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -41,8 +41,8 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/types": "4.30.0", - "@typescript-eslint/visitor-keys": "4.30.0", + "@typescript-eslint/types": "4.31.0", + "@typescript-eslint/visitor-keys": "4.31.0", "debug": "^4.3.1", "globby": "^11.0.3", "is-glob": "^4.0.1", @@ -59,7 +59,7 @@ "@types/is-glob": "*", "@types/semver": "*", "@types/tmp": "*", - "@typescript-eslint/shared-fixtures": "4.30.0", + "@typescript-eslint/shared-fixtures": "4.31.0", "glob": "*", "jest-specific-snapshot": "*", "make-dir": "*", diff --git a/packages/visitor-keys/CHANGELOG.md b/packages/visitor-keys/CHANGELOG.md index 8b1f5b13d4d..6d2b3716988 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. +# [4.31.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.30.0...v4.31.0) (2021-09-06) + +**Note:** Version bump only for package @typescript-eslint/visitor-keys + + + + + # [4.30.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.29.3...v4.30.0) (2021-08-30) diff --git a/packages/visitor-keys/package.json b/packages/visitor-keys/package.json index 90167ed5d1b..58334b5bc78 100644 --- a/packages/visitor-keys/package.json +++ b/packages/visitor-keys/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/visitor-keys", - "version": "4.30.0", + "version": "4.31.0", "description": "Visitor keys used to help traverse the TypeScript-ESTree AST", "keywords": [ "eslint", @@ -38,7 +38,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/types": "4.30.0", + "@typescript-eslint/types": "4.31.0", "eslint-visitor-keys": "^2.0.0" }, "devDependencies": {