diff --git a/.cspell.json b/.cspell.json index 09466a9d300a..4691cd152db3 100644 --- a/.cspell.json +++ b/.cspell.json @@ -73,8 +73,10 @@ "linebreaks", "lzstring", "markdownlint", + "metastring", "necroing", "nocheck", + "noninteractive", "nullish", "OOM", "OOMs", diff --git a/.prettierignore b/.prettierignore index 896d5c464a35..eda67619c874 100644 --- a/.prettierignore +++ b/.prettierignore @@ -14,6 +14,9 @@ packages/eslint-plugin/src/configs/*.json CONTRIBUTORS.md packages/ast-spec/src/*/*/fixtures/_error_/*/fixture.ts +# Syntax not yet supported +packages/scope-manager/tests/fixtures/type-declaration/type-query-with-parameters.ts + # Ignore CHANGELOG.md files to avoid issues with automated release job CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md index d8d52c1f202a..6ec5ad755cf1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,24 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.28.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.1...v5.28.0) (2022-06-13) + + +### Bug Fixes + +* [TS4.7] allow visiting of typeParameters in TSTypeQuery ([#5166](https://github.com/typescript-eslint/typescript-eslint/issues/5166)) ([dc1f930](https://github.com/typescript-eslint/typescript-eslint/commit/dc1f9309cf04aa7314e758980ac687558482f47f)) +* **eslint-plugin:** [space-infix-ops] support for optional property without type ([#5155](https://github.com/typescript-eslint/typescript-eslint/issues/5155)) ([1f25daf](https://github.com/typescript-eslint/typescript-eslint/commit/1f25daf74e5d45077199f9ee9fa9bf31107f4089)) + + +### Features + +* **ast-spec:** extract `AssignmentOperatorToText` ([#3570](https://github.com/typescript-eslint/typescript-eslint/issues/3570)) ([45f75e6](https://github.com/typescript-eslint/typescript-eslint/commit/45f75e6b869f4160a45a6890d794aba004356ad7)) +* **eslint-plugin:** [consistent-generic-constructors] add rule ([#4924](https://github.com/typescript-eslint/typescript-eslint/issues/4924)) ([921cdf1](https://github.com/typescript-eslint/typescript-eslint/commit/921cdf17e548845311d0591249616ec844503926)) + + + + + ## [5.27.1](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.0...v5.27.1) (2022-06-06) diff --git a/docs/linting/MONOREPO.md b/docs/linting/MONOREPO.md index 2f8cbe15f349..4ec2df161362 100644 --- a/docs/linting/MONOREPO.md +++ b/docs/linting/MONOREPO.md @@ -18,22 +18,24 @@ Earlier in our docs on [typed linting](./TYPED_LINTING.md), we showed you how to For example, this is how we specify all of our `tsconfig.json` within this repo. -```diff title=".eslintrc.js" - module.exports = { - root: true, - parser: '@typescript-eslint/parser', - parserOptions: { - tsconfigRootDir: __dirname, -- project: ['./tsconfig.json'], -+ project: ['./tsconfig.eslint.json', './packages/*/tsconfig.json'], - }, - plugins: ['@typescript-eslint'], - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', - ], - }; +```js title=".eslintrc.js" +module.exports = { + root: true, + parser: '@typescript-eslint/parser', + parserOptions: { + tsconfigRootDir: __dirname, + // Remove this line + project: ['./tsconfig.json'], + // Add this line + project: ['./tsconfig.eslint.json', './packages/*/tsconfig.json'], + }, + plugins: ['@typescript-eslint'], + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:@typescript-eslint/recommended-requiring-type-checking', + ], +}; ``` If you're looking for an example of what the `.eslintrc.js`, and referenced `tsconfig.json` might look like in a real example, look no further than this very repo. We're a multi-package monorepo that uses one `tsconfig.json` per package, that also uses typed linting. diff --git a/docs/linting/README.md b/docs/linting/README.md index dbf08d1e7808..23f0a2b1981a 100644 --- a/docs/linting/README.md +++ b/docs/linting/README.md @@ -136,19 +136,18 @@ If you use [`prettier`](https://www.npmjs.com/package/prettier), there is also a Using this config by adding it to the end of your `extends`: -```diff title=".eslintrc.js" - module.exports = { - root: true, - parser: '@typescript-eslint/parser', - plugins: [ - '@typescript-eslint', - ], - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', -+ 'prettier', - ], - }; +```js title=".eslintrc.js" +module.exports = { + root: true, + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint'], + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + // Add this line + 'prettier', + ], +}; ``` ### Community Configs @@ -163,19 +162,20 @@ A few popular all-in-one configs are: To use one of these complete config packages, you would replace the `extends` with the package name. For example: -```diff title=".eslintrc.js" - module.exports = { - root: true, - parser: '@typescript-eslint/parser', - plugins: [ - '@typescript-eslint', - ], - extends: [ -- 'eslint:recommended', -- 'plugin:@typescript-eslint/recommended', -+ 'airbnb-typescript', - ], - }; +```js title=".eslintrc.js" +module.exports = { + root: true, + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint'], + extends: [ + // Removed lines start + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + // Removed lines end + // Add this line + 'airbnb-typescript', + ], +}; ``` @@ -196,20 +196,22 @@ Below are just a few examples: Every plugin that is out there includes documentation on the various configurations and rules they offer. A typical plugin might be used like: -```diff title=".eslintrc.js" - module.exports = { - root: true, - parser: '@typescript-eslint/parser', - plugins: [ - '@typescript-eslint', -+ 'jest', - ], - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', -+ 'plugin:jest/recommended', - ], - }; +```js title=".eslintrc.js" +module.exports = { + root: true, + parser: '@typescript-eslint/parser', + plugins: [ + '@typescript-eslint', + // Add this line + 'jest', + ], + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + // Add this line + 'plugin:jest/recommended', + ], +}; ``` diff --git a/docs/linting/TROUBLESHOOTING.md b/docs/linting/TROUBLESHOOTING.md index d6cb97486f57..d9c447b4d0e2 100644 --- a/docs/linting/TROUBLESHOOTING.md +++ b/docs/linting/TROUBLESHOOTING.md @@ -42,12 +42,15 @@ See our docs on [type aware linting](./TYPED_LINTING.md#i-get-errors-telling-me- You can use `parserOptions.extraFileExtensions` to specify an array of non-TypeScript extensions to allow, for example: -```diff - parserOptions: { - tsconfigRootDir: __dirname, - project: ['./tsconfig.json'], -+ extraFileExtensions: ['.vue'], - }, +```js title=".eslintrc.js" +module.exports = { + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./tsconfig.json'], + // Add this line + extraFileExtensions: ['.vue'], + }, +}; ``` ## One of my lint rules isn't working correctly on a pure JavaScript file diff --git a/docs/linting/TYPED_LINTING.md b/docs/linting/TYPED_LINTING.md index 376a0334c174..ae58028e442b 100644 --- a/docs/linting/TYPED_LINTING.md +++ b/docs/linting/TYPED_LINTING.md @@ -8,21 +8,24 @@ Under the hood, the typescript-eslint parser uses TypeScript's compiler APIs to To tap into TypeScript's additional powers, there are two small changes you need to make to your config file: -```diff title=".eslintrc.js" - module.exports = { - root: true, - parser: '@typescript-eslint/parser', -+ parserOptions: { -+ tsconfigRootDir: __dirname, -+ project: ['./tsconfig.json'], -+ }, - plugins: ['@typescript-eslint'], - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', -+ 'plugin:@typescript-eslint/recommended-requiring-type-checking', - ], - }; +```js title=".eslintrc.js" +module.exports = { + root: true, + parser: '@typescript-eslint/parser', + // Added lines start + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./tsconfig.json'], + }, + // Added lines end + plugins: ['@typescript-eslint'], + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + // Add this line + 'plugin:@typescript-eslint/recommended-requiring-type-checking', + ], +}; ``` In more detail: diff --git a/lerna.json b/lerna.json index ff883e18240b..8fa5466d478e 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "5.27.1", + "version": "5.28.0", "npmClient": "yarn", "useWorkspaces": true, "stream": true diff --git a/package.json b/package.json index 264427094dd1..16f4cf82e8d1 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "@types/eslint-visitor-keys": "^1.0.0", "@types/glob": "^7.2.0", "@types/is-glob": "^4.0.2", - "@types/jest": "^27.5.0", + "@types/jest": "^28.1.1", "@types/jest-specific-snapshot": "^0.5.5", "@types/lodash": "^4.14.182", "@types/marked": "^4.0.3", @@ -92,7 +92,7 @@ "jest-snapshot": "^28.1.0", "jest-specific-snapshot": "^5.0.0", "lerna": "5.0.0", - "lint-staged": "^12.4.1", + "lint-staged": "^13.0.0", "make-dir": "^3.1.0", "markdownlint-cli": "^0.31.1", "ncp": "^2.0.0", diff --git a/packages/ast-spec/CHANGELOG.md b/packages/ast-spec/CHANGELOG.md index 28fdf351c002..032b40a162bd 100644 --- a/packages/ast-spec/CHANGELOG.md +++ b/packages/ast-spec/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.28.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.1...v5.28.0) (2022-06-13) + + +### Features + +* **ast-spec:** extract `AssignmentOperatorToText` ([#3570](https://github.com/typescript-eslint/typescript-eslint/issues/3570)) ([45f75e6](https://github.com/typescript-eslint/typescript-eslint/commit/45f75e6b869f4160a45a6890d794aba004356ad7)) + + + + + ## [5.27.1](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.0...v5.27.1) (2022-06-06) **Note:** Version bump only for package @typescript-eslint/ast-spec diff --git a/packages/ast-spec/package.json b/packages/ast-spec/package.json index 57a9b87464cc..b0197654abad 100644 --- a/packages/ast-spec/package.json +++ b/packages/ast-spec/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/ast-spec", - "version": "5.27.1", + "version": "5.28.0", "description": "TypeScript-ESTree AST spec", "private": true, "keywords": [ diff --git a/packages/ast-spec/src/expression/AssignmentExpression/AssignmentOperatorToText.ts b/packages/ast-spec/src/expression/AssignmentExpression/AssignmentOperatorToText.ts new file mode 100644 index 000000000000..9cebd34b8df2 --- /dev/null +++ b/packages/ast-spec/src/expression/AssignmentExpression/AssignmentOperatorToText.ts @@ -0,0 +1,20 @@ +import type { SyntaxKind } from 'typescript'; + +export interface AssignmentOperatorToText { + [SyntaxKind.EqualsToken]: '='; + [SyntaxKind.PlusEqualsToken]: '+='; + [SyntaxKind.MinusEqualsToken]: '-='; + [SyntaxKind.AsteriskEqualsToken]: '*='; + [SyntaxKind.AsteriskAsteriskEqualsToken]: '**='; + [SyntaxKind.SlashEqualsToken]: '/='; + [SyntaxKind.PercentEqualsToken]: '%='; + [SyntaxKind.LessThanLessThanEqualsToken]: '<<='; + [SyntaxKind.GreaterThanGreaterThanEqualsToken]: '>>='; + [SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken]: '>>>='; + [SyntaxKind.AmpersandEqualsToken]: '&='; + [SyntaxKind.BarEqualsToken]: '|='; + [SyntaxKind.BarBarEqualsToken]: '||='; + [SyntaxKind.AmpersandAmpersandEqualsToken]: '&&='; + [SyntaxKind.QuestionQuestionEqualsToken]: '??='; + [SyntaxKind.CaretEqualsToken]: '^='; +} diff --git a/packages/ast-spec/src/expression/AssignmentExpression/spec.ts b/packages/ast-spec/src/expression/AssignmentExpression/spec.ts index eb3c8effa991..cbe97f55e519 100644 --- a/packages/ast-spec/src/expression/AssignmentExpression/spec.ts +++ b/packages/ast-spec/src/expression/AssignmentExpression/spec.ts @@ -1,26 +1,14 @@ import type { AST_NODE_TYPES } from '../../ast-node-types'; import type { BaseNode } from '../../base/BaseNode'; import type { Expression } from '../../unions/Expression'; +import type { ValueOf } from '../../utils'; +import type { AssignmentOperatorToText } from './AssignmentOperatorToText'; + +export * from './AssignmentOperatorToText'; export interface AssignmentExpression extends BaseNode { type: AST_NODE_TYPES.AssignmentExpression; - operator: - | '-=' - | '??=' - | '**=' - | '*=' - | '/=' - | '&&=' - | '&=' - | '%=' - | '^=' - | '+=' - | '<<=' - | '=' - | '>>=' - | '>>>=' - | '|=' - | '||='; + operator: ValueOf; left: Expression; right: Expression; } diff --git a/packages/ast-spec/src/token/PunctuatorToken/PunctuatorTokenToText.ts b/packages/ast-spec/src/token/PunctuatorToken/PunctuatorTokenToText.ts index d15682a4efe7..a3ea5b151613 100644 --- a/packages/ast-spec/src/token/PunctuatorToken/PunctuatorTokenToText.ts +++ b/packages/ast-spec/src/token/PunctuatorToken/PunctuatorTokenToText.ts @@ -1,6 +1,8 @@ import type { SyntaxKind } from 'typescript'; -export interface PunctuatorTokenToText { +import type { AssignmentOperatorToText } from '../../expression/AssignmentExpression/AssignmentOperatorToText'; + +export interface PunctuatorTokenToText extends AssignmentOperatorToText { [SyntaxKind.OpenBraceToken]: '{'; [SyntaxKind.CloseBraceToken]: '}'; [SyntaxKind.OpenParenToken]: '('; @@ -46,20 +48,4 @@ export interface PunctuatorTokenToText { [SyntaxKind.QuestionQuestionToken]: '??'; [SyntaxKind.BacktickToken]: '`'; [SyntaxKind.HashToken]: '#'; - [SyntaxKind.EqualsToken]: '='; - [SyntaxKind.PlusEqualsToken]: '+='; - [SyntaxKind.MinusEqualsToken]: '-='; - [SyntaxKind.AsteriskEqualsToken]: '*='; - [SyntaxKind.AsteriskAsteriskEqualsToken]: '**='; - [SyntaxKind.SlashEqualsToken]: '/='; - [SyntaxKind.PercentEqualsToken]: '%='; - [SyntaxKind.LessThanLessThanEqualsToken]: '<<='; - [SyntaxKind.GreaterThanGreaterThanEqualsToken]: '>>='; - [SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken]: '>>>='; - [SyntaxKind.AmpersandEqualsToken]: '&='; - [SyntaxKind.BarEqualsToken]: '|='; - [SyntaxKind.BarBarEqualsToken]: '||='; - [SyntaxKind.AmpersandAmpersandEqualsToken]: '&&='; - [SyntaxKind.QuestionQuestionEqualsToken]: '??='; - [SyntaxKind.CaretEqualsToken]: '^='; } diff --git a/packages/ast-spec/src/token/PunctuatorToken/spec.ts b/packages/ast-spec/src/token/PunctuatorToken/spec.ts index 68156aad6638..733e0108d2f4 100644 --- a/packages/ast-spec/src/token/PunctuatorToken/spec.ts +++ b/packages/ast-spec/src/token/PunctuatorToken/spec.ts @@ -1,11 +1,10 @@ import type { AST_TOKEN_TYPES } from '../../ast-token-types'; import type { BaseToken } from '../../base/BaseToken'; +import type { ValueOf } from '../../utils'; import type { PunctuatorTokenToText } from './PunctuatorTokenToText'; export * from './PunctuatorTokenToText'; -type ValueOf = T[keyof T]; - export interface PunctuatorToken extends BaseToken { type: AST_TOKEN_TYPES.Punctuator; value: ValueOf; diff --git a/packages/ast-spec/src/utils.ts b/packages/ast-spec/src/utils.ts new file mode 100644 index 000000000000..5f2cf2cf07f3 --- /dev/null +++ b/packages/ast-spec/src/utils.ts @@ -0,0 +1 @@ +export type ValueOf = T[keyof T]; diff --git a/packages/ast-spec/tests/AssignmentOperatorToText.type-test.ts b/packages/ast-spec/tests/AssignmentOperatorToText.type-test.ts new file mode 100644 index 000000000000..53035facabef --- /dev/null +++ b/packages/ast-spec/tests/AssignmentOperatorToText.type-test.ts @@ -0,0 +1,10 @@ +import type { AssignmentOperator } from 'typescript'; + +import { AssignmentOperatorToText } from '../src'; + +type _Test = { + readonly [T in AssignmentOperator]: AssignmentOperatorToText[T]; + // If there are any AssignmentOperator members that don't have a corresponding + // AssignmentOperatorToText, then this line will error with "Type 'T' cannot + // be used to index type 'AssignmentOperatorToText'." +}; diff --git a/packages/eslint-plugin-internal/CHANGELOG.md b/packages/eslint-plugin-internal/CHANGELOG.md index ec72cec735d9..4a0a6da13697 100644 --- a/packages/eslint-plugin-internal/CHANGELOG.md +++ b/packages/eslint-plugin-internal/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.28.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.1...v5.28.0) (2022-06-13) + +**Note:** Version bump only for package @typescript-eslint/eslint-plugin-internal + + + + + ## [5.27.1](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.0...v5.27.1) (2022-06-06) **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 072d420171bb..472a5fcc1afb 100644 --- a/packages/eslint-plugin-internal/package.json +++ b/packages/eslint-plugin-internal/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin-internal", - "version": "5.27.1", + "version": "5.28.0", "private": true, "main": "dist/index.js", "scripts": { @@ -14,8 +14,8 @@ }, "dependencies": { "@types/prettier": "*", - "@typescript-eslint/scope-manager": "5.27.1", - "@typescript-eslint/utils": "5.27.1", + "@typescript-eslint/scope-manager": "5.28.0", + "@typescript-eslint/utils": "5.28.0", "prettier": "*" } } diff --git a/packages/eslint-plugin-tslint/CHANGELOG.md b/packages/eslint-plugin-tslint/CHANGELOG.md index 407e968c3686..5f4051d4ddfe 100644 --- a/packages/eslint-plugin-tslint/CHANGELOG.md +++ b/packages/eslint-plugin-tslint/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.28.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.1...v5.28.0) (2022-06-13) + +**Note:** Version bump only for package @typescript-eslint/eslint-plugin-tslint + + + + + ## [5.27.1](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.0...v5.27.1) (2022-06-06) **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 03a3cf55d8d4..2fcd49a2a832 100644 --- a/packages/eslint-plugin-tslint/package.json +++ b/packages/eslint-plugin-tslint/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin-tslint", - "version": "5.27.1", + "version": "5.28.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/utils": "5.27.1", + "@typescript-eslint/utils": "5.28.0", "lodash": "^4.17.21" }, "peerDependencies": { @@ -48,6 +48,6 @@ }, "devDependencies": { "@types/lodash": "*", - "@typescript-eslint/parser": "5.27.1" + "@typescript-eslint/parser": "5.28.0" } } diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index f0cccd0ce94d..062a638e1502 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -3,6 +3,23 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.28.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.1...v5.28.0) (2022-06-13) + + +### Bug Fixes + +* [TS4.7] allow visiting of typeParameters in TSTypeQuery ([#5166](https://github.com/typescript-eslint/typescript-eslint/issues/5166)) ([dc1f930](https://github.com/typescript-eslint/typescript-eslint/commit/dc1f9309cf04aa7314e758980ac687558482f47f)) +* **eslint-plugin:** [space-infix-ops] support for optional property without type ([#5155](https://github.com/typescript-eslint/typescript-eslint/issues/5155)) ([1f25daf](https://github.com/typescript-eslint/typescript-eslint/commit/1f25daf74e5d45077199f9ee9fa9bf31107f4089)) + + +### Features + +* **eslint-plugin:** [consistent-generic-constructors] add rule ([#4924](https://github.com/typescript-eslint/typescript-eslint/issues/4924)) ([921cdf1](https://github.com/typescript-eslint/typescript-eslint/commit/921cdf17e548845311d0591249616ec844503926)) + + + + + ## [5.27.1](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.0...v5.27.1) (2022-06-06) diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index ff85922117e5..60a769945183 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -102,6 +102,7 @@ Pro Tip: For larger codebases you may want to consider splitting our linting int | [`@typescript-eslint/ban-tslint-comment`](./docs/rules/ban-tslint-comment.md) | Disallow `// tslint:` comments | :lock: | :wrench: | | | [`@typescript-eslint/ban-types`](./docs/rules/ban-types.md) | Disallow certain types | :white_check_mark: | :wrench: | | | [`@typescript-eslint/class-literal-property-style`](./docs/rules/class-literal-property-style.md) | Enforce that literals on classes are exposed in a consistent style | :lock: | :wrench: | | +| [`@typescript-eslint/consistent-generic-constructors`](./docs/rules/consistent-generic-constructors.md) | Enforce specifying generic type arguments on type annotation or constructor name of a constructor call | :lock: | :wrench: | | | [`@typescript-eslint/consistent-indexed-object-style`](./docs/rules/consistent-indexed-object-style.md) | Require or disallow the `Record` type | :lock: | :wrench: | | | [`@typescript-eslint/consistent-type-assertions`](./docs/rules/consistent-type-assertions.md) | Enforce consistent usage of type assertions | :lock: | | | | [`@typescript-eslint/consistent-type-definitions`](./docs/rules/consistent-type-definitions.md) | Enforce type definitions to consistently use either `interface` or `type` | :lock: | :wrench: | | diff --git a/packages/eslint-plugin/docs/rules/README.md b/packages/eslint-plugin/docs/rules/README.md index 41cdb518c1cd..805f126f8228 100644 --- a/packages/eslint-plugin/docs/rules/README.md +++ b/packages/eslint-plugin/docs/rules/README.md @@ -24,6 +24,7 @@ See [Configs](/docs/linting/configs) for how to enable recommended rules using c | [`@typescript-eslint/ban-tslint-comment`](./ban-tslint-comment.md) | Disallow `// tslint:` comments | :lock: | :wrench: | | | [`@typescript-eslint/ban-types`](./ban-types.md) | Disallow certain types | :white_check_mark: | :wrench: | | | [`@typescript-eslint/class-literal-property-style`](./class-literal-property-style.md) | Enforce that literals on classes are exposed in a consistent style | :lock: | :wrench: | | +| [`@typescript-eslint/consistent-generic-constructors`](./consistent-generic-constructors.md) | Enforce specifying generic type arguments on type annotation or constructor name of a constructor call | :lock: | :wrench: | | | [`@typescript-eslint/consistent-indexed-object-style`](./consistent-indexed-object-style.md) | Require or disallow the `Record` type | :lock: | :wrench: | | | [`@typescript-eslint/consistent-type-assertions`](./consistent-type-assertions.md) | Enforce consistent usage of type assertions | :lock: | | | | [`@typescript-eslint/consistent-type-definitions`](./consistent-type-definitions.md) | Enforce type definitions to consistently use either `interface` or `type` | :lock: | :wrench: | | diff --git a/packages/eslint-plugin/docs/rules/consistent-generic-constructors.md b/packages/eslint-plugin/docs/rules/consistent-generic-constructors.md new file mode 100644 index 000000000000..db717dbcbd3d --- /dev/null +++ b/packages/eslint-plugin/docs/rules/consistent-generic-constructors.md @@ -0,0 +1,82 @@ +# `consistent-generic-constructors` + +Enforces specifying generic type arguments on type annotation or constructor name of a constructor call. + +When constructing a generic class, you can specify the type arguments on either the left-hand side (as a type annotation) or the right-hand side (as part of the constructor call): + +```ts +// Left-hand side +const map: Map = new Map(); + +// Right-hand side +const map = new Map(); +``` + +This rule ensures that type arguments appear consistently on one side of the declaration. + +## Options + +```jsonc +{ + "rules": { + "@typescript-eslint/consistent-generic-constructors": [ + "error", + "constructor" + ] + } +} +``` + +This rule takes a string option: + +- If it's set to `constructor` (default), type arguments that **only** appear on the type annotation are disallowed. +- If it's set to `type-annotation`, type arguments that **only** appear on the constructor are disallowed. + +## Rule Details + +The rule never reports when there are type parameters on both sides, or neither sides of the declaration. It also doesn't report if the names of the type annotation and the constructor don't match. + +### `constructor` + + + +#### ❌ Incorrect + +```ts +const map: Map = new Map(); +const set: Set = new Set(); +``` + +#### ✅ Correct + +```ts +const map = new Map(); +const map: Map = new MyMap(); +const set = new Set(); +const set = new Set(); +const set: Set = new Set(); +``` + +### `type-annotation` + + + +#### ❌ Incorrect + +```ts +const map = new Map(); +const set = new Set(); +``` + +#### ✅ Correct + +```ts +const map: Map = new Map(); +const set: Set = new Set(); +const set = new Set(); +const set: Set = new Set(); +``` + +## When Not To Use It + +You can turn this rule off if you don't want to enforce one kind of generic constructor style over the other. diff --git a/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.md b/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.md index 2b5aa6243542..b25350b60b97 100644 --- a/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.md +++ b/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.md @@ -158,10 +158,9 @@ Examples of code for this rule with `{ allowDirectConstAssertionInArrowFunctions ```ts export const func = (value: number) => ({ type: 'X', value }); -export const foo = () => - ({ - bar: true, - } as const); +export const foo = () => ({ + bar: true, +}); export const bar = () => 1; ``` diff --git a/packages/eslint-plugin/docs/rules/prefer-optional-chain.md b/packages/eslint-plugin/docs/rules/prefer-optional-chain.md index ce48aa9ceee6..c2b196a04a47 100644 --- a/packages/eslint-plugin/docs/rules/prefer-optional-chain.md +++ b/packages/eslint-plugin/docs/rules/prefer-optional-chain.md @@ -61,8 +61,8 @@ foo && foo.a && foo.a.b && foo.a.b.c; foo && foo['a'] && foo['a'].b && foo['a'].b.c; foo && foo.a && foo.a.b && foo.a.b.method && foo.a.b.method(); -(((foo || {}).a || {}).b {}).c; -(((foo || {})['a'] || {}).b {}).c; +(((foo || {}).a || {}).b || {}).c; +(((foo || {})['a'] || {}).b || {}).c; // this rule also supports converting chained strict nullish checks: foo && diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index c833b4926627..c8f58a1f21b1 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin", - "version": "5.27.1", + "version": "5.28.0", "description": "TypeScript plugin for ESLint", "keywords": [ "eslint", @@ -44,9 +44,9 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/scope-manager": "5.27.1", - "@typescript-eslint/type-utils": "5.27.1", - "@typescript-eslint/utils": "5.27.1", + "@typescript-eslint/scope-manager": "5.28.0", + "@typescript-eslint/type-utils": "5.28.0", + "@typescript-eslint/utils": "5.28.0", "debug": "^4.3.4", "functional-red-black-tree": "^1.0.1", "ignore": "^5.2.0", diff --git a/packages/eslint-plugin/src/configs/all.ts b/packages/eslint-plugin/src/configs/all.ts index 5f9562d5bac3..8742d36b2089 100644 --- a/packages/eslint-plugin/src/configs/all.ts +++ b/packages/eslint-plugin/src/configs/all.ts @@ -18,6 +18,7 @@ export = { '@typescript-eslint/comma-dangle': 'error', 'comma-spacing': 'off', '@typescript-eslint/comma-spacing': 'error', + '@typescript-eslint/consistent-generic-constructors': 'error', '@typescript-eslint/consistent-indexed-object-style': 'error', '@typescript-eslint/consistent-type-assertions': 'error', '@typescript-eslint/consistent-type-definitions': 'error', diff --git a/packages/eslint-plugin/src/configs/strict.ts b/packages/eslint-plugin/src/configs/strict.ts index bb51ebfa4f27..a9c91f7c1ca1 100644 --- a/packages/eslint-plugin/src/configs/strict.ts +++ b/packages/eslint-plugin/src/configs/strict.ts @@ -9,6 +9,7 @@ export = { '@typescript-eslint/ban-tslint-comment': 'warn', '@typescript-eslint/class-literal-property-style': 'warn', '@typescript-eslint/consistent-indexed-object-style': 'warn', + '@typescript-eslint/consistent-generic-constructors': 'warn', '@typescript-eslint/consistent-type-assertions': 'warn', '@typescript-eslint/consistent-type-definitions': 'warn', 'dot-notation': 'off', diff --git a/packages/eslint-plugin/src/rules/consistent-generic-constructors.ts b/packages/eslint-plugin/src/rules/consistent-generic-constructors.ts new file mode 100644 index 000000000000..0df1412bd7bb --- /dev/null +++ b/packages/eslint-plugin/src/rules/consistent-generic-constructors.ts @@ -0,0 +1,104 @@ +import { AST_NODE_TYPES } from '@typescript-eslint/utils'; +import { createRule } from '../util'; + +type MessageIds = 'preferTypeAnnotation' | 'preferConstructor'; +type Options = ['type-annotation' | 'constructor']; + +export default createRule({ + name: 'consistent-generic-constructors', + meta: { + type: 'suggestion', + docs: { + description: + 'Enforce specifying generic type arguments on type annotation or constructor name of a constructor call', + recommended: 'strict', + }, + messages: { + preferTypeAnnotation: + 'The generic type arguments should be specified as part of the type annotation.', + preferConstructor: + 'The generic type arguments should be specified as part of the constructor type arguments.', + }, + fixable: 'code', + schema: [ + { + enum: ['type-annotation', 'constructor'], + }, + ], + }, + defaultOptions: ['constructor'], + create(context, [mode]) { + const sourceCode = context.getSourceCode(); + return { + VariableDeclarator(node): void { + const lhs = node.id.typeAnnotation?.typeAnnotation; + const rhs = node.init; + if ( + !rhs || + rhs.type !== AST_NODE_TYPES.NewExpression || + rhs.callee.type !== AST_NODE_TYPES.Identifier + ) { + return; + } + if ( + lhs && + (lhs.type !== AST_NODE_TYPES.TSTypeReference || + lhs.typeName.type !== AST_NODE_TYPES.Identifier || + lhs.typeName.name !== rhs.callee.name) + ) { + return; + } + if (mode === 'type-annotation') { + if (!lhs && rhs.typeParameters) { + const { typeParameters, callee } = rhs; + const typeAnnotation = + sourceCode.getText(callee) + sourceCode.getText(typeParameters); + context.report({ + node, + messageId: 'preferTypeAnnotation', + fix(fixer) { + return [ + fixer.remove(typeParameters), + fixer.insertTextAfter(node.id, ': ' + typeAnnotation), + ]; + }, + }); + } + return; + } + if (mode === 'constructor') { + if (lhs?.typeParameters && !rhs.typeParameters) { + const hasParens = + sourceCode.getTokenAfter(rhs.callee)?.value === '('; + const extraComments = new Set( + sourceCode.getCommentsInside(lhs.parent!), + ); + sourceCode + .getCommentsInside(lhs.typeParameters) + .forEach(c => extraComments.delete(c)); + context.report({ + node, + messageId: 'preferConstructor', + *fix(fixer) { + yield fixer.remove(lhs.parent!); + for (const comment of extraComments) { + yield fixer.insertTextAfter( + rhs.callee, + sourceCode.getText(comment), + ); + } + yield fixer.insertTextAfter( + rhs.callee, + sourceCode.getText(lhs.typeParameters), + ); + if (!hasParens) { + yield fixer.insertTextAfter(rhs.callee, '()'); + } + }, + }); + } + } + }, + }; + }, +}); diff --git a/packages/eslint-plugin/src/rules/index.ts b/packages/eslint-plugin/src/rules/index.ts index 41afc88199f2..29a47ec2384a 100644 --- a/packages/eslint-plugin/src/rules/index.ts +++ b/packages/eslint-plugin/src/rules/index.ts @@ -8,6 +8,7 @@ import braceStyle from './brace-style'; import classLiteralPropertyStyle from './class-literal-property-style'; import commaDangle from './comma-dangle'; import commaSpacing from './comma-spacing'; +import consistentGenericConstructors from './consistent-generic-constructors'; import consistentIndexedObjectStyle from './consistent-indexed-object-style'; import consistentTypeAssertions from './consistent-type-assertions'; import consistentTypeDefinitions from './consistent-type-definitions'; @@ -136,6 +137,7 @@ export default { 'class-literal-property-style': classLiteralPropertyStyle, 'comma-dangle': commaDangle, 'comma-spacing': commaSpacing, + 'consistent-generic-constructors': consistentGenericConstructors, 'consistent-indexed-object-style': consistentIndexedObjectStyle, 'consistent-type-assertions': consistentTypeAssertions, 'consistent-type-definitions': consistentTypeDefinitions, diff --git a/packages/eslint-plugin/src/rules/space-infix-ops.ts b/packages/eslint-plugin/src/rules/space-infix-ops.ts index a43ba5c30ab3..9cab8d27f529 100644 --- a/packages/eslint-plugin/src/rules/space-infix-ops.ts +++ b/packages/eslint-plugin/src/rules/space-infix-ops.ts @@ -36,13 +36,9 @@ export default util.createRule({ const rules = baseRule.create(context); const sourceCode = context.getSourceCode(); - const report = ( - node: TSESTree.Node | TSESTree.Token, - operator: TSESTree.Token, - ): void => { + function report(operator: TSESTree.Token): void { context.report({ - node: node, - loc: operator.loc, + node: operator, messageId: 'missingSpace', data: { operator: operator.value, @@ -65,21 +61,19 @@ export default util.createRule({ return fixer.replaceText(operator, fixString); }, }); - }; + } function isSpaceChar(token: TSESTree.Token): boolean { return ( - token.type === AST_TOKEN_TYPES.Punctuator && - /^[=|?|:]$/.test(token.value) + token.type === AST_TOKEN_TYPES.Punctuator && /^[=?:]$/.test(token.value) ); } function checkAndReportAssignmentSpace( - node: TSESTree.Node, - leftNode: TSESTree.Token, - rightNode?: TSESTree.Token | null, + leftNode: TSESTree.Token | TSESTree.Node | null, + rightNode?: TSESTree.Token | TSESTree.Node | null, ): void { - if (!rightNode) { + if (!rightNode || !leftNode) { return; } @@ -87,16 +81,16 @@ export default util.createRule({ leftNode, rightNode, isSpaceChar, - ); + )!; - const prev = sourceCode.getTokenBefore(operator!); - const next = sourceCode.getTokenAfter(operator!); + const prev = sourceCode.getTokenBefore(operator)!; + const next = sourceCode.getTokenAfter(operator)!; if ( - !sourceCode.isSpaceBetween!(prev!, operator!) || - !sourceCode.isSpaceBetween!(operator!, next!) + !sourceCode.isSpaceBetween!(prev, operator) || + !sourceCode.isSpaceBetween!(operator, next) ) { - report(node, operator!); + report(operator); } } @@ -105,16 +99,7 @@ export default util.createRule({ * @param node The node to report */ function checkForEnumAssignmentSpace(node: TSESTree.TSEnumMember): void { - if (!node.initializer) { - return; - } - - const leftNode = sourceCode.getTokenByRangeStart(node.id.range[0])!; - const rightNode = sourceCode.getTokenByRangeStart( - node.initializer.range[0], - )!; - - checkAndReportAssignmentSpace(node, leftNode, rightNode); + checkAndReportAssignmentSpace(node.id, node.initializer); } /** @@ -124,14 +109,12 @@ export default util.createRule({ function checkForPropertyDefinitionAssignmentSpace( node: TSESTree.PropertyDefinition, ): void { - const leftNode = sourceCode.getLastToken( - node.typeAnnotation ?? node.key, - )!; - const rightNode = node.value - ? sourceCode.getTokenByRangeStart(node.value.range[0]) - : undefined; + const leftNode = + node.optional && !node.typeAnnotation + ? sourceCode.getTokenAfter(node.key) + : node.typeAnnotation ?? node.key; - checkAndReportAssignmentSpace(node, leftNode, rightNode); + checkAndReportAssignmentSpace(leftNode, node.value); } /** @@ -161,7 +144,7 @@ export default util.createRule({ !sourceCode.isSpaceBetween!(prev!, operator) || !sourceCode.isSpaceBetween!(operator, next!) ) { - report(typeAnnotation, operator); + report(operator); } } }); @@ -174,20 +157,15 @@ export default util.createRule({ function checkForTypeAliasAssignment( node: TSESTree.TSTypeAliasDeclaration, ): void { - const leftNode = sourceCode.getLastToken(node.typeParameters ?? node.id)!; - const rightNode = sourceCode.getFirstToken(node.typeAnnotation); - - checkAndReportAssignmentSpace(node, leftNode, rightNode); + checkAndReportAssignmentSpace( + node.typeParameters ?? node.id, + node.typeAnnotation, + ); } function checkForTypeConditional(node: TSESTree.TSConditionalType): void { - const extendsLastToken = sourceCode.getLastToken(node.extendsType)!; - const trueFirstToken = sourceCode.getFirstToken(node.trueType)!; - const trueLastToken = sourceCode.getLastToken(node.trueType)!; - const falseFirstToken = sourceCode.getFirstToken(node.falseType)!; - - checkAndReportAssignmentSpace(node, extendsLastToken, trueFirstToken); - checkAndReportAssignmentSpace(node, trueLastToken, falseFirstToken); + checkAndReportAssignmentSpace(node.extendsType, node.trueType); + checkAndReportAssignmentSpace(node.trueType, node.falseType); } return { diff --git a/packages/eslint-plugin/tests/rules/consistent-generic-constructors.test.ts b/packages/eslint-plugin/tests/rules/consistent-generic-constructors.test.ts new file mode 100644 index 000000000000..0fe3bcae7fb0 --- /dev/null +++ b/packages/eslint-plugin/tests/rules/consistent-generic-constructors.test.ts @@ -0,0 +1,217 @@ +import rule from '../../src/rules/consistent-generic-constructors'; +import { RuleTester, noFormat } from '../RuleTester'; + +const ruleTester = new RuleTester({ + parser: '@typescript-eslint/parser', +}); + +ruleTester.run('consistent-generic-constructors', rule, { + valid: [ + // default: constructor + 'const a = new Foo();', + 'const a = new Foo();', + 'const a: Foo = new Foo();', + 'const a: Foo = new Foo();', + 'const a: Bar = new Foo();', + 'const a: Foo = new Foo();', + 'const a: Bar = new Foo();', + 'const a: Bar = new Foo();', + 'const a: Foo = Foo();', + 'const a: Foo = Foo();', + 'const a: Foo = Foo();', + // type-annotation + { + code: 'const a = new Foo();', + options: ['type-annotation'], + }, + { + code: 'const a: Foo = new Foo();', + options: ['type-annotation'], + }, + { + code: 'const a: Foo = new Foo();', + options: ['type-annotation'], + }, + { + code: 'const a: Foo = new Foo();', + options: ['type-annotation'], + }, + { + code: 'const a: Bar = new Foo();', + options: ['type-annotation'], + }, + { + code: 'const a: Bar = new Foo();', + options: ['type-annotation'], + }, + { + code: 'const a: Foo = Foo();', + options: ['type-annotation'], + }, + { + code: 'const a: Foo = Foo();', + options: ['type-annotation'], + }, + { + code: 'const a: Foo = Foo();', + options: ['type-annotation'], + }, + { + code: 'const a = new (class C {})();', + options: ['type-annotation'], + }, + ], + invalid: [ + { + code: 'const a: Foo = new Foo();', + errors: [ + { + messageId: 'preferConstructor', + }, + ], + output: 'const a = new Foo();', + }, + { + code: 'const a: Map = new Map();', + errors: [ + { + messageId: 'preferConstructor', + }, + ], + output: 'const a = new Map();', + }, + { + code: noFormat`const a: Map = new Map();`, + errors: [ + { + messageId: 'preferConstructor', + }, + ], + output: noFormat`const a = new Map();`, + }, + { + code: noFormat`const a: Map< string, number > = new Map();`, + errors: [ + { + messageId: 'preferConstructor', + }, + ], + output: noFormat`const a = new Map< string, number >();`, + }, + { + code: noFormat`const a: Map = new Map ();`, + errors: [ + { + messageId: 'preferConstructor', + }, + ], + output: noFormat`const a = new Map ();`, + }, + { + code: noFormat`const a: Foo = new Foo;`, + errors: [ + { + messageId: 'preferConstructor', + }, + ], + output: noFormat`const a = new Foo();`, + }, + { + code: 'const a: /* comment */ Foo/* another */ = new Foo();', + errors: [ + { + messageId: 'preferConstructor', + }, + ], + output: noFormat`const a = new Foo/* comment *//* another */();`, + }, + { + code: 'const a: Foo/* comment */ = new Foo /* another */();', + errors: [ + { + messageId: 'preferConstructor', + }, + ], + output: noFormat`const a = new Foo/* comment */ /* another */();`, + }, + { + code: noFormat`const a: Foo = new \n Foo \n ();`, + errors: [ + { + messageId: 'preferConstructor', + }, + ], + output: noFormat`const a = new \n Foo \n ();`, + }, + { + code: 'const a = new Foo();', + options: ['type-annotation'], + errors: [ + { + messageId: 'preferTypeAnnotation', + }, + ], + output: 'const a: Foo = new Foo();', + }, + { + code: 'const a = new Map();', + options: ['type-annotation'], + errors: [ + { + messageId: 'preferTypeAnnotation', + }, + ], + output: 'const a: Map = new Map();', + }, + { + code: noFormat`const a = new Map ();`, + options: ['type-annotation'], + errors: [ + { + messageId: 'preferTypeAnnotation', + }, + ], + output: noFormat`const a: Map = new Map ();`, + }, + { + code: noFormat`const a = new Map< string, number >();`, + options: ['type-annotation'], + errors: [ + { + messageId: 'preferTypeAnnotation', + }, + ], + output: noFormat`const a: Map< string, number > = new Map();`, + }, + { + code: noFormat`const a = new \n Foo \n ();`, + options: ['type-annotation'], + errors: [ + { + messageId: 'preferTypeAnnotation', + }, + ], + output: noFormat`const a: Foo = new \n Foo \n ();`, + }, + { + code: 'const a = new Foo/* comment */ /* another */();', + options: ['type-annotation'], + errors: [ + { + messageId: 'preferTypeAnnotation', + }, + ], + output: noFormat`const a: Foo = new Foo/* comment */ /* another */();`, + }, + { + code: 'const a = new Foo();', + options: ['type-annotation'], + errors: [ + { + messageId: 'preferTypeAnnotation', + }, + ], + output: noFormat`const a: Foo = new Foo();`, + }, + ], +}); diff --git a/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts b/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts index fb7eadb47b71..cca98d2a952b 100644 --- a/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts @@ -739,6 +739,15 @@ export function foo() { return new Promise(); } `, + // https://github.com/typescript-eslint/typescript-eslint/issues/5152 + { + code: noFormat` +function foo(value: T): T { + return { value }; +} +export type Foo = typeof foo; + `, + }, // https://github.com/typescript-eslint/typescript-eslint/issues/2331 { code: ` diff --git a/packages/eslint-plugin/tests/rules/space-infix-ops.test.ts b/packages/eslint-plugin/tests/rules/space-infix-ops.test.ts index e8b5fa2bc930..37060fab7457 100644 --- a/packages/eslint-plugin/tests/rules/space-infix-ops.test.ts +++ b/packages/eslint-plugin/tests/rules/space-infix-ops.test.ts @@ -165,6 +165,20 @@ ruleTester.run('space-infix-ops', rule, { } `, }, + { + code: ` + class Test { + value: string & number; + } + `, + }, + { + code: ` + class Test { + optional? = false; + } + `, + }, { code: ` type Test = @@ -379,13 +393,6 @@ ruleTester.run('space-infix-ops', rule, { const x: string & (((() => void))); `, }, - { - code: ` - class Test { - value: string & number; - } - `, - }, { code: ` function foo() {} @@ -984,6 +991,91 @@ ruleTester.run('space-infix-ops', rule, { }, ], }, + { + code: ` + type Test = |string|(((() => void)))|string; + `, + output: ` + type Test = | string | (((() => void))) | string; + `, + errors: [ + { + messageId: 'missingSpace', + column: 21, + line: 2, + }, + { + messageId: 'missingSpace', + column: 28, + line: 2, + }, + { + messageId: 'missingSpace', + column: 45, + line: 2, + }, + ], + }, + { + code: ` + type Test=|string|(((() => void)))|string; + `, + output: ` + type Test = |string | (((() => void))) | string; + `, + errors: [ + { + messageId: 'missingSpace', + column: 18, + line: 2, + }, + { + messageId: 'missingSpace', + column: 19, + line: 2, + }, + { + messageId: 'missingSpace', + column: 26, + line: 2, + }, + { + messageId: 'missingSpace', + column: 43, + line: 2, + }, + ], + }, + { + code: ` + type Test=(string&number)|string|(((() => void))); + `, + output: ` + type Test = (string & number) | string | (((() => void))); + `, + errors: [ + { + messageId: 'missingSpace', + column: 18, + line: 2, + }, + { + messageId: 'missingSpace', + column: 26, + line: 2, + }, + { + messageId: 'missingSpace', + column: 34, + line: 2, + }, + { + messageId: 'missingSpace', + column: 41, + line: 2, + }, + ], + }, { code: ` type Test = @@ -1861,6 +1953,25 @@ ruleTester.run('space-infix-ops', rule, { }, ], }, + { + code: ` + class Test { + optional?= false; + } + `, + output: ` + class Test { + optional? = false; + } + `, + errors: [ + { + messageId: 'missingSpace', + column: 20, + line: 3, + }, + ], + }, { code: ` function foo() {} diff --git a/packages/experimental-utils/CHANGELOG.md b/packages/experimental-utils/CHANGELOG.md index b3d9d9d767e7..baea50af726e 100644 --- a/packages/experimental-utils/CHANGELOG.md +++ b/packages/experimental-utils/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.28.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.1...v5.28.0) (2022-06-13) + +**Note:** Version bump only for package @typescript-eslint/experimental-utils + + + + + ## [5.27.1](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.0...v5.27.1) (2022-06-06) **Note:** Version bump only for package @typescript-eslint/experimental-utils diff --git a/packages/experimental-utils/package.json b/packages/experimental-utils/package.json index e37d30782a5d..63850eab7d55 100644 --- a/packages/experimental-utils/package.json +++ b/packages/experimental-utils/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/experimental-utils", - "version": "5.27.1", + "version": "5.28.0", "description": "(Experimental) Utilities for working with TypeScript + ESLint together", "keywords": [ "eslint", @@ -38,7 +38,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/utils": "5.27.1" + "@typescript-eslint/utils": "5.28.0" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" diff --git a/packages/parser/CHANGELOG.md b/packages/parser/CHANGELOG.md index 4785b23ee9d0..6462749fbf93 100644 --- a/packages/parser/CHANGELOG.md +++ b/packages/parser/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.28.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.1...v5.28.0) (2022-06-13) + +**Note:** Version bump only for package @typescript-eslint/parser + + + + + ## [5.27.1](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.0...v5.27.1) (2022-06-06) **Note:** Version bump only for package @typescript-eslint/parser diff --git a/packages/parser/package.json b/packages/parser/package.json index acf1c65fe71d..c4689384da17 100644 --- a/packages/parser/package.json +++ b/packages/parser/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/parser", - "version": "5.27.1", + "version": "5.28.0", "description": "An ESLint custom parser which leverages TypeScript ESTree", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -44,9 +44,9 @@ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "dependencies": { - "@typescript-eslint/scope-manager": "5.27.1", - "@typescript-eslint/types": "5.27.1", - "@typescript-eslint/typescript-estree": "5.27.1", + "@typescript-eslint/scope-manager": "5.28.0", + "@typescript-eslint/types": "5.28.0", + "@typescript-eslint/typescript-estree": "5.28.0", "debug": "^4.3.4" }, "devDependencies": { diff --git a/packages/scope-manager/CHANGELOG.md b/packages/scope-manager/CHANGELOG.md index 51a94bcea8ac..a7a02ddc2511 100644 --- a/packages/scope-manager/CHANGELOG.md +++ b/packages/scope-manager/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.28.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.1...v5.28.0) (2022-06-13) + + +### Bug Fixes + +* [TS4.7] allow visiting of typeParameters in TSTypeQuery ([#5166](https://github.com/typescript-eslint/typescript-eslint/issues/5166)) ([dc1f930](https://github.com/typescript-eslint/typescript-eslint/commit/dc1f9309cf04aa7314e758980ac687558482f47f)) + + + + + ## [5.27.1](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.0...v5.27.1) (2022-06-06) **Note:** Version bump only for package @typescript-eslint/scope-manager diff --git a/packages/scope-manager/package.json b/packages/scope-manager/package.json index 7326b5d8dfe0..7e0463a4c139 100644 --- a/packages/scope-manager/package.json +++ b/packages/scope-manager/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/scope-manager", - "version": "5.27.1", + "version": "5.28.0", "description": "TypeScript scope analyser for ESLint", "keywords": [ "eslint", @@ -38,12 +38,12 @@ "typecheck": "cd ../../ && nx typecheck @typescript-eslint/scope-manager" }, "dependencies": { - "@typescript-eslint/types": "5.27.1", - "@typescript-eslint/visitor-keys": "5.27.1" + "@typescript-eslint/types": "5.28.0", + "@typescript-eslint/visitor-keys": "5.28.0" }, "devDependencies": { "@types/glob": "*", - "@typescript-eslint/typescript-estree": "5.27.1", + "@typescript-eslint/typescript-estree": "5.28.0", "glob": "*", "jest-specific-snapshot": "*", "make-dir": "*", diff --git a/packages/scope-manager/src/referencer/TypeVisitor.ts b/packages/scope-manager/src/referencer/TypeVisitor.ts index e9abb40f4f42..0d345a149a29 100644 --- a/packages/scope-manager/src/referencer/TypeVisitor.ts +++ b/packages/scope-manager/src/referencer/TypeVisitor.ts @@ -265,6 +265,7 @@ class TypeVisitor extends Visitor { } this.#referencer.currentScope().referenceValue(expr); } + this.visit(node.typeParameters); } protected TSTypeAnnotation(node: TSESTree.TSTypeAnnotation): void { diff --git a/packages/scope-manager/tests/fixtures.test.ts b/packages/scope-manager/tests/fixtures.test.ts index f029367ba06e..b5a2fc70bd67 100644 --- a/packages/scope-manager/tests/fixtures.test.ts +++ b/packages/scope-manager/tests/fixtures.test.ts @@ -13,7 +13,9 @@ const ONLY = [].join(path.sep); const FIXTURES_DIR = path.resolve(__dirname, 'fixtures'); const fixtures = glob - .sync(`${FIXTURES_DIR}/**/*.{js,ts,jsx,tsx}`, { + .sync('**/*.{js,ts,jsx,tsx}', { + cwd: FIXTURES_DIR, + absolute: true, ignore: ['fixtures.test.ts'], }) .map(absolute => { diff --git a/packages/scope-manager/tests/fixtures/type-declaration/type-query-with-parameters.ts b/packages/scope-manager/tests/fixtures/type-declaration/type-query-with-parameters.ts new file mode 100644 index 000000000000..e8928f9f914a --- /dev/null +++ b/packages/scope-manager/tests/fixtures/type-declaration/type-query-with-parameters.ts @@ -0,0 +1,5 @@ +function foo(y: T) { + return { y }; +} + +export type Foo = typeof foo; diff --git a/packages/scope-manager/tests/fixtures/type-declaration/type-query-with-parameters.ts.shot b/packages/scope-manager/tests/fixtures/type-declaration/type-query-with-parameters.ts.shot new file mode 100644 index 000000000000..7ec279b55f82 --- /dev/null +++ b/packages/scope-manager/tests/fixtures/type-declaration/type-query-with-parameters.ts.shot @@ -0,0 +1,167 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`type-declaration type-query-with-parameters 1`] = ` +ScopeManager { + variables: Array [ + ImplicitGlobalConstTypeVariable, + Variable$2 { + defs: Array [ + FunctionNameDefinition$1 { + name: Identifier<"foo">, + node: FunctionDeclaration$1, + }, + ], + name: "foo", + references: Array [ + Reference$3 { + identifier: Identifier<"foo">, + isRead: true, + isTypeReference: false, + isValueReference: true, + isWrite: false, + resolved: Variable$2, + }, + ], + isValueVariable: true, + isTypeVariable: false, + }, + Variable$3 { + defs: Array [], + name: "arguments", + references: Array [], + isValueVariable: true, + isTypeVariable: true, + }, + Variable$4 { + defs: Array [ + ParameterDefinition$2 { + name: Identifier<"y">, + node: FunctionDeclaration$1, + }, + ], + name: "y", + references: Array [ + Reference$2 { + identifier: Identifier<"y">, + isRead: true, + isTypeReference: false, + isValueReference: true, + isWrite: false, + resolved: Variable$4, + }, + ], + isValueVariable: true, + isTypeVariable: false, + }, + Variable$5 { + defs: Array [ + TypeDefinition$3 { + name: Identifier<"T">, + node: TSTypeParameter$2, + }, + ], + name: "T", + references: Array [ + Reference$1 { + identifier: Identifier<"T">, + isRead: true, + isTypeReference: true, + isValueReference: false, + isWrite: false, + resolved: Variable$5, + }, + ], + isValueVariable: false, + isTypeVariable: true, + }, + Variable$6 { + defs: Array [ + TypeDefinition$4 { + name: Identifier<"Foo">, + node: TSTypeAliasDeclaration$3, + }, + ], + name: "Foo", + references: Array [], + isValueVariable: false, + isTypeVariable: true, + }, + Variable$7 { + defs: Array [ + TypeDefinition$5 { + name: Identifier<"T">, + node: TSTypeParameter$4, + }, + ], + name: "T", + references: Array [ + Reference$4 { + identifier: Identifier<"T">, + isRead: true, + isTypeReference: true, + isValueReference: false, + isWrite: false, + resolved: Variable$7, + }, + ], + isValueVariable: false, + isTypeVariable: true, + }, + ], + scopes: Array [ + GlobalScope$1 { + block: Program$5, + isStrict: false, + references: Array [], + set: Map { + "const" => ImplicitGlobalConstTypeVariable, + "foo" => Variable$2, + "Foo" => Variable$6, + }, + type: "global", + upper: null, + variables: Array [ + ImplicitGlobalConstTypeVariable, + Variable$2, + Variable$6, + ], + }, + FunctionScope$2 { + block: FunctionDeclaration$1, + isStrict: false, + references: Array [ + Reference$1, + Reference$2, + ], + set: Map { + "arguments" => Variable$3, + "y" => Variable$4, + "T" => Variable$5, + }, + type: "function", + upper: GlobalScope$1, + variables: Array [ + Variable$3, + Variable$4, + Variable$5, + ], + }, + TypeScope$3 { + block: TSTypeAliasDeclaration$3, + isStrict: true, + references: Array [ + Reference$3, + Reference$4, + ], + set: Map { + "T" => Variable$7, + }, + type: "type", + upper: GlobalScope$1, + variables: Array [ + Variable$7, + ], + }, + ], +} +`; diff --git a/packages/shared-fixtures/CHANGELOG.md b/packages/shared-fixtures/CHANGELOG.md index 469780eb7d87..cd3d2d5d9f69 100644 --- a/packages/shared-fixtures/CHANGELOG.md +++ b/packages/shared-fixtures/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.28.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.1...v5.28.0) (2022-06-13) + +**Note:** Version bump only for package @typescript-eslint/shared-fixtures + + + + + ## [5.27.1](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.0...v5.27.1) (2022-06-06) **Note:** Version bump only for package @typescript-eslint/shared-fixtures diff --git a/packages/shared-fixtures/package.json b/packages/shared-fixtures/package.json index 4e466a4fc88f..fc6622a52218 100644 --- a/packages/shared-fixtures/package.json +++ b/packages/shared-fixtures/package.json @@ -1,5 +1,5 @@ { "name": "@typescript-eslint/shared-fixtures", - "version": "5.27.1", + "version": "5.28.0", "private": true } diff --git a/packages/type-utils/CHANGELOG.md b/packages/type-utils/CHANGELOG.md index def402e214b4..03680868999e 100644 --- a/packages/type-utils/CHANGELOG.md +++ b/packages/type-utils/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.28.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.1...v5.28.0) (2022-06-13) + +**Note:** Version bump only for package @typescript-eslint/type-utils + + + + + ## [5.27.1](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.0...v5.27.1) (2022-06-06) **Note:** Version bump only for package @typescript-eslint/type-utils diff --git a/packages/type-utils/package.json b/packages/type-utils/package.json index bba58e43f79e..7f75be1bb591 100644 --- a/packages/type-utils/package.json +++ b/packages/type-utils/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/type-utils", - "version": "5.27.1", + "version": "5.28.0", "description": "Type utilities for working with TypeScript + ESLint together", "keywords": [ "eslint", @@ -39,12 +39,12 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/utils": "5.27.1", + "@typescript-eslint/utils": "5.28.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, "devDependencies": { - "@typescript-eslint/parser": "5.27.1", + "@typescript-eslint/parser": "5.28.0", "typescript": "*" }, "peerDependencies": { diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index aed8d0b7864e..deb9bedc7224 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.28.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.1...v5.28.0) (2022-06-13) + +**Note:** Version bump only for package @typescript-eslint/types + + + + + ## [5.27.1](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.0...v5.27.1) (2022-06-06) **Note:** Version bump only for package @typescript-eslint/types diff --git a/packages/types/package.json b/packages/types/package.json index f48b090e6d1d..8322bef44356 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/types", - "version": "5.27.1", + "version": "5.28.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 0375965a65ca..01eb3ecfc4ef 100644 --- a/packages/typescript-estree/CHANGELOG.md +++ b/packages/typescript-estree/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.28.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.1...v5.28.0) (2022-06-13) + +**Note:** Version bump only for package @typescript-eslint/typescript-estree + + + + + ## [5.27.1](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.0...v5.27.1) (2022-06-06) **Note:** Version bump only for package @typescript-eslint/typescript-estree diff --git a/packages/typescript-estree/package.json b/packages/typescript-estree/package.json index 15bccb08d032..6411ef0be095 100644 --- a/packages/typescript-estree/package.json +++ b/packages/typescript-estree/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/typescript-estree", - "version": "5.27.1", + "version": "5.28.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": "5.27.1", - "@typescript-eslint/visitor-keys": "5.27.1", + "@typescript-eslint/types": "5.28.0", + "@typescript-eslint/visitor-keys": "5.28.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -58,7 +58,7 @@ "@types/is-glob": "*", "@types/semver": "*", "@types/tmp": "*", - "@typescript-eslint/shared-fixtures": "5.27.1", + "@typescript-eslint/shared-fixtures": "5.28.0", "glob": "*", "jest-specific-snapshot": "*", "make-dir": "*", diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md index e91009644499..aff6cc238df7 100644 --- a/packages/utils/CHANGELOG.md +++ b/packages/utils/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.28.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.1...v5.28.0) (2022-06-13) + + +### Features + +* **eslint-plugin:** [consistent-generic-constructors] add rule ([#4924](https://github.com/typescript-eslint/typescript-eslint/issues/4924)) ([921cdf1](https://github.com/typescript-eslint/typescript-eslint/commit/921cdf17e548845311d0591249616ec844503926)) + + + + + ## [5.27.1](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.0...v5.27.1) (2022-06-06) **Note:** Version bump only for package @typescript-eslint/utils diff --git a/packages/utils/package.json b/packages/utils/package.json index b3b099ae1abc..b235586b1f1a 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/utils", - "version": "5.27.1", + "version": "5.28.0", "description": "Utilities for working with TypeScript + ESLint together", "keywords": [ "eslint", @@ -40,9 +40,9 @@ }, "dependencies": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.27.1", - "@typescript-eslint/types": "5.27.1", - "@typescript-eslint/typescript-estree": "5.27.1", + "@typescript-eslint/scope-manager": "5.28.0", + "@typescript-eslint/types": "5.28.0", + "@typescript-eslint/typescript-estree": "5.28.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" }, diff --git a/packages/utils/src/ts-eslint/SourceCode.ts b/packages/utils/src/ts-eslint/SourceCode.ts index 7ecc7ab1b095..17893d25b50a 100644 --- a/packages/utils/src/ts-eslint/SourceCode.ts +++ b/packages/utils/src/ts-eslint/SourceCode.ts @@ -276,7 +276,7 @@ declare class SourceCodeBase extends TokenStore { * @returns The text representing the AST node. */ getText( - node?: TSESTree.Node, + node?: TSESTree.Node | TSESTree.Token, beforeCount?: number, afterCount?: number, ): string; diff --git a/packages/visitor-keys/CHANGELOG.md b/packages/visitor-keys/CHANGELOG.md index 3d024f5700be..e04c340df8e7 100644 --- a/packages/visitor-keys/CHANGELOG.md +++ b/packages/visitor-keys/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.28.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.1...v5.28.0) (2022-06-13) + + +### Bug Fixes + +* [TS4.7] allow visiting of typeParameters in TSTypeQuery ([#5166](https://github.com/typescript-eslint/typescript-eslint/issues/5166)) ([dc1f930](https://github.com/typescript-eslint/typescript-eslint/commit/dc1f9309cf04aa7314e758980ac687558482f47f)) + + + + + ## [5.27.1](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.0...v5.27.1) (2022-06-06) **Note:** Version bump only for package @typescript-eslint/visitor-keys diff --git a/packages/visitor-keys/package.json b/packages/visitor-keys/package.json index 241e81c52e90..0037aa4bb762 100644 --- a/packages/visitor-keys/package.json +++ b/packages/visitor-keys/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/visitor-keys", - "version": "5.27.1", + "version": "5.28.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": "5.27.1", + "@typescript-eslint/types": "5.28.0", "eslint-visitor-keys": "^3.3.0" }, "devDependencies": { diff --git a/packages/visitor-keys/src/visitor-keys.ts b/packages/visitor-keys/src/visitor-keys.ts index f7be9f1aed8c..4c3a26d40665 100644 --- a/packages/visitor-keys/src/visitor-keys.ts +++ b/packages/visitor-keys/src/visitor-keys.ts @@ -142,7 +142,7 @@ const additionalKeys: AdditionalKeys = { TSTypeParameterDeclaration: ['params'], TSTypeParameterInstantiation: ['params'], TSTypePredicate: ['typeAnnotation', 'parameterName'], - TSTypeQuery: ['exprName'], + TSTypeQuery: ['exprName', 'typeParameters'], TSTypeReference: ['typeName', 'typeParameters'], TSUndefinedKeyword: [], TSUnionType: ['types'], diff --git a/packages/website-eslint/CHANGELOG.md b/packages/website-eslint/CHANGELOG.md index 6d1f412f6258..3b86e7f26a85 100644 --- a/packages/website-eslint/CHANGELOG.md +++ b/packages/website-eslint/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.28.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.1...v5.28.0) (2022-06-13) + +**Note:** Version bump only for package @typescript-eslint/website-eslint + + + + + ## [5.27.1](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.0...v5.27.1) (2022-06-06) **Note:** Version bump only for package @typescript-eslint/website-eslint diff --git a/packages/website-eslint/package.json b/packages/website-eslint/package.json index 0dfb42cabfd5..e911194ebccf 100644 --- a/packages/website-eslint/package.json +++ b/packages/website-eslint/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/website-eslint", - "version": "5.27.1", + "version": "5.28.0", "private": true, "description": "ESLint which works in browsers.", "engines": { @@ -16,19 +16,19 @@ "format": "prettier --write \"./**/*.{ts,mts,cts,tsx,js,mjs,cjs,jsx,json,md,css}\" --ignore-path ../../.prettierignore" }, "dependencies": { - "@typescript-eslint/types": "5.27.1", - "@typescript-eslint/utils": "5.27.1" + "@typescript-eslint/types": "5.28.0", + "@typescript-eslint/utils": "5.28.0" }, "devDependencies": { "@rollup/plugin-commonjs": "^22.0.0", "@rollup/plugin-json": "^4.1.0", "@rollup/plugin-node-resolve": "^13.3.0", "@rollup/pluginutils": "^4.2.1", - "@typescript-eslint/eslint-plugin": "5.27.1", - "@typescript-eslint/parser": "5.27.1", - "@typescript-eslint/scope-manager": "5.27.1", - "@typescript-eslint/typescript-estree": "5.27.1", - "@typescript-eslint/visitor-keys": "5.27.1", + "@typescript-eslint/eslint-plugin": "5.28.0", + "@typescript-eslint/parser": "5.28.0", + "@typescript-eslint/scope-manager": "5.28.0", + "@typescript-eslint/typescript-estree": "5.28.0", + "@typescript-eslint/visitor-keys": "5.28.0", "eslint": "*", "rollup": "^2.75.4", "rollup-plugin-terser": "^7.0.2", diff --git a/packages/website/CHANGELOG.md b/packages/website/CHANGELOG.md index 2f7b8097edc2..b7e48f0e5abc 100644 --- a/packages/website/CHANGELOG.md +++ b/packages/website/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.28.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.1...v5.28.0) (2022-06-13) + +**Note:** Version bump only for package website + + + + + ## [5.27.1](https://github.com/typescript-eslint/typescript-eslint/compare/v5.27.0...v5.27.1) (2022-06-06) **Note:** Version bump only for package website diff --git a/packages/website/docusaurusConfig.ts b/packages/website/docusaurusConfig.ts index eab99e5d2eb3..ed8d4deaa0cf 100644 --- a/packages/website/docusaurusConfig.ts +++ b/packages/website/docusaurusConfig.ts @@ -139,6 +139,23 @@ const themeConfig: ThemeCommonConfig & AlgoliaThemeConfig = { styles: [], }, additionalLanguages: ['ignore'], + magicComments: [ + { + className: 'theme-code-block-highlighted-line', + line: 'highlight-next-line', + block: { start: 'highlight-start', end: 'highlight-end' }, + }, + { + className: 'code-block-removed-line', + line: 'Remove this line', + block: { start: 'Removed lines start', end: 'Removed lines end' }, + }, + { + className: 'code-block-added-line', + line: 'Add this line', + block: { start: 'Added lines start', end: 'Added lines end' }, + }, + ], }, tableOfContents: { maxHeadingLevel: 4, diff --git a/packages/website/package.json b/packages/website/package.json index ffa80744244b..8157c02761cb 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -1,6 +1,6 @@ { "name": "website", - "version": "5.27.1", + "version": "5.28.0", "private": true, "scripts": { "build": "docusaurus build", @@ -20,12 +20,13 @@ "@docusaurus/remark-plugin-npm2yarn": "2.0.0-beta.21", "@docusaurus/theme-common": "2.0.0-beta.21", "@mdx-js/react": "1.6.22", - "@typescript-eslint/website-eslint": "5.27.1", + "@typescript-eslint/website-eslint": "5.28.0", "clsx": "^1.1.1", "eslint": "*", "json5": "^2.2.1", "konamimojisplosion": "^0.5.1", "lzstring.ts": "^2.0.2", + "prism-react-renderer": "^1.3.3", "react": "^18.1.0", "react-dom": "^18.1.0", "remark-docusaurus-tabs": "^0.2.0", @@ -36,7 +37,7 @@ "@types/react": "^18.0.9", "@types/react-helmet": "^6.1.5", "@types/react-router-dom": "^5.3.3", - "@typescript-eslint/eslint-plugin": "5.27.1", + "@typescript-eslint/eslint-plugin": "5.28.0", "copy-webpack-plugin": "^11.0.0", "cypress": "8.3.0", "cypress-axe": "^0.14.0", diff --git a/packages/website/src/components/ErrorsViewer.module.css b/packages/website/src/components/ErrorsViewer.module.css index fab012b69e88..22178ae72acd 100644 --- a/packages/website/src/components/ErrorsViewer.module.css +++ b/packages/website/src/components/ErrorsViewer.module.css @@ -13,9 +13,12 @@ margin: 0; } -.fixer { - margin: 0.5rem 1.5rem; +.fixerContainer { display: flex; justify-content: space-between; align-items: center; } + +.fixer { + margin: 0.5rem 0 0.5rem 1.5rem; +} diff --git a/packages/website/src/components/ErrorsViewer.tsx b/packages/website/src/components/ErrorsViewer.tsx index 566f1b83fdc4..6d7621d096aa 100644 --- a/packages/website/src/components/ErrorsViewer.tsx +++ b/packages/website/src/components/ErrorsViewer.tsx @@ -1,11 +1,13 @@ -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import type Monaco from 'monaco-editor'; -import type { ErrorItem } from './types'; +import clsx from 'clsx'; +import type { ErrorItem, ErrorGroup } from './types'; +import IconExternalLink from '@theme/IconExternalLink'; import styles from './ErrorsViewer.module.css'; export interface ErrorsViewerProps { - readonly value?: ErrorItem[]; + readonly value?: ErrorGroup[]; } export interface ErrorBlockProps { @@ -14,6 +16,12 @@ export interface ErrorBlockProps { readonly isLocked: boolean; } +export interface FixButtonProps { + readonly fix: () => void; + readonly setIsLocked: (value: boolean) => void; + readonly disabled: boolean; +} + function severityClass(severity: Monaco.MarkerSeverity): string { switch (severity) { case 8: @@ -26,16 +34,19 @@ function severityClass(severity: Monaco.MarkerSeverity): string { return 'info'; } -function groupErrorItems(items: ErrorItem[]): [string, ErrorItem[]][] { - return Object.entries( - items.reduce>((acc, obj) => { - if (!acc[obj.group]) { - acc[obj.group] = []; - } - acc[obj.group].push(obj); - return acc; - }, {}), - ).sort(([a], [b]) => a.localeCompare(b)); +function FixButton(props: FixButtonProps): JSX.Element { + return ( + + ); } function ErrorBlock({ @@ -46,30 +57,35 @@ function ErrorBlock({ return (
-
-
+
+
{item.message} {item.location}
- {item.hasFixers && ( -
- {item.fixers.map((fixer, index) => ( -
- > {fixer.message} - -
- ))} -
+ {item.fixer && ( + )}
+ {item.suggestions.length > 0 && ( +
+ {item.suggestions.map((fixer, index) => ( +
+ > {fixer.message} + +
+ ))} +
+ )}
); @@ -78,11 +94,6 @@ function ErrorBlock({ export default function ErrorsViewer({ value, }: ErrorsViewerProps): JSX.Element { - const model = useMemo( - () => (value ? groupErrorItems(value) : undefined), - [value], - ); - const [isLocked, setIsLocked] = useState(false); useEffect(() => { @@ -91,11 +102,21 @@ export default function ErrorsViewer({ return (
- {model?.map(([group, data]) => { + {value?.map(({ group, uri, items }) => { return (
-

{group}

- {data.map((item, index) => ( +

+ {group} + {uri && ( + <> + {' - '} + + docs + + + )} +

+ {items.map((item, index) => ( (); const [tsAst, setTsAST] = useState(); const [scope, setScope] = useState | null>(); - const [markers, setMarkers] = useState(); + const [markers, setMarkers] = useState(); const [ruleNames, setRuleNames] = useState([]); const [isLoading, setIsLoading] = useState(true); const [tsVersions, setTSVersion] = useState([]); diff --git a/packages/website/src/components/config/ConfigEditor.module.css b/packages/website/src/components/config/ConfigEditor.module.css index 1329e5af9a74..b2f25dfcbe0f 100644 --- a/packages/website/src/components/config/ConfigEditor.module.css +++ b/packages/website/src/components/config/ConfigEditor.module.css @@ -39,6 +39,10 @@ margin: 0.2rem 0; } +.searchResultDescription { + flex: 1 0 75%; +} + .searchResult:nth-child(even), .searchResultGroup:nth-child(even) { background: var(--ifm-color-emphasis-100); diff --git a/packages/website/src/components/config/ConfigEditor.tsx b/packages/website/src/components/config/ConfigEditor.tsx index 43bfcadd9bcd..4f0f9d939955 100644 --- a/packages/website/src/components/config/ConfigEditor.tsx +++ b/packages/website/src/components/config/ConfigEditor.tsx @@ -7,11 +7,14 @@ import Text from '../inputs/Text'; import Checkbox from '../inputs/Checkbox'; import useFocus from '../hooks/useFocus'; import Modal from '@site/src/components/modals/Modal'; +import Dropdown from '@site/src/components/inputs/Dropdown'; export interface ConfigOptionsField { key: string; + type: 'boolean' | 'string'; label?: string; defaults?: unknown[]; + enum?: string[]; } export interface ConfigOptionsType { @@ -33,6 +36,11 @@ function reducerObject( state: ConfigEditorValues, action: | { type: 'init'; config?: ConfigEditorValues } + | { + type: 'set'; + name: string; + value: unknown; + } | { type: 'toggle'; checked: boolean; @@ -44,6 +52,15 @@ function reducerObject( case 'init': { return action.config ?? {}; } + case 'set': { + const newState = { ...state }; + if (action.value === '') { + delete newState[action.name]; + } else { + newState[action.name] = action.value; + } + return newState; + } case 'toggle': { const newState = { ...state }; if (action.checked) { @@ -110,28 +127,44 @@ function ConfigEditor(props: ConfigEditorProps): JSX.Element {
{group.fields.map(item => ( ))}
diff --git a/packages/website/src/components/config/ConfigEslint.tsx b/packages/website/src/components/config/ConfigEslint.tsx index 3ffc57cb35ff..f14d00ec5b78 100644 --- a/packages/website/src/components/config/ConfigEslint.tsx +++ b/packages/website/src/components/config/ConfigEslint.tsx @@ -1,14 +1,9 @@ import React, { useCallback, useEffect, useState } from 'react'; import ConfigEditor, { ConfigOptionsType } from './ConfigEditor'; -import type { - RulesRecord, - RuleDetails, - RuleEntry, - ConfigModel, -} from '../types'; +import type { RuleDetails, RuleEntry, ConfigModel, EslintRC } from '../types'; import { shallowEqual } from '../lib/shallowEqual'; -import { parseESLintRC, toJsonConfig } from '@site/src/components/config/utils'; +import { parseESLintRC, toJson } from './utils'; export interface ConfigEslintProps { readonly isOpen: boolean; @@ -33,11 +28,11 @@ function checkOptions(rule: [string, unknown]): rule is [string, RuleEntry] { function ConfigEslint(props: ConfigEslintProps): JSX.Element { const [options, updateOptions] = useState([]); - const [configObject, updateConfigObject] = useState({}); + const [configObject, updateConfigObject] = useState(); useEffect(() => { if (props.isOpen) { - updateConfigObject(props.config ? parseESLintRC(props.config) : {}); + updateConfigObject(parseESLintRC(props.config)); } }, [props.isOpen, props.config]); @@ -50,6 +45,7 @@ function ConfigEslint(props: ConfigEslintProps): JSX.Element { .map(item => ({ key: item.name, label: item.description, + type: 'boolean', defaults: ['error', 2, 'warn', 1, ['error'], ['warn'], [2], [1]], })), }, @@ -60,6 +56,7 @@ function ConfigEslint(props: ConfigEslintProps): JSX.Element { .map(item => ({ key: item.name, label: item.description, + type: 'boolean', defaults: ['error', 2, 'warn', 1, ['error'], ['warn'], [2], [1]], })), }, @@ -77,8 +74,10 @@ function ConfigEslint(props: ConfigEslintProps): JSX.Element { ) .filter(checkOptions), ); - if (!shallowEqual(cfg, configObject)) { - props.onClose({ eslintrc: toJsonConfig(cfg, 'rules') }); + if (!shallowEqual(cfg, configObject?.rules)) { + props.onClose({ + eslintrc: toJson({ ...(configObject ?? {}), rules: cfg }), + }); } else { props.onClose(); } @@ -90,7 +89,7 @@ function ConfigEslint(props: ConfigEslintProps): JSX.Element { diff --git a/packages/website/src/components/config/ConfigTypeScript.tsx b/packages/website/src/components/config/ConfigTypeScript.tsx index 78f547088b66..91a4781d14fe 100644 --- a/packages/website/src/components/config/ConfigTypeScript.tsx +++ b/packages/website/src/components/config/ConfigTypeScript.tsx @@ -1,9 +1,9 @@ import React, { useCallback, useEffect, useState } from 'react'; import ConfigEditor, { ConfigOptionsType } from './ConfigEditor'; -import type { CompilerFlags, ConfigModel } from '../types'; +import type { ConfigModel, TSConfig } from '../types'; import { shallowEqual } from '../lib/shallowEqual'; -import { getTypescriptOptions, parseTSConfig, toJsonConfig } from './utils'; +import { getTypescriptOptions, parseTSConfig, toJson } from './utils'; interface ConfigTypeScriptProps { readonly isOpen: boolean; @@ -11,17 +11,13 @@ interface ConfigTypeScriptProps { readonly config?: string; } -function checkOptions(item: [string, unknown]): item is [string, boolean] { - return typeof item[1] === 'boolean'; -} - function ConfigTypeScript(props: ConfigTypeScriptProps): JSX.Element { const [tsConfigOptions, updateOptions] = useState([]); - const [configObject, updateConfigObject] = useState({}); + const [configObject, updateConfigObject] = useState(); useEffect(() => { if (props.isOpen) { - updateConfigObject(props.config ? parseTSConfig(props.config) : {}); + updateConfigObject(parseTSConfig(props.config)); } }, [props.isOpen, props.config]); @@ -36,10 +32,20 @@ function ConfigTypeScript(props: ConfigTypeScriptProps): JSX.Element { heading: category, fields: [], }; - group[category].fields.push({ - key: item.name, - label: item.description!.message, - }); + if (item.type === 'boolean') { + group[category].fields.push({ + key: item.name, + type: 'boolean', + label: item.description!.message, + }); + } else if (item.type instanceof Map) { + group[category].fields.push({ + key: item.name, + type: 'string', + label: item.description!.message, + enum: ['', ...Array.from(item.type.keys())], + }); + } return group; }, {}, @@ -51,11 +57,11 @@ function ConfigTypeScript(props: ConfigTypeScriptProps): JSX.Element { const onClose = useCallback( (newConfig: Record) => { - const cfg = Object.fromEntries( - Object.entries(newConfig).filter(checkOptions), - ); - if (!shallowEqual(cfg, configObject)) { - props.onClose({ tsconfig: toJsonConfig(cfg, 'compilerOptions') }); + const cfg = { ...newConfig }; + if (!shallowEqual(cfg, configObject?.compilerOptions)) { + props.onClose({ + tsconfig: toJson({ ...(configObject ?? {}), compilerOptions: cfg }), + }); } else { props.onClose(); } @@ -67,7 +73,7 @@ function ConfigTypeScript(props: ConfigTypeScriptProps): JSX.Element { diff --git a/packages/website/src/components/config/utils.ts b/packages/website/src/components/config/utils.ts index 9ee188b6152e..d068f9e13ff5 100644 --- a/packages/website/src/components/config/utils.ts +++ b/packages/website/src/components/config/utils.ts @@ -1,4 +1,4 @@ -import type { CompilerFlags, RulesRecord } from '@site/src/components/types'; +import type { EslintRC, TSConfig } from '@site/src/components/types'; import { parse } from 'json5'; import { isRecord } from '@site/src/components/ast/utils'; @@ -8,56 +8,89 @@ export interface OptionDeclarations { type?: unknown; category?: { message: string }; description?: { message: string }; + element?: { + type: unknown; + }; } -export function parseESLintRC(code?: string): RulesRecord { +export function parseESLintRC(code?: string): EslintRC { if (code) { try { const parsed: unknown = parse(code); - if (isRecord(parsed) && 'rules' in parsed && isRecord(parsed.rules)) { - return parsed.rules as RulesRecord; + if (isRecord(parsed)) { + if ('rules' in parsed && isRecord(parsed.rules)) { + return parsed as EslintRC; + } + return { ...parsed, rules: {} }; } } catch (e) { // eslint-disable-next-line no-console console.error(e); } } - return {}; + return { rules: {} }; } -export function parseTSConfig(code?: string): CompilerFlags { +export function parseTSConfig(code?: string): TSConfig { if (code) { try { - const parsed: unknown = parse(code); - if ( - isRecord(parsed) && - 'compilerOptions' in parsed && - isRecord(parsed.compilerOptions) - ) { - return parsed.compilerOptions as CompilerFlags; + const parsed = window.ts.parseConfigFileTextToJson( + '/tsconfig.json', + code, + ); + if (parsed.error) { + // eslint-disable-next-line no-console + console.error(parsed.error); + } + if (isRecord(parsed.config)) { + return parsed.config as TSConfig; } } catch (e) { // eslint-disable-next-line no-console console.error(e); } } - return {}; + return { compilerOptions: {} }; +} + +const moduleRegexp = /(module\.exports\s*=)/g; + +function constrainedScopeEval(obj: string): unknown { + // eslint-disable-next-line @typescript-eslint/no-implied-eval + return new Function(` + "use strict"; + var module = { exports: {} }; + (${obj}); + return module.exports + `)(); +} + +export function tryParseEslintModule(value: string): string { + try { + if (moduleRegexp.test(value)) { + const newValue = toJson(constrainedScopeEval(value)); + if (newValue !== value) { + return newValue; + } + } + } catch (e) { + // eslint-disable-next-line no-console + console.error(e); + } + return value; +} + +export function toJson(cfg: unknown): string { + return JSON.stringify(cfg, null, 2); } export function toJsonConfig(cfg: unknown, prop: string): string { - return JSON.stringify( - { - [prop]: cfg, - }, - null, - 2, - ); + return toJson({ [prop]: cfg }); } export function getTypescriptOptions(): OptionDeclarations[] { const allowedCategories = [ 'Command-line Options', - 'Modules', 'Projects', 'Compiler Diagnostics', 'Editor Support', @@ -66,21 +99,33 @@ export function getTypescriptOptions(): OptionDeclarations[] { 'Source Map Options', ]; + const filteredNames = [ + 'moduleResolution', + 'moduleDetection', + 'plugins', + 'typeRoots', + 'jsx', + ]; + // @ts-expect-error: definition is not fully correct return (window.ts.optionDeclarations as OptionDeclarations[]).filter( item => - item.type === 'boolean' && + (item.type === 'boolean' || + item.type === 'list' || + item.type instanceof Map) && item.description && item.category && - !allowedCategories.includes(item.category.message), + !allowedCategories.includes(item.category.message) && + !filteredNames.includes(item.name), ); } -export const defaultTsConfig = toJsonConfig( - { +export const defaultTsConfig = toJson({ + compilerOptions: { strictNullChecks: true, }, - 'compilerOptions', -); +}); -export const defaultEslintConfig = toJsonConfig({}, 'rules'); +export const defaultEslintConfig = toJson({ + rules: {}, +}); diff --git a/packages/website/src/components/editor/LoadedEditor.tsx b/packages/website/src/components/editor/LoadedEditor.tsx index 0269c62e7f5f..f325fb91e6df 100644 --- a/packages/website/src/components/editor/LoadedEditor.tsx +++ b/packages/website/src/components/editor/LoadedEditor.tsx @@ -24,8 +24,7 @@ import { LintCodeAction, } from '../linter/utils'; import { - defaultEslintConfig, - defaultTsConfig, + tryParseEslintModule, parseESLintRC, parseTSConfig, } from '../config/utils'; @@ -62,14 +61,14 @@ export const LoadedEditor: React.FC = ({ const tabsDefault = { code: sandboxInstance.editor.getModel()!, tsconfig: sandboxInstance.monaco.editor.createModel( - defaultTsConfig, + tsconfig, 'json', - sandboxInstance.monaco.Uri.file('./tsconfig.json'), + sandboxInstance.monaco.Uri.file('/tsconfig.json'), ), eslintrc: sandboxInstance.monaco.editor.createModel( - defaultEslintConfig, + eslintrc, 'json', - sandboxInstance.monaco.Uri.file('./.eslintrc'), + sandboxInstance.monaco.Uri.file('/.eslintrc'), ), }; tabsDefault.code.updateOptions({ tabSize: 2, insertSpaces: true }); @@ -83,7 +82,7 @@ export const LoadedEditor: React.FC = ({ const markers = sandboxInstance.monaco.editor.getModelMarkers({ resource: model.uri, }); - onMarkersChange(parseMarkers(markers, codeActions, model)); + onMarkersChange(parseMarkers(markers, codeActions, sandboxInstance.editor)); }, []); useEffect(() => { @@ -95,20 +94,25 @@ export const LoadedEditor: React.FC = ({ sandboxInstance.monaco.Uri.file(newPath), ); newModel.updateOptions({ tabSize: 2, insertSpaces: true }); - sandboxInstance.editor.setModel(newModel); + if (tabs.code.isAttachedToEditor()) { + sandboxInstance.editor.setModel(newModel); + } tabs.code.dispose(); tabs.code = newModel; } }, [jsx]); useEffect(() => { - const config = createCompilerOptions(jsx, parseTSConfig(tsconfig)); + const config = createCompilerOptions( + jsx, + parseTSConfig(tsconfig).compilerOptions, + ); webLinter.updateCompilerOptions(config); sandboxInstance.setCompilerSettings(config); }, [jsx, tsconfig]); useEffect(() => { - webLinter.updateRules(parseESLintRC(eslintrc)); + webLinter.updateRules(parseESLintRC(eslintrc).rules); }, [eslintrc]); useEffect(() => { @@ -125,7 +129,9 @@ export const LoadedEditor: React.FC = ({ const messages = webLinter.lint(code); - const markers = parseLintResults(messages, codeActions); + const markers = parseLintResults(messages, codeActions, ruleId => + sandboxInstance.monaco.Uri.parse(webLinter.rulesUrl.get(ruleId) ?? ''), + ); sandboxInstance.monaco.editor.setModelMarkers( tabs.code, @@ -169,9 +175,18 @@ export const LoadedEditor: React.FC = ({ 'typescript', createProvideCodeActions(codeActions), ), + sandboxInstance.editor.onDidPaste(() => { + if (tabs.eslintrc.isAttachedToEditor()) { + const value = tabs.eslintrc.getValue(); + const newValue = tryParseEslintModule(value); + if (newValue !== value) { + tabs.eslintrc.setValue(newValue); + } + } + }), sandboxInstance.editor.onDidChangeCursorPosition( debounce(() => { - if (sandboxInstance.editor.getModel() === tabs.code) { + if (tabs.code.isAttachedToEditor()) { const position = sandboxInstance.editor.getPosition(); if (position) { // eslint-disable-next-line no-console diff --git a/packages/website/src/components/editor/config.ts b/packages/website/src/components/editor/config.ts index 679baa8a0f22..e2c5b7fe6bb0 100644 --- a/packages/website/src/components/editor/config.ts +++ b/packages/website/src/components/editor/config.ts @@ -6,14 +6,31 @@ export function createCompilerOptions( jsx = false, tsConfig: Record = {}, ): Monaco.languages.typescript.CompilerOptions { - return { - noResolve: true, - // ts and monaco has different type as monaco types are not changing base on ts version - target: window.ts.ScriptTarget.ESNext as number, - module: window.ts.ModuleKind.ESNext as number, - ...tsConfig, - jsx: jsx ? window.ts.JsxEmit.Preserve : window.ts.JsxEmit.None, - }; + const config = window.ts.convertCompilerOptionsFromJson( + { + // ts and monaco has different type as monaco types are not changing base on ts version + target: 'esnext', + module: 'esnext', + ...tsConfig, + jsx: jsx ? 'preserve' : undefined, + lib: Array.isArray(tsConfig.lib) ? tsConfig.lib : undefined, + moduleResolution: undefined, + plugins: undefined, + typeRoots: undefined, + paths: undefined, + moduleDetection: undefined, + baseUrl: undefined, + }, + '/tsconfig.json', + ); + + const options = config.options as Monaco.languages.typescript.CompilerOptions; + + if (!options.lib) { + options.lib = [window.ts.getDefaultLibFileName(options)]; + } + + return options; } export function getEslintSchema( @@ -58,10 +75,27 @@ export function getEslintSchema( export function getTsConfigSchema(): JSONSchema4 { const properties = getTypescriptOptions().reduce((options, item) => { - options[item.name] = { - type: item.type, - description: item.description!.message, - }; + if (item.type === 'boolean') { + options[item.name] = { + type: 'boolean', + description: item.description!.message, + }; + } else if (item.type === 'list' && item.element?.type instanceof Map) { + options[item.name] = { + type: 'array', + items: { + type: 'string', + enum: Array.from(item.element.type.keys()), + }, + description: item.description!.message, + }; + } else if (item.type instanceof Map) { + options[item.name] = { + type: 'string', + description: item.description!.message, + enum: Array.from(item.type.keys()), + }; + } return options; }, {}); diff --git a/packages/website/src/components/editor/createProvideCodeActions.ts b/packages/website/src/components/editor/createProvideCodeActions.ts index 2239a00459b6..26045a467939 100644 --- a/packages/website/src/components/editor/createProvideCodeActions.ts +++ b/packages/website/src/components/editor/createProvideCodeActions.ts @@ -28,9 +28,10 @@ export function createProvideCodeActions( const messages = fixes.get(createURI(marker)) ?? []; for (const message of messages) { actions.push({ - title: message.message, + title: message.message + (message.code ? ` (${message.code})` : ''), diagnostics: [marker], kind: 'quickfix', + isPreferred: message.isPreferred, edit: { edits: [ { diff --git a/packages/website/src/components/editor/types.ts b/packages/website/src/components/editor/types.ts index 578ef28d00b4..7b904b4bf5f8 100644 --- a/packages/website/src/components/editor/types.ts +++ b/packages/website/src/components/editor/types.ts @@ -1,5 +1,5 @@ import type Monaco from 'monaco-editor'; -import type { ConfigModel, SelectedRange, ErrorItem, TabType } from '../types'; +import type { ConfigModel, SelectedRange, ErrorGroup, TabType } from '../types'; import type { TSESTree } from '@typescript-eslint/utils'; import type { SourceFile } from 'typescript'; @@ -11,6 +11,6 @@ export interface CommonEditorProps extends ConfigModel { readonly onTsASTChange: (value: undefined | SourceFile) => void; readonly onEsASTChange: (value: undefined | TSESTree.Program) => void; readonly onScopeChange: (value: undefined | Record) => void; - readonly onMarkersChange: (value: ErrorItem[]) => void; + readonly onMarkersChange: (value: ErrorGroup[]) => void; readonly onSelect: (position: Monaco.Position | null) => void; } diff --git a/packages/website/src/components/editor/useSandboxServices.ts b/packages/website/src/components/editor/useSandboxServices.ts index 1276fc38f87d..eb54143bad46 100644 --- a/packages/website/src/components/editor/useSandboxServices.ts +++ b/packages/website/src/components/editor/useSandboxServices.ts @@ -64,6 +64,7 @@ export const useSandboxServices = ( formatOnType: true, wrappingIndent: 'same', }, + acquireTypes: false, compilerOptions: compilerOptions, domID: editorEmbedId, }; @@ -77,19 +78,34 @@ export const useSandboxServices = ( colorMode === 'dark' ? 'vs-dark' : 'vs-light', ); - // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access - const libs = ((window.ts as any).libs as string[]) ?? ['esnext']; - - const libMap = await sandboxInstance.tsvfs.createDefaultMapFromCDN( - { - ...sandboxInstance.getCompilerOptions(), - lib: libs.filter(item => !item.includes('.')), - }, - props.ts, - true, - window.ts, - ); - const system = sandboxInstance.tsvfs.createSystem(libMap); + let libEntries: Map | undefined; + const worker = await sandboxInstance.getWorkerProcess(); + if (worker.getLibFiles) { + libEntries = new Map( + Object.entries((await worker.getLibFiles()) ?? {}).map(item => [ + '/' + item[0], + item[1], + ]), + ); + } else { + // for some older version of playground we do not have definitions available + libEntries = await sandboxInstance.tsvfs.createDefaultMapFromCDN( + { + lib: Array.from(window.ts.libMap.keys()), + }, + props.ts, + true, + window.ts, + ); + for (const pair of libEntries) { + sandboxInstance.languageServiceDefaults.addExtraLib( + pair[1], + 'ts:' + pair[0], + ); + } + } + + const system = sandboxInstance.tsvfs.createSystem(libEntries); const webLinter = new WebLinter(system, compilerOptions, lintUtils); diff --git a/packages/website/src/components/linter/WebLinter.ts b/packages/website/src/components/linter/WebLinter.ts index de29ed72502c..eaece6e236f0 100644 --- a/packages/website/src/components/linter/WebLinter.ts +++ b/packages/website/src/components/linter/WebLinter.ts @@ -35,7 +35,8 @@ export class WebLinter { private lintUtils: LintUtils; private rules: TSESLint.Linter.RulesRecord = {}; - public ruleNames: { name: string; description?: string }[]; + public readonly ruleNames: { name: string; description?: string }[] = []; + public readonly rulesUrl = new Map(); constructor( system: System, @@ -54,11 +55,12 @@ export class WebLinter { }, }); - this.ruleNames = Array.from(this.linter.getRules()).map(value => { - return { - name: value[0], - description: value[1]?.meta?.docs?.description, - }; + this.linter.getRules().forEach((item, name) => { + this.ruleNames.push({ + name: name, + description: item.meta?.docs?.description, + }); + this.rulesUrl.set(name, item.meta?.docs?.url); }); } diff --git a/packages/website/src/components/linter/utils.ts b/packages/website/src/components/linter/utils.ts index 7c7056a62821..8f8d0f23fbdd 100644 --- a/packages/website/src/components/linter/utils.ts +++ b/packages/website/src/components/linter/utils.ts @@ -1,9 +1,11 @@ import type Monaco from 'monaco-editor'; -import type { ErrorItem } from '../types'; +import type { ErrorGroup } from '../types'; import type { TSESLint } from '@typescript-eslint/utils'; export interface LintCodeAction { message: string; + code?: string | null; + isPreferred: boolean; fix: { range: Readonly<[number, number]>; text: string; @@ -45,46 +47,76 @@ export function createEditOperation( }; } +function normalizeCode(code: Monaco.editor.IMarker['code']): { + value: string; + target?: string; +} { + if (!code) { + return { value: '' }; + } + if (typeof code === 'string') { + return { value: code }; + } + return { + value: code.value, + target: code.target.toString(), + }; +} + export function parseMarkers( markers: Monaco.editor.IMarker[], fixes: Map, - model: Monaco.editor.ITextModel, -): ErrorItem[] { - return markers.map(marker => { - const code = - typeof marker.code === 'string' ? marker.code : marker.code?.value ?? ''; + editor: Monaco.editor.IStandaloneCodeEditor, +): ErrorGroup[] { + const result: Record = {}; + for (const marker of markers) { + const code = normalizeCode(marker.code); const uri = createURI(marker); const fixers = - fixes.get(uri)?.map(item => { - return { - message: item.message, - fix(): void { - model.applyEdits([createEditOperation(model, item)]); - }, - }; - }) ?? []; - - return { - group: - marker.owner === 'eslint' - ? code - : marker.owner === 'typescript' - ? 'TypeScript' - : marker.owner, + fixes.get(uri)?.map(item => ({ + message: item.message, + isPreferred: item.isPreferred, + fix(): void { + editor.executeEdits('eslint', [ + createEditOperation(editor.getModel()!, item), + ]); + }, + })) ?? []; + + const group = + marker.owner === 'eslint' + ? code.value + : marker.owner === 'typescript' + ? 'TypeScript' + : marker.owner; + + if (!result[group]) { + result[group] = { + group: group, + uri: code.target, + items: [], + }; + } + + result[group].items.push({ message: - (marker.owner !== 'eslint' && code ? `${code}: ` : '') + marker.message, + (marker.owner !== 'eslint' && code ? `${code.value}: ` : '') + + marker.message, location: `${marker.startLineNumber}:${marker.startColumn} - ${marker.endLineNumber}:${marker.endColumn}`, severity: marker.severity, - hasFixers: fixers.length > 0, - fixers: fixers, - }; - }); + fixer: fixers.find(item => item.isPreferred), + suggestions: fixers.filter(item => !item.isPreferred), + }); + } + + return Object.values(result).sort((a, b) => a.group.localeCompare(b.group)); } export function parseLintResults( messages: TSESLint.Linter.LintMessage[], codeActions: Map, + ruleUri: (ruleId: string) => Monaco.Uri, ): Monaco.editor.IMarkerData[] { const markers: Monaco.editor.IMarkerData[] = []; @@ -97,7 +129,12 @@ export function parseLintResults( const endColumn = ensurePositiveInt(message.endColumn, startColumn + 1); const marker: Monaco.editor.IMarkerData = { - code: message.ruleId ?? 'FATAL', + code: message.ruleId + ? { + value: message.ruleId, + target: ruleUri(message.ruleId), + } + : 'FATAL', severity: message.severity === 2 ? 8 // MarkerSeverity.Error @@ -116,13 +153,16 @@ export function parseLintResults( fixes.push({ message: `Fix this ${message.ruleId ?? 'unknown'} problem`, fix: message.fix, + isPreferred: true, }); } if (message.suggestions) { for (const suggestion of message.suggestions) { fixes.push({ - message: `${suggestion.desc} (${message.ruleId ?? 'unknown'})`, + message: suggestion.desc, + code: message.ruleId, fix: suggestion.fix, + isPreferred: false, }); } } diff --git a/packages/website/src/components/types.ts b/packages/website/src/components/types.ts index c517353a66bf..b63d9bca307b 100644 --- a/packages/website/src/components/types.ts +++ b/packages/website/src/components/types.ts @@ -35,10 +35,20 @@ export interface SelectedRange { } export interface ErrorItem { - group: string; message: string; location: string; severity: number; - hasFixers: boolean; - fixers: { message: string; fix(): void }[]; + suggestions: { message: string; fix(): void }[]; + fixer?: { message: string; fix(): void }; } + +export interface ErrorGroup { + group: string; + uri?: string; + items: ErrorItem[]; +} + +export type EslintRC = Record & { rules: RulesRecord }; +export type TSConfig = Record & { + compilerOptions: CompilerFlags; +}; diff --git a/packages/website/src/css/custom.css b/packages/website/src/css/custom.css index 2324486fc7e5..dcda800b7ab7 100644 --- a/packages/website/src/css/custom.css +++ b/packages/website/src/css/custom.css @@ -109,7 +109,39 @@ h6 { background-color: var(--code-line-decoration); } -/* indent the nested checklist for the rule doc attributes */ -ul.contains-task-list > li > ul.contains-task-list { - padding-left: 24px; +.code-block-removed-line::before { + content: '-'; + display: inline-block; + width: 0px; + position: relative; + left: -0.7em; + color: red; +} + +.code-block-removed-line { + background-color: #ff000020; + display: block; + margin: 0 calc(-1 * var(--ifm-pre-padding)); + padding: 0 var(--ifm-pre-padding); + user-select: none; +} + +.code-block-added-line::before { + content: '+'; + display: inline-block; + width: 0px; + position: relative; + left: -0.7em; + color: rgb(2, 164, 113); +} + +.code-block-added-line { + background-color: #00ff9540; + display: block; + margin: 0 calc(-1 * var(--ifm-pre-padding)); + padding: 0 var(--ifm-pre-padding); +} + +[data-theme='dark'] .code-block-added-line { + background-color: #00ff9510; } diff --git a/packages/website/src/theme/CodeBlock/Content/String.tsx b/packages/website/src/theme/CodeBlock/Content/String.tsx new file mode 100644 index 000000000000..f26a6ec5b9c5 --- /dev/null +++ b/packages/website/src/theme/CodeBlock/Content/String.tsx @@ -0,0 +1,121 @@ +// Change: added `copiedCode` which filters out the removed lines + +import React from 'react'; +import clsx from 'clsx'; +import { + useThemeConfig, + parseCodeBlockTitle, + parseLanguage, + parseLines, + containsLineNumbers, + usePrismTheme, + useCodeWordWrap, +} from '@docusaurus/theme-common'; +import Highlight, { defaultProps, type Language } from 'prism-react-renderer'; +import Line from '@theme/CodeBlock/Line'; +import CopyButton from '@theme/CodeBlock/CopyButton'; +import WordWrapButton from '@theme/CodeBlock/WordWrapButton'; +import Container from '@theme/CodeBlock/Container'; +import type { Props } from '@theme/CodeBlock/Content/String'; + +import styles from './styles.module.css'; + +// eslint-disable-next-line import/no-default-export +export default function CodeBlockString({ + children, + className: blockClassName = '', + metastring, + title: titleProp, + showLineNumbers: showLineNumbersProp, + language: languageProp, +}: Props): JSX.Element { + const { + prism: { defaultLanguage, magicComments }, + } = useThemeConfig(); + const language = + languageProp ?? parseLanguage(blockClassName) ?? defaultLanguage; + const prismTheme = usePrismTheme(); + const wordWrap = useCodeWordWrap(); + + // We still parse the metastring in case we want to support more syntax in the + // future. Note that MDX doesn't strip quotes when parsing metastring: + // "title=\"xyz\"" => title: "\"xyz\"" + const title = parseCodeBlockTitle(metastring) || titleProp; + + const { lineClassNames, code } = parseLines(children, { + metastring, + language, + magicComments, + }); + const showLineNumbers = + showLineNumbersProp ?? containsLineNumbers(metastring); + + const copiedCode = code + .split('\n') + .filter((c, i) => !lineClassNames[i]?.includes('code-block-removed-line')) + .join('\n'); + + return ( + + {title &&
{title}
} +
+ + {({ + className, + tokens, + getLineProps, + getTokenProps, + }): JSX.Element => ( +
+              
+                {tokens.map((line, i) => (
+                  
+                ))}
+              
+            
+ )} +
+
+ {(wordWrap.isEnabled || wordWrap.isCodeScrollable) && ( + wordWrap.toggle()} + isEnabled={wordWrap.isEnabled} + /> + )} + +
+
+
+ ); +} diff --git a/packages/website/src/theme/CodeBlock/Content/styles.module.css b/packages/website/src/theme/CodeBlock/Content/styles.module.css new file mode 100644 index 000000000000..e75d80399a67 --- /dev/null +++ b/packages/website/src/theme/CodeBlock/Content/styles.module.css @@ -0,0 +1,81 @@ +/* No change; copied over so that the .tsx file can get its CSS */ + +.codeBlockContent { + position: relative; + /* rtl:ignore */ + direction: ltr; + border-radius: inherit; +} + +.codeBlockTitle { + border-bottom: 1px solid var(--ifm-color-emphasis-300); + font-size: var(--ifm-code-font-size); + font-weight: 500; + padding: 0.75rem var(--ifm-pre-padding); + border-top-left-radius: inherit; + border-top-right-radius: inherit; +} + +.codeBlock { + --ifm-pre-background: var(--prism-background-color); + margin: 0; + padding: 0; +} + +.codeBlockTitle + .codeBlockContent .codeBlock { + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.codeBlockStandalone { + padding: 0; +} + +.codeBlockLines { + font: inherit; + /* rtl:ignore */ + float: left; + min-width: 100%; + padding: var(--ifm-pre-padding); +} + +.codeBlockLinesWithNumbering { + display: table; + padding: var(--ifm-pre-padding) 0; +} + +@media print { + .codeBlockLines { + white-space: pre-wrap; + } +} + +.buttonGroup { + display: flex; + column-gap: 0.2rem; + position: absolute; + right: calc(var(--ifm-pre-padding) / 2); + top: calc(var(--ifm-pre-padding) / 2); +} + +.buttonGroup button { + display: flex; + align-items: center; + background: var(--prism-background-color); + color: var(--prism-color); + border: 1px solid var(--ifm-color-emphasis-300); + border-radius: var(--ifm-global-radius); + padding: 0.4rem; + line-height: 0; + transition: opacity 200ms ease-in-out; + opacity: 0; +} + +.buttonGroup button:focus-visible, +.buttonGroup button:hover { + opacity: 1 !important; +} + +:global(.theme-code-block:hover) .buttonGroup button { + opacity: 0.4; +} diff --git a/packages/website/src/vendor/sandbox.d.ts b/packages/website/src/vendor/sandbox.d.ts index 4b3ba86d8aae..0bd3ecc2d259 100644 --- a/packages/website/src/vendor/sandbox.d.ts +++ b/packages/website/src/vendor/sandbox.d.ts @@ -105,7 +105,8 @@ export declare const createTypeScriptSandbox: ( }; /** A list of TypeScript versions you can use with the TypeScript sandbox */ supportedVersions: readonly [ - '4.6.2', + '4.7.3', + '4.6.4', '4.5.5', '4.4.4', '4.3.5', diff --git a/packages/website/src/vendor/tsWorker.d.ts b/packages/website/src/vendor/tsWorker.d.ts index eaa5dd5cabb1..801ea3e43b44 100644 --- a/packages/website/src/vendor/tsWorker.d.ts +++ b/packages/website/src/vendor/tsWorker.d.ts @@ -89,6 +89,10 @@ export declare class TypeScriptWorker implements ts.LanguageServiceHost { formatOptions: ts.FormatCodeOptions, ): Promise>; updateExtraLibs(extraLibs: IExtraLibs): void; + /** + * https://github.com/microsoft/TypeScript-Website/blob/246798df5013036bd9b4389932b642c20ab35deb/packages/playground-worker/types.d.ts#L48 + */ + getLibFiles(): Promise>; } export interface IExtraLib { content: string; diff --git a/packages/website/typings/remark-docusaurus-tabs.d.ts b/packages/website/typings/remark-docusaurus-tabs.d.ts index 9dab9651dd63..a2fb12147cba 100644 --- a/packages/website/typings/remark-docusaurus-tabs.d.ts +++ b/packages/website/typings/remark-docusaurus-tabs.d.ts @@ -1,5 +1,6 @@ declare module 'remark-docusaurus-tabs' { import type { Plugin } from 'unified'; + const plugin: Plugin; export = plugin; } diff --git a/packages/website/typings/typescript.d.ts b/packages/website/typings/typescript.d.ts new file mode 100644 index 000000000000..7239e4ddcb5f --- /dev/null +++ b/packages/website/typings/typescript.d.ts @@ -0,0 +1,13 @@ +import 'typescript'; + +type StringMap = Map; + +declare module 'typescript' { + /** + * Map of available libraries + * + * The key is the key used in compilerOptions.lib + * The value is the file name + */ + const libMap: StringMap; +} diff --git a/yarn.lock b/yarn.lock index c0cbb5684a92..0e62419c3f83 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3964,10 +3964,10 @@ dependencies: "@types/jest" "*" -"@types/jest@*", "@types/jest@^27.5.0": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.5.1.tgz#2c8b6dc6ff85c33bcd07d0b62cb3d19ddfdb3ab9" - integrity sha512-fUy7YRpT+rHXto1YlL+J9rs0uLGyiqVt3ZOTQR+4ROc47yNl8WLdVLgUloBRhOxP1PZvguHl44T3H0wAWxahYQ== +"@types/jest@*", "@types/jest@^28.1.1": + version "28.1.1" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-28.1.1.tgz#8c9ba63702a11f8c386ee211280e8b68cb093cd1" + integrity sha512-C2p7yqleUKtCkVjlOur9BWVA4HgUQmEj/HWCt5WzZ5mLXrWnyIfl0wGuArc+kBXsy0ZZfLp+7dywB4HtSVYGVA== dependencies: jest-matcher-utils "^27.0.0" pretty-format "^27.0.0" @@ -4100,9 +4100,9 @@ "@types/react" "*" "@types/react@*", "@types/react@^18.0.9": - version "18.0.9" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.9.tgz#d6712a38bd6cd83469603e7359511126f122e878" - integrity sha512-9bjbg1hJHUm4De19L1cHiW0Jvx3geel6Qczhjd0qY5VKVE2X5+x77YxAepuCwVh4vrgZJdgEJw48zrhRIeF4Nw== + version "18.0.12" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.12.tgz#cdaa209d0a542b3fcf69cf31a03976ec4cdd8840" + integrity sha512-duF1OTASSBQtcigUvhuiTB1Ya3OvSy+xORCiEf20H0P0lzx+/KeVsA99U5UjLXSbyo1DRJDlLKqTeM1ngosqtg== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -6958,9 +6958,9 @@ eslint-plugin-import@^2.26.0: tsconfig-paths "^3.14.1" eslint-plugin-jest@^26.1.5: - version "26.4.5" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-26.4.5.tgz#c1772800bfc15c6f34d3e1536932ece0627c9f2a" - integrity sha512-jGPKXoV7v21gvt2QivCPuN1c2RePxJ9XnYQjucioAZhMTXrJ0y48QhP7UOpgNs/sj0Lns2NKRvoAjnyXDCfqbw== + version "26.5.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-26.5.3.tgz#a3ceeaf4a757878342b8b00eca92379b246e5505" + integrity sha512-sICclUqJQnR1bFRZGLN2jnSVsYOsmPYYnroGCIMVSvTS3y8XR3yjzy1EcTQmk6typ5pRgyIWzbjqxK6cZHEZuQ== dependencies: "@typescript-eslint/utils" "^5.10.0" @@ -7187,7 +7187,7 @@ execa@4.1.0: signal-exit "^3.0.2" strip-final-newline "^2.0.0" -execa@^5.0.0, execa@^5.1.1: +execa@^5.0.0: version "5.1.1" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== @@ -7202,6 +7202,21 @@ execa@^5.0.0, execa@^5.1.1: signal-exit "^3.0.3" strip-final-newline "^2.0.0" +execa@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-6.1.0.tgz#cea16dee211ff011246556388effa0818394fb20" + integrity sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.1" + human-signals "^3.0.1" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^3.0.7" + strip-final-newline "^3.0.0" + executable@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c" @@ -7771,7 +7786,7 @@ get-stream@^5.0.0, get-stream@^5.1.0: dependencies: pump "^3.0.0" -get-stream@^6.0.0: +get-stream@^6.0.0, get-stream@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== @@ -8412,6 +8427,11 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== +human-signals@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-3.0.1.tgz#c740920859dafa50e5a3222da9d3bf4bb0e5eef5" + integrity sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ== + humanize-ms@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" @@ -8903,6 +8923,11 @@ is-stream@^2.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== +is-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" + integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + is-string@^1.0.5, is-string@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" @@ -9718,16 +9743,16 @@ linkify-it@^3.0.1: dependencies: uc.micro "^1.0.1" -lint-staged@^12.4.1: - version "12.4.3" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-12.4.3.tgz#914fa468458364e14cc952145db552d87c8847b6" - integrity sha512-eH6SKOmdm/ZwCRMTZAmM3q3dPkpq6vco/BfrOw8iGun4Xs/thYegPD/MLIwKO+iPkzibkLJuQcRhRLXKvaKreg== +lint-staged@^13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-13.0.0.tgz#ce3526a844e6328814a3261fbfedc610a18856fa" + integrity sha512-vWban5utFt78VZohbosUxNIa46KKJ+KOQTDWTQ8oSl1DLEEVl9zhUtaQbiiydAmx+h2wKJK2d0+iMaRmknuWRQ== dependencies: cli-truncate "^3.1.0" colorette "^2.0.16" commander "^9.3.0" debug "^4.3.4" - execa "^5.1.1" + execa "^6.1.0" lilconfig "2.0.5" listr2 "^4.0.5" micromatch "^4.0.5" @@ -9735,8 +9760,7 @@ lint-staged@^12.4.1: object-inspect "^1.12.2" pidtree "^0.5.0" string-argv "^0.3.1" - supports-color "^9.2.2" - yaml "^1.10.2" + yaml "^2.1.1" listr2@^3.8.3: version "3.13.5" @@ -10323,6 +10347,11 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +mimic-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" + integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + mimic-response@^1.0.0, mimic-response@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" @@ -10801,6 +10830,13 @@ npm-run-path@^4.0.0, npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" +npm-run-path@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.1.0.tgz#bc62f7f3f6952d9894bd08944ba011a6ee7b7e00" + integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q== + dependencies: + path-key "^4.0.0" + npm-to-yarn@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/npm-to-yarn/-/npm-to-yarn-1.0.1.tgz#6cdb95114c4ff0be50a7a2381d4d16131a5f52df" @@ -10980,6 +11016,13 @@ onetime@^5.1.0, onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" +onetime@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" + integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== + dependencies: + mimic-fn "^4.0.0" + open@^8.0.9, open@^8.4.0: version "8.4.0" resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8" @@ -11323,6 +11366,11 @@ path-key@^3.0.0, path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + path-parse@^1.0.6, path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" @@ -12620,9 +12668,9 @@ rollup-plugin-terser@^7.0.2: terser "^5.0.0" rollup@^2.75.4: - version "2.75.4" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.75.4.tgz#c3518c326c98e508b628a93015a03a276c331f22" - integrity sha512-JgZiJMJkKImMZJ8ZY1zU80Z2bA/TvrL/7D9qcBCrfl2bP+HUaIw0QHUroB4E3gBpFl6CRFM1YxGbuYGtdAswbQ== + version "2.75.5" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.75.5.tgz#7985c1962483235dd07966f09fdad5c5f89f16d0" + integrity sha512-JzNlJZDison3o2mOxVmb44Oz7t74EfSd1SQrplQk0wSaXV7uLQXtVdHbxlcT3w+8tZ1TL4r/eLfc7nAbz38BBA== optionalDependencies: fsevents "~2.3.2" @@ -13384,6 +13432,11 @@ strip-final-newline@^2.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== +strip-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" + integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== + strip-indent@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" @@ -13446,11 +13499,6 @@ supports-color@^8.0.0, supports-color@^8.1.1: dependencies: has-flag "^4.0.0" -supports-color@^9.2.2: - version "9.2.2" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-9.2.2.tgz#502acaf82f2b7ee78eb7c83dcac0f89694e5a7bb" - integrity sha512-XC6g/Kgux+rJXmwokjm9ECpD6k/smUoS5LKlUCcsYr4IY3rW0XyAympon2RmxGrlnZURMpg5T18gWDP9CsHXFA== - supports-hyperlinks@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" @@ -14405,9 +14453,9 @@ webpack-sources@^3.2.3: integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== webpack@^5.72.1: - version "5.72.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.72.1.tgz#3500fc834b4e9ba573b9f430b2c0a61e1bb57d13" - integrity sha512-dXG5zXCLspQR4krZVR6QgajnZOjW2K/djHvdcRaDQvsjV9z9vaW6+ja5dZOYbqBBjF6kGXka/2ZyxNdc+8Jung== + version "5.73.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.73.0.tgz#bbd17738f8a53ee5760ea2f59dce7f3431d35d38" + integrity sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA== dependencies: "@types/eslint-scope" "^3.7.3" "@types/estree" "^0.0.51" @@ -14670,6 +14718,11 @@ yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== +yaml@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.1.1.tgz#1e06fb4ca46e60d9da07e4f786ea370ed3c3cfec" + integrity sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw== + yargs-parser@20.2.4: version "20.2.4" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"