From 8f4d9391b76786790e13cb9ca3b6a0da04014636 Mon Sep 17 00:00:00 2001 From: cigui Date: Mon, 9 Oct 2023 05:11:43 +0800 Subject: [PATCH 01/16] docs: fix prefer-optional-chain example for the unsafe fixes option (#7711) docs: fix the example for the option allowPotentiallyUnsafeFixesThatModifyTheReturnTypeIKnowWhatImDoing in prefer-optional-chain --- packages/eslint-plugin/docs/rules/prefer-optional-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/docs/rules/prefer-optional-chain.md b/packages/eslint-plugin/docs/rules/prefer-optional-chain.md index 6efb88b17ae5..416828194871 100644 --- a/packages/eslint-plugin/docs/rules/prefer-optional-chain.md +++ b/packages/eslint-plugin/docs/rules/prefer-optional-chain.md @@ -76,7 +76,7 @@ declare function acceptsBoolean(arg: boolean): void; acceptsBoolean(foo != null && foo.bar); // ❌ typechecks UNSUCCESSFULLY as the expression returns `boolean | undefined` -acceptsBoolean(foo != null && foo.bar); +acceptsBoolean(foo?.bar); ``` This style of code isn't super common - which means having this option set to `true` _should_ be safe in most codebases. However we default it to `false` due to its unsafe nature. We have provided this option for convenience because it increases the autofix cases covered by the rule. If you set option to `true` the onus is entirely on you and your team to ensure that each fix is correct and safe and that it does not break the build. From db40a0a83abf14237a7a9b3f75d869da26512292 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Sun, 8 Oct 2023 17:23:05 -0400 Subject: [PATCH 02/16] fix(eslint-plugin): [prefer-string-starts-ends-with] only report slice/substring with correct range (#7712) --- .../rules/prefer-string-starts-ends-with.ts | 67 +++++++++++++------ .../prefer-string-starts-ends-with.test.ts | 33 +++++---- 2 files changed, 62 insertions(+), 38 deletions(-) diff --git a/packages/eslint-plugin/src/rules/prefer-string-starts-ends-with.ts b/packages/eslint-plugin/src/rules/prefer-string-starts-ends-with.ts index 926c49e82a5b..82451e181320 100644 --- a/packages/eslint-plugin/src/rules/prefer-string-starts-ends-with.ts +++ b/packages/eslint-plugin/src/rules/prefer-string-starts-ends-with.ts @@ -161,23 +161,22 @@ export default createRule({ } /** - * Check if a given node is a negative index expression - * - * E.g. `s.slice(- )`, `s.substring(s.length - )` - * - * @param node The node to check. - * @param expectedIndexedNode The node which is expected as the receiver of index expression. + * Returns true if `node` is `-substring.length` or + * `parentString.length - substring.length` */ - function isNegativeIndexExpression( + function isLengthAheadOfEnd( node: TSESTree.Node, - expectedIndexedNode: TSESTree.Node, + substring: TSESTree.Node, + parentString: TSESTree.Node, ): boolean { return ( (node.type === AST_NODE_TYPES.UnaryExpression && - node.operator === '-') || + node.operator === '-' && + isLengthExpression(node.argument, substring)) || (node.type === AST_NODE_TYPES.BinaryExpression && node.operator === '-' && - isLengthExpression(node.left, expectedIndexedNode)) + isLengthExpression(node.left, parentString) && + isLengthExpression(node.right, substring)) ); } @@ -567,16 +566,44 @@ export default createRule({ return; } - const isEndsWith = - (callNode.arguments.length === 1 || - (callNode.arguments.length === 2 && - isLengthExpression(callNode.arguments[1], node.object))) && - isNegativeIndexExpression(callNode.arguments[0], node.object); - const isStartsWith = - !isEndsWith && - callNode.arguments.length === 2 && - isNumber(callNode.arguments[0], 0) && - !isNegativeIndexExpression(callNode.arguments[1], node.object); + let isEndsWith = false; + let isStartsWith = false; + if (callNode.arguments.length === 1) { + if ( + // foo.slice(-bar.length) === bar + // foo.slice(foo.length - bar.length) === bar + isLengthAheadOfEnd( + callNode.arguments[0], + parentNode.right, + node.object, + ) + ) { + isEndsWith = true; + } + } else if (callNode.arguments.length === 2) { + if ( + // foo.slice(0, bar.length) === bar + isNumber(callNode.arguments[0], 0) && + isLengthExpression(callNode.arguments[1], parentNode.right) + ) { + isStartsWith = true; + } else if ( + // foo.slice(foo.length - bar.length, foo.length) === bar + // foo.slice(foo.length - bar.length, 0) === bar + // foo.slice(-bar.length, foo.length) === bar + // foo.slice(-bar.length, 0) === bar + (isLengthExpression(callNode.arguments[1], node.object) || + isNumber(callNode.arguments[1], 0)) && + isLengthAheadOfEnd( + callNode.arguments[0], + parentNode.right, + node.object, + ) + ) { + isEndsWith = true; + } + } + if (!isStartsWith && !isEndsWith) { return; } diff --git a/packages/eslint-plugin/tests/rules/prefer-string-starts-ends-with.test.ts b/packages/eslint-plugin/tests/rules/prefer-string-starts-ends-with.test.ts index aaea8e8b36c7..e51cbe3a8d87 100644 --- a/packages/eslint-plugin/tests/rules/prefer-string-starts-ends-with.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-string-starts-ends-with.test.ts @@ -242,6 +242,21 @@ ruleTester.run('prefer-string-starts-ends-with', rule, { x.endsWith('foo') && x.slice(0, -4) === 'bar' } `, + ` + function f(s: string) { + s.slice(0, length) === needle // the 'length' can be different to 'needle.length' + } + `, + ` + function f(s: string) { + s.slice(-length) === needle // 'length' can be different + } + `, + ` + function f(s: string) { + s.slice(0, 3) === needle + } + `, ]), invalid: addOptional([ // String indexing. @@ -817,15 +832,6 @@ ruleTester.run('prefer-string-starts-ends-with', rule, { `, errors: [{ messageId: 'preferStartsWith' }], }, - { - code: ` - function f(s: string) { - s.slice(0, length) === needle // the 'length' can be different to 'needle.length' - } - `, - output: null, - errors: [{ messageId: 'preferStartsWith' }], - }, { code: ` function f(s: string) { @@ -887,15 +893,6 @@ ruleTester.run('prefer-string-starts-ends-with', rule, { `, errors: [{ messageId: 'preferEndsWith' }], }, - { - code: ` - function f(s: string) { - s.slice(-length) === needle // 'length' can be different - } - `, - output: null, - errors: [{ messageId: 'preferEndsWith' }], - }, { code: ` function f(s: string) { From d0729024869aebe5bd6fb1971e17a15ce645fdfe Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Sun, 8 Oct 2023 17:26:40 -0400 Subject: [PATCH 03/16] docs(website): mention how rule options should be handled (#7713) --- docs/developers/Custom_Rules.mdx | 52 ++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/docs/developers/Custom_Rules.mdx b/docs/developers/Custom_Rules.mdx index e64156d1ff4e..b2ca6d64c807 100644 --- a/docs/developers/Custom_Rules.mdx +++ b/docs/developers/Custom_Rules.mdx @@ -121,6 +121,58 @@ export const rule = ESLintUtils.RuleCreator.withoutDocs({ We recommend any custom ESLint rule include a descriptive error message and link to informative documentation. ::: +## Handling rule options + +ESLint rules can take options. When handling options, you will need to add information in at most three places: + +- The `Options` generic type argument to `RuleCreator`, where you declare the type of the options +- The `meta.schema` property, where you add a JSON schema describing the options shape +- The `defaultOptions` property, where you add the default options value + +```ts +type MessageIds = 'lowercase' | 'uppercase'; + +type Options = [ + { + preferredCase: 'lower' | 'upper'; + }, +]; + +export const rule = createRule({ + meta: { + // ... + schema: [ + { + type: 'object', + properties: { + preferredCase: { + type: 'string', + enum: ['lower', 'upper'], + }, + }, + additionalProperties: false, + }, + ], + }, + defaultOptions: [ + { + preferredCase: 'lower', + }, + ], + create(context, options) { + if (options[0].preferredCase === 'lower') { + // ... + } + }, +}); +``` + +:::warning + +When reading the options, use the second parameter of the `create` function, not `context.options` from the first parameter. The first is created by ESLint and does not have the default options applied. + +::: + ## AST Extensions `@typescript-eslint/estree` creates AST nodes for TypeScript syntax with names that begin with `TS`, such as `TSInterfaceDeclaration` and `TSTypeAnnotation`. From 36aecb6a836eb01307c35b42ca60f5a78496c339 Mon Sep 17 00:00:00 2001 From: "typescript-eslint[bot]" Date: Mon, 9 Oct 2023 17:14:15 +0000 Subject: [PATCH 04/16] chore: publish v6.7.5 --- CHANGELOG.md | 13 ++ lerna.json | 2 +- packages/ast-spec/CHANGELOG.md | 10 ++ packages/ast-spec/package.json | 2 +- packages/eslint-plugin-internal/CHANGELOG.md | 10 ++ packages/eslint-plugin-internal/package.json | 10 +- packages/eslint-plugin-tslint/CHANGELOG.md | 10 ++ packages/eslint-plugin-tslint/package.json | 6 +- packages/eslint-plugin/CHANGELOG.md | 13 ++ packages/eslint-plugin/package.json | 14 +-- packages/integration-tests/CHANGELOG.md | 10 ++ packages/integration-tests/package.json | 2 +- packages/parser/CHANGELOG.md | 10 ++ packages/parser/package.json | 10 +- packages/repo-tools/CHANGELOG.md | 10 ++ packages/repo-tools/package.json | 2 +- .../CHANGELOG.md | 10 ++ .../package.json | 6 +- packages/rule-tester/CHANGELOG.md | 10 ++ packages/rule-tester/package.json | 8 +- packages/scope-manager/CHANGELOG.md | 10 ++ packages/scope-manager/package.json | 8 +- packages/type-utils/CHANGELOG.md | 10 ++ packages/type-utils/package.json | 8 +- packages/types/CHANGELOG.md | 10 ++ packages/types/package.json | 2 +- packages/typescript-estree/CHANGELOG.md | 10 ++ packages/typescript-estree/package.json | 6 +- packages/utils/CHANGELOG.md | 10 ++ packages/utils/package.json | 10 +- packages/visitor-keys/CHANGELOG.md | 10 ++ packages/visitor-keys/package.json | 4 +- packages/website-eslint/CHANGELOG.md | 10 ++ packages/website-eslint/package.json | 16 +-- packages/website/CHANGELOG.md | 10 ++ packages/website/package.json | 12 +- yarn.lock | 114 +++++++++--------- 37 files changed, 307 insertions(+), 121 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 096654f23345..eaf2bfc4106c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,19 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.7.5](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.4...v6.7.5) (2023-10-09) + + +### Bug Fixes + +* **eslint-plugin:** [prefer-string-starts-ends-with] only report slice/substring with correct range ([#7712](https://github.com/typescript-eslint/typescript-eslint/issues/7712)) ([db40a0a](https://github.com/typescript-eslint/typescript-eslint/commit/db40a0a83abf14237a7a9b3f75d869da26512292)) + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + ## [6.7.4](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.3...v6.7.4) (2023-10-02) **Note:** Version bump only for package @typescript-eslint/typescript-eslint diff --git a/lerna.json b/lerna.json index 50d40156b52a..776d5f3ad558 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "6.7.4", + "version": "6.7.5", "npmClient": "yarn", "stream": true, "command": { diff --git a/packages/ast-spec/CHANGELOG.md b/packages/ast-spec/CHANGELOG.md index 1c957c332bd7..f3714f9a08f6 100644 --- a/packages/ast-spec/CHANGELOG.md +++ b/packages/ast-spec/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.7.5](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.4...v6.7.5) (2023-10-09) + +**Note:** Version bump only for package @typescript-eslint/ast-spec + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + ## [6.7.4](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.3...v6.7.4) (2023-10-02) **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 6e105ee7653f..a6b0e4fd5505 100644 --- a/packages/ast-spec/package.json +++ b/packages/ast-spec/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/ast-spec", - "version": "6.7.4", + "version": "6.7.5", "description": "Complete specification for the TypeScript-ESTree AST", "private": true, "keywords": [ diff --git a/packages/eslint-plugin-internal/CHANGELOG.md b/packages/eslint-plugin-internal/CHANGELOG.md index c0ccb4181ca3..8803e68dee60 100644 --- a/packages/eslint-plugin-internal/CHANGELOG.md +++ b/packages/eslint-plugin-internal/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.7.5](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.4...v6.7.5) (2023-10-09) + +**Note:** Version bump only for package @typescript-eslint/eslint-plugin-internal + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + ## [6.7.4](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.3...v6.7.4) (2023-10-02) **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 0d9608269058..fbae2a3344a1 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": "6.7.4", + "version": "6.7.5", "private": true, "main": "dist/index.js", "scripts": { @@ -14,10 +14,10 @@ }, "dependencies": { "@types/prettier": "*", - "@typescript-eslint/rule-tester": "6.7.4", - "@typescript-eslint/scope-manager": "6.7.4", - "@typescript-eslint/type-utils": "6.7.4", - "@typescript-eslint/utils": "6.7.4", + "@typescript-eslint/rule-tester": "6.7.5", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/type-utils": "6.7.5", + "@typescript-eslint/utils": "6.7.5", "prettier": "^2.8.4" }, "devDependencies": { diff --git a/packages/eslint-plugin-tslint/CHANGELOG.md b/packages/eslint-plugin-tslint/CHANGELOG.md index fac809c0960e..b1b895ca7da0 100644 --- a/packages/eslint-plugin-tslint/CHANGELOG.md +++ b/packages/eslint-plugin-tslint/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.7.5](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.4...v6.7.5) (2023-10-09) + +**Note:** Version bump only for package @typescript-eslint/eslint-plugin-tslint + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + ## [6.7.4](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.3...v6.7.4) (2023-10-02) **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 58498bd00bc4..8216f5133947 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": "6.7.4", + "version": "6.7.5", "main": "dist/index.js", "typings": "src/index.ts", "description": "ESLint plugin that wraps a TSLint configuration and lints the whole source using TSLint", @@ -46,7 +46,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/utils": "6.7.4" + "@typescript-eslint/utils": "6.7.5" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0", @@ -55,7 +55,7 @@ }, "devDependencies": { "@types/lodash": "*", - "@typescript-eslint/parser": "6.7.4", + "@typescript-eslint/parser": "6.7.5", "jest": "29.7.0", "prettier": "^2.8.4", "rimraf": "*" diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index 4fa2f0a85d65..4423fabe758a 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -3,6 +3,19 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.7.5](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.4...v6.7.5) (2023-10-09) + + +### Bug Fixes + +* **eslint-plugin:** [prefer-string-starts-ends-with] only report slice/substring with correct range ([#7712](https://github.com/typescript-eslint/typescript-eslint/issues/7712)) ([db40a0a](https://github.com/typescript-eslint/typescript-eslint/commit/db40a0a83abf14237a7a9b3f75d869da26512292)) + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + ## [6.7.4](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.3...v6.7.4) (2023-10-02) **Note:** Version bump only for package @typescript-eslint/eslint-plugin diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 15d6b464a2b0..600f4e53aa0a 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin", - "version": "6.7.4", + "version": "6.7.5", "description": "TypeScript plugin for ESLint", "files": [ "dist", @@ -57,10 +57,10 @@ }, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.7.4", - "@typescript-eslint/type-utils": "6.7.4", - "@typescript-eslint/utils": "6.7.4", - "@typescript-eslint/visitor-keys": "6.7.4", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/type-utils": "6.7.5", + "@typescript-eslint/utils": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -73,8 +73,8 @@ "@types/marked": "*", "@types/natural-compare": "*", "@types/prettier": "*", - "@typescript-eslint/rule-schema-to-typescript-types": "6.7.4", - "@typescript-eslint/rule-tester": "6.7.4", + "@typescript-eslint/rule-schema-to-typescript-types": "6.7.5", + "@typescript-eslint/rule-tester": "6.7.5", "ajv": "^6.12.6", "chalk": "^5.3.0", "cross-fetch": "*", diff --git a/packages/integration-tests/CHANGELOG.md b/packages/integration-tests/CHANGELOG.md index 2bee213a782a..8dd504024173 100644 --- a/packages/integration-tests/CHANGELOG.md +++ b/packages/integration-tests/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.7.5](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.4...v6.7.5) (2023-10-09) + +**Note:** Version bump only for package @typescript-eslint/integration-tests + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + ## [6.7.4](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.3...v6.7.4) (2023-10-02) **Note:** Version bump only for package @typescript-eslint/integration-tests diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index 1d7935a61134..920ba556c11f 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/integration-tests", - "version": "6.7.4", + "version": "6.7.5", "private": true, "scripts": { "format": "prettier --write \"./**/*.{ts,mts,cts,tsx,js,mjs,cjs,jsx,json,md,css}\" --ignore-path ../../.prettierignore", diff --git a/packages/parser/CHANGELOG.md b/packages/parser/CHANGELOG.md index e3c66faaed4a..4109841a12f6 100644 --- a/packages/parser/CHANGELOG.md +++ b/packages/parser/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.7.5](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.4...v6.7.5) (2023-10-09) + +**Note:** Version bump only for package @typescript-eslint/parser + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + ## [6.7.4](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.3...v6.7.4) (2023-10-02) **Note:** Version bump only for package @typescript-eslint/parser diff --git a/packages/parser/package.json b/packages/parser/package.json index ec161cd9d45a..66d3c6d918de 100644 --- a/packages/parser/package.json +++ b/packages/parser/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/parser", - "version": "6.7.4", + "version": "6.7.5", "description": "An ESLint custom parser which leverages TypeScript ESTree", "files": [ "dist", @@ -51,10 +51,10 @@ "eslint": "^7.0.0 || ^8.0.0" }, "dependencies": { - "@typescript-eslint/scope-manager": "6.7.4", - "@typescript-eslint/types": "6.7.4", - "@typescript-eslint/typescript-estree": "6.7.4", - "@typescript-eslint/visitor-keys": "6.7.4", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/typescript-estree": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4" }, "devDependencies": { diff --git a/packages/repo-tools/CHANGELOG.md b/packages/repo-tools/CHANGELOG.md index 6f156bc455a8..e55a3588dc58 100644 --- a/packages/repo-tools/CHANGELOG.md +++ b/packages/repo-tools/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.7.5](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.4...v6.7.5) (2023-10-09) + +**Note:** Version bump only for package @typescript-eslint/repo-tools + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + ## [6.7.4](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.3...v6.7.4) (2023-10-02) **Note:** Version bump only for package @typescript-eslint/repo-tools diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index 0704067a83be..3332d914311d 100644 --- a/packages/repo-tools/package.json +++ b/packages/repo-tools/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/repo-tools", - "version": "6.7.4", + "version": "6.7.5", "private": true, "scripts": { "//": "NOTE: intentionally no build step in this package", diff --git a/packages/rule-schema-to-typescript-types/CHANGELOG.md b/packages/rule-schema-to-typescript-types/CHANGELOG.md index 55ab80d35421..f96409d3f3a4 100644 --- a/packages/rule-schema-to-typescript-types/CHANGELOG.md +++ b/packages/rule-schema-to-typescript-types/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.7.5](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.4...v6.7.5) (2023-10-09) + +**Note:** Version bump only for package @typescript-eslint/rule-schema-to-typescript-types + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + ## [6.7.4](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.3...v6.7.4) (2023-10-02) **Note:** Version bump only for package @typescript-eslint/rule-schema-to-typescript-types diff --git a/packages/rule-schema-to-typescript-types/package.json b/packages/rule-schema-to-typescript-types/package.json index a4a523ba51a4..04b6a5deb482 100644 --- a/packages/rule-schema-to-typescript-types/package.json +++ b/packages/rule-schema-to-typescript-types/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/rule-schema-to-typescript-types", - "version": "6.7.4", + "version": "6.7.5", "private": true, "type": "commonjs", "exports": { @@ -33,8 +33,8 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/type-utils": "6.7.4", - "@typescript-eslint/utils": "6.7.4", + "@typescript-eslint/type-utils": "6.7.5", + "@typescript-eslint/utils": "6.7.5", "natural-compare": "^1.4.0", "prettier": "^2.8.4" }, diff --git a/packages/rule-tester/CHANGELOG.md b/packages/rule-tester/CHANGELOG.md index 66184e48308e..7073cb937b9d 100644 --- a/packages/rule-tester/CHANGELOG.md +++ b/packages/rule-tester/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.7.5](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.4...v6.7.5) (2023-10-09) + +**Note:** Version bump only for package @typescript-eslint/rule-tester + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + ## [6.7.4](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.3...v6.7.4) (2023-10-02) **Note:** Version bump only for package @typescript-eslint/rule-tester diff --git a/packages/rule-tester/package.json b/packages/rule-tester/package.json index 3f6424c9d519..51c0bbdf32d4 100644 --- a/packages/rule-tester/package.json +++ b/packages/rule-tester/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/rule-tester", - "version": "6.7.4", + "version": "6.7.5", "description": "Tooling to test ESLint rules", "files": [ "dist", @@ -47,8 +47,8 @@ }, "//": "NOTE - AJV is out-of-date, but it's intentionally synced with ESLint - https://github.com/eslint/eslint/blob/ad9dd6a933fd098a0d99c6a9aa059850535c23ee/package.json#L70", "dependencies": { - "@typescript-eslint/typescript-estree": "6.7.4", - "@typescript-eslint/utils": "6.7.4", + "@typescript-eslint/typescript-estree": "6.7.5", + "@typescript-eslint/utils": "6.7.5", "ajv": "^6.10.0", "lodash.merge": "4.6.2", "semver": "^7.5.4" @@ -59,7 +59,7 @@ }, "devDependencies": { "@types/lodash.merge": "4.6.7", - "@typescript-eslint/parser": "6.7.4", + "@typescript-eslint/parser": "6.7.5", "chai": "^4.3.7", "mocha": "^10.0.0", "sinon": "^15.0.0", diff --git a/packages/scope-manager/CHANGELOG.md b/packages/scope-manager/CHANGELOG.md index d78dcc7bc7ac..4412ee7f9c75 100644 --- a/packages/scope-manager/CHANGELOG.md +++ b/packages/scope-manager/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.7.5](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.4...v6.7.5) (2023-10-09) + +**Note:** Version bump only for package @typescript-eslint/scope-manager + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + ## [6.7.4](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.3...v6.7.4) (2023-10-02) **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 1b5c0a8babea..7af913f3051b 100644 --- a/packages/scope-manager/package.json +++ b/packages/scope-manager/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/scope-manager", - "version": "6.7.4", + "version": "6.7.5", "description": "TypeScript scope analyser for ESLint", "files": [ "dist", @@ -44,12 +44,12 @@ "typecheck": "nx typecheck" }, "dependencies": { - "@typescript-eslint/types": "6.7.4", - "@typescript-eslint/visitor-keys": "6.7.4" + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5" }, "devDependencies": { "@types/glob": "*", - "@typescript-eslint/typescript-estree": "6.7.4", + "@typescript-eslint/typescript-estree": "6.7.5", "glob": "*", "jest-specific-snapshot": "*", "make-dir": "*", diff --git a/packages/type-utils/CHANGELOG.md b/packages/type-utils/CHANGELOG.md index ce6d1735e880..a15a6f61c0f9 100644 --- a/packages/type-utils/CHANGELOG.md +++ b/packages/type-utils/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.7.5](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.4...v6.7.5) (2023-10-09) + +**Note:** Version bump only for package @typescript-eslint/type-utils + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + ## [6.7.4](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.3...v6.7.4) (2023-10-02) **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 747838953d9d..8f2536e585da 100644 --- a/packages/type-utils/package.json +++ b/packages/type-utils/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/type-utils", - "version": "6.7.4", + "version": "6.7.5", "description": "Type utilities for working with TypeScript + ESLint together", "files": [ "dist", @@ -45,13 +45,13 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/typescript-estree": "6.7.4", - "@typescript-eslint/utils": "6.7.4", + "@typescript-eslint/typescript-estree": "6.7.5", + "@typescript-eslint/utils": "6.7.5", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, "devDependencies": { - "@typescript-eslint/parser": "6.7.4", + "@typescript-eslint/parser": "6.7.5", "ajv": "^6.10.0", "downlevel-dts": "*", "jest": "29.7.0", diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index be47c2ec8aab..8d80b126994d 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.7.5](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.4...v6.7.5) (2023-10-09) + +**Note:** Version bump only for package @typescript-eslint/types + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + ## [6.7.4](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.3...v6.7.4) (2023-10-02) **Note:** Version bump only for package @typescript-eslint/types diff --git a/packages/types/package.json b/packages/types/package.json index df548d9f0793..5c428f982a6c 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/types", - "version": "6.7.4", + "version": "6.7.5", "description": "Types for the TypeScript-ESTree AST spec", "files": [ "dist", diff --git a/packages/typescript-estree/CHANGELOG.md b/packages/typescript-estree/CHANGELOG.md index b299af1f122d..becec9a6aa02 100644 --- a/packages/typescript-estree/CHANGELOG.md +++ b/packages/typescript-estree/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.7.5](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.4...v6.7.5) (2023-10-09) + +**Note:** Version bump only for package @typescript-eslint/typescript-estree + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + ## [6.7.4](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.3...v6.7.4) (2023-10-02) **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 13fb09e1305d..9d6ba24ce9d9 100644 --- a/packages/typescript-estree/package.json +++ b/packages/typescript-estree/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/typescript-estree", - "version": "6.7.4", + "version": "6.7.5", "description": "A parser that converts TypeScript source code into an ESTree compatible form", "files": [ "dist", @@ -52,8 +52,8 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/types": "6.7.4", - "@typescript-eslint/visitor-keys": "6.7.4", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md index 9a90902a4f88..28c36a2edb43 100644 --- a/packages/utils/CHANGELOG.md +++ b/packages/utils/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.7.5](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.4...v6.7.5) (2023-10-09) + +**Note:** Version bump only for package @typescript-eslint/utils + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + ## [6.7.4](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.3...v6.7.4) (2023-10-02) **Note:** Version bump only for package @typescript-eslint/utils diff --git a/packages/utils/package.json b/packages/utils/package.json index 1548cb2caf34..ee0e6db96bf0 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/utils", - "version": "6.7.4", + "version": "6.7.5", "description": "Utilities for working with TypeScript + ESLint together", "files": [ "dist", @@ -68,16 +68,16 @@ "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.7.4", - "@typescript-eslint/types": "6.7.4", - "@typescript-eslint/typescript-estree": "6.7.4", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/typescript-estree": "6.7.5", "semver": "^7.5.4" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0" }, "devDependencies": { - "@typescript-eslint/parser": "6.7.4", + "@typescript-eslint/parser": "6.7.5", "downlevel-dts": "*", "jest": "29.7.0", "prettier": "^2.8.4", diff --git a/packages/visitor-keys/CHANGELOG.md b/packages/visitor-keys/CHANGELOG.md index 5244d796b495..204e5e631d28 100644 --- a/packages/visitor-keys/CHANGELOG.md +++ b/packages/visitor-keys/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.7.5](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.4...v6.7.5) (2023-10-09) + +**Note:** Version bump only for package @typescript-eslint/visitor-keys + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + ## [6.7.4](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.3...v6.7.4) (2023-10-02) **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 6f64e7cdc3ba..6d7615d37f26 100644 --- a/packages/visitor-keys/package.json +++ b/packages/visitor-keys/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/visitor-keys", - "version": "6.7.4", + "version": "6.7.5", "description": "Visitor keys used to help traverse the TypeScript-ESTree AST", "files": [ "dist", @@ -45,7 +45,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/types": "6.7.4", + "@typescript-eslint/types": "6.7.5", "eslint-visitor-keys": "^3.4.1" }, "devDependencies": { diff --git a/packages/website-eslint/CHANGELOG.md b/packages/website-eslint/CHANGELOG.md index 0374329f582b..476c628fd0ca 100644 --- a/packages/website-eslint/CHANGELOG.md +++ b/packages/website-eslint/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.7.5](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.4...v6.7.5) (2023-10-09) + +**Note:** Version bump only for package @typescript-eslint/website-eslint + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + ## [6.7.4](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.3...v6.7.4) (2023-10-02) **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 3eef1c891bf1..58b4fa0e124e 100644 --- a/packages/website-eslint/package.json +++ b/packages/website-eslint/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/website-eslint", - "version": "6.7.4", + "version": "6.7.5", "private": true, "description": "ESLint which works in browsers.", "files": [ @@ -23,16 +23,16 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@typescript-eslint/types": "6.7.4", - "@typescript-eslint/utils": "6.7.4" + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/utils": "6.7.5" }, "devDependencies": { "@eslint/js": "8.49.0", - "@typescript-eslint/eslint-plugin": "6.7.4", - "@typescript-eslint/parser": "6.7.4", - "@typescript-eslint/scope-manager": "6.7.4", - "@typescript-eslint/typescript-estree": "6.7.4", - "@typescript-eslint/visitor-keys": "6.7.4", + "@typescript-eslint/eslint-plugin": "6.7.5", + "@typescript-eslint/parser": "6.7.5", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/typescript-estree": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "esbuild": "~0.19.0", "eslint": "*", "esquery": "*", diff --git a/packages/website/CHANGELOG.md b/packages/website/CHANGELOG.md index bdf8c6df4250..bbe4d7c288b0 100644 --- a/packages/website/CHANGELOG.md +++ b/packages/website/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.7.5](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.4...v6.7.5) (2023-10-09) + +**Note:** Version bump only for package website + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + ## [6.7.4](https://github.com/typescript-eslint/typescript-eslint/compare/v6.7.3...v6.7.4) (2023-10-02) **Note:** Version bump only for package website diff --git a/packages/website/package.json b/packages/website/package.json index 2fc26380dccb..0db43591f4bc 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -1,6 +1,6 @@ { "name": "website", - "version": "6.7.4", + "version": "6.7.5", "private": true, "scripts": { "build": "docusaurus build", @@ -24,8 +24,8 @@ "@docusaurus/remark-plugin-npm2yarn": "~2.4.1", "@docusaurus/theme-common": "~2.4.1", "@mdx-js/react": "1.6.22", - "@typescript-eslint/parser": "6.7.4", - "@typescript-eslint/website-eslint": "6.7.4", + "@typescript-eslint/parser": "6.7.5", + "@typescript-eslint/website-eslint": "6.7.5", "clsx": "^2.0.0", "eslint": "*", "json-schema": "^0.4.0", @@ -52,9 +52,9 @@ "@types/react": "*", "@types/react-helmet": "^6.1.6", "@types/react-router-dom": "^5.3.3", - "@typescript-eslint/eslint-plugin": "6.7.4", - "@typescript-eslint/rule-schema-to-typescript-types": "6.7.4", - "@typescript-eslint/types": "6.7.4", + "@typescript-eslint/eslint-plugin": "6.7.5", + "@typescript-eslint/rule-schema-to-typescript-types": "6.7.5", + "@typescript-eslint/types": "6.7.5", "copy-webpack-plugin": "^11.0.0", "cross-fetch": "*", "globby": "^11.1.0", diff --git a/yarn.lock b/yarn.lock index 6cd44b1e1e7d..9a478c3e19d2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5741,10 +5741,10 @@ __metadata: resolution: "@typescript-eslint/eslint-plugin-internal@workspace:packages/eslint-plugin-internal" dependencies: "@types/prettier": "*" - "@typescript-eslint/rule-tester": 6.7.4 - "@typescript-eslint/scope-manager": 6.7.4 - "@typescript-eslint/type-utils": 6.7.4 - "@typescript-eslint/utils": 6.7.4 + "@typescript-eslint/rule-tester": 6.7.5 + "@typescript-eslint/scope-manager": 6.7.5 + "@typescript-eslint/type-utils": 6.7.5 + "@typescript-eslint/utils": 6.7.5 jest: 29.7.0 prettier: ^2.8.4 rimraf: "*" @@ -5756,8 +5756,8 @@ __metadata: resolution: "@typescript-eslint/eslint-plugin-tslint@workspace:packages/eslint-plugin-tslint" dependencies: "@types/lodash": "*" - "@typescript-eslint/parser": 6.7.4 - "@typescript-eslint/utils": 6.7.4 + "@typescript-eslint/parser": 6.7.5 + "@typescript-eslint/utils": 6.7.5 jest: 29.7.0 prettier: ^2.8.4 rimraf: "*" @@ -5768,7 +5768,7 @@ __metadata: languageName: unknown linkType: soft -"@typescript-eslint/eslint-plugin@6.7.4, @typescript-eslint/eslint-plugin@workspace:packages/eslint-plugin": +"@typescript-eslint/eslint-plugin@6.7.5, @typescript-eslint/eslint-plugin@workspace:packages/eslint-plugin": version: 0.0.0-use.local resolution: "@typescript-eslint/eslint-plugin@workspace:packages/eslint-plugin" dependencies: @@ -5777,12 +5777,12 @@ __metadata: "@types/marked": "*" "@types/natural-compare": "*" "@types/prettier": "*" - "@typescript-eslint/rule-schema-to-typescript-types": 6.7.4 - "@typescript-eslint/rule-tester": 6.7.4 - "@typescript-eslint/scope-manager": 6.7.4 - "@typescript-eslint/type-utils": 6.7.4 - "@typescript-eslint/utils": 6.7.4 - "@typescript-eslint/visitor-keys": 6.7.4 + "@typescript-eslint/rule-schema-to-typescript-types": 6.7.5 + "@typescript-eslint/rule-tester": 6.7.5 + "@typescript-eslint/scope-manager": 6.7.5 + "@typescript-eslint/type-utils": 6.7.5 + "@typescript-eslint/utils": 6.7.5 + "@typescript-eslint/visitor-keys": 6.7.5 ajv: ^6.12.6 chalk: ^5.3.0 cross-fetch: "*" @@ -5821,15 +5821,15 @@ __metadata: languageName: unknown linkType: soft -"@typescript-eslint/parser@6.7.4, @typescript-eslint/parser@workspace:packages/parser": +"@typescript-eslint/parser@6.7.5, @typescript-eslint/parser@workspace:packages/parser": version: 0.0.0-use.local resolution: "@typescript-eslint/parser@workspace:packages/parser" dependencies: "@types/glob": "*" - "@typescript-eslint/scope-manager": 6.7.4 - "@typescript-eslint/types": 6.7.4 - "@typescript-eslint/typescript-estree": 6.7.4 - "@typescript-eslint/visitor-keys": 6.7.4 + "@typescript-eslint/scope-manager": 6.7.5 + "@typescript-eslint/types": 6.7.5 + "@typescript-eslint/typescript-estree": 6.7.5 + "@typescript-eslint/visitor-keys": 6.7.5 debug: ^4.3.4 downlevel-dts: "*" glob: "*" @@ -5859,25 +5859,25 @@ __metadata: languageName: unknown linkType: soft -"@typescript-eslint/rule-schema-to-typescript-types@6.7.4, @typescript-eslint/rule-schema-to-typescript-types@workspace:packages/rule-schema-to-typescript-types": +"@typescript-eslint/rule-schema-to-typescript-types@6.7.5, @typescript-eslint/rule-schema-to-typescript-types@workspace:packages/rule-schema-to-typescript-types": version: 0.0.0-use.local resolution: "@typescript-eslint/rule-schema-to-typescript-types@workspace:packages/rule-schema-to-typescript-types" dependencies: - "@typescript-eslint/type-utils": 6.7.4 - "@typescript-eslint/utils": 6.7.4 + "@typescript-eslint/type-utils": 6.7.5 + "@typescript-eslint/utils": 6.7.5 natural-compare: ^1.4.0 prettier: ^2.8.4 languageName: unknown linkType: soft -"@typescript-eslint/rule-tester@6.7.4, @typescript-eslint/rule-tester@workspace:packages/rule-tester": +"@typescript-eslint/rule-tester@6.7.5, @typescript-eslint/rule-tester@workspace:packages/rule-tester": version: 0.0.0-use.local resolution: "@typescript-eslint/rule-tester@workspace:packages/rule-tester" dependencies: "@types/lodash.merge": 4.6.7 - "@typescript-eslint/parser": 6.7.4 - "@typescript-eslint/typescript-estree": 6.7.4 - "@typescript-eslint/utils": 6.7.4 + "@typescript-eslint/parser": 6.7.5 + "@typescript-eslint/typescript-estree": 6.7.5 + "@typescript-eslint/utils": 6.7.5 ajv: ^6.10.0 chai: ^4.3.7 lodash.merge: 4.6.2 @@ -5891,14 +5891,14 @@ __metadata: languageName: unknown linkType: soft -"@typescript-eslint/scope-manager@6.7.4, @typescript-eslint/scope-manager@workspace:packages/scope-manager": +"@typescript-eslint/scope-manager@6.7.5, @typescript-eslint/scope-manager@workspace:packages/scope-manager": version: 0.0.0-use.local resolution: "@typescript-eslint/scope-manager@workspace:packages/scope-manager" dependencies: "@types/glob": "*" - "@typescript-eslint/types": 6.7.4 - "@typescript-eslint/typescript-estree": 6.7.4 - "@typescript-eslint/visitor-keys": 6.7.4 + "@typescript-eslint/types": 6.7.5 + "@typescript-eslint/typescript-estree": 6.7.5 + "@typescript-eslint/visitor-keys": 6.7.5 glob: "*" jest-specific-snapshot: "*" make-dir: "*" @@ -5917,13 +5917,13 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/type-utils@6.7.4, @typescript-eslint/type-utils@workspace:packages/type-utils": +"@typescript-eslint/type-utils@6.7.5, @typescript-eslint/type-utils@workspace:packages/type-utils": version: 0.0.0-use.local resolution: "@typescript-eslint/type-utils@workspace:packages/type-utils" dependencies: - "@typescript-eslint/parser": 6.7.4 - "@typescript-eslint/typescript-estree": 6.7.4 - "@typescript-eslint/utils": 6.7.4 + "@typescript-eslint/parser": 6.7.5 + "@typescript-eslint/typescript-estree": 6.7.5 + "@typescript-eslint/utils": 6.7.5 ajv: ^6.10.0 debug: ^4.3.4 downlevel-dts: "*" @@ -5940,7 +5940,7 @@ __metadata: languageName: unknown linkType: soft -"@typescript-eslint/types@6.7.4, @typescript-eslint/types@workspace:packages/types": +"@typescript-eslint/types@6.7.5, @typescript-eslint/types@workspace:packages/types": version: 0.0.0-use.local resolution: "@typescript-eslint/types@workspace:packages/types" dependencies: @@ -6030,14 +6030,14 @@ __metadata: languageName: unknown linkType: soft -"@typescript-eslint/typescript-estree@6.7.4, @typescript-eslint/typescript-estree@workspace:packages/typescript-estree": +"@typescript-eslint/typescript-estree@6.7.5, @typescript-eslint/typescript-estree@workspace:packages/typescript-estree": version: 0.0.0-use.local resolution: "@typescript-eslint/typescript-estree@workspace:packages/typescript-estree" dependencies: "@babel/code-frame": "*" "@babel/parser": "*" - "@typescript-eslint/types": 6.7.4 - "@typescript-eslint/visitor-keys": 6.7.4 + "@typescript-eslint/types": 6.7.5 + "@typescript-eslint/visitor-keys": 6.7.5 debug: ^4.3.4 glob: "*" globby: ^11.1.0 @@ -6075,17 +6075,17 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@6.7.4, @typescript-eslint/utils@workspace:packages/utils": +"@typescript-eslint/utils@6.7.5, @typescript-eslint/utils@workspace:packages/utils": version: 0.0.0-use.local resolution: "@typescript-eslint/utils@workspace:packages/utils" dependencies: "@eslint-community/eslint-utils": ^4.4.0 "@types/json-schema": ^7.0.12 "@types/semver": ^7.5.0 - "@typescript-eslint/parser": 6.7.4 - "@typescript-eslint/scope-manager": 6.7.4 - "@typescript-eslint/types": 6.7.4 - "@typescript-eslint/typescript-estree": 6.7.4 + "@typescript-eslint/parser": 6.7.5 + "@typescript-eslint/scope-manager": 6.7.5 + "@typescript-eslint/types": 6.7.5 + "@typescript-eslint/typescript-estree": 6.7.5 downlevel-dts: "*" jest: 29.7.0 prettier: ^2.8.4 @@ -6115,12 +6115,12 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@6.7.4, @typescript-eslint/visitor-keys@workspace:packages/visitor-keys": +"@typescript-eslint/visitor-keys@6.7.5, @typescript-eslint/visitor-keys@workspace:packages/visitor-keys": version: 0.0.0-use.local resolution: "@typescript-eslint/visitor-keys@workspace:packages/visitor-keys" dependencies: "@types/eslint-visitor-keys": "*" - "@typescript-eslint/types": 6.7.4 + "@typescript-eslint/types": 6.7.5 downlevel-dts: "*" eslint-visitor-keys: ^3.4.1 jest: 29.7.0 @@ -6140,18 +6140,18 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/website-eslint@6.7.4, @typescript-eslint/website-eslint@workspace:packages/website-eslint": +"@typescript-eslint/website-eslint@6.7.5, @typescript-eslint/website-eslint@workspace:packages/website-eslint": version: 0.0.0-use.local resolution: "@typescript-eslint/website-eslint@workspace:packages/website-eslint" dependencies: "@eslint/js": 8.49.0 - "@typescript-eslint/eslint-plugin": 6.7.4 - "@typescript-eslint/parser": 6.7.4 - "@typescript-eslint/scope-manager": 6.7.4 - "@typescript-eslint/types": 6.7.4 - "@typescript-eslint/typescript-estree": 6.7.4 - "@typescript-eslint/utils": 6.7.4 - "@typescript-eslint/visitor-keys": 6.7.4 + "@typescript-eslint/eslint-plugin": 6.7.5 + "@typescript-eslint/parser": 6.7.5 + "@typescript-eslint/scope-manager": 6.7.5 + "@typescript-eslint/types": 6.7.5 + "@typescript-eslint/typescript-estree": 6.7.5 + "@typescript-eslint/utils": 6.7.5 + "@typescript-eslint/visitor-keys": 6.7.5 esbuild: ~0.19.0 eslint: "*" esquery: "*" @@ -20786,11 +20786,11 @@ __metadata: "@types/react": "*" "@types/react-helmet": ^6.1.6 "@types/react-router-dom": ^5.3.3 - "@typescript-eslint/eslint-plugin": 6.7.4 - "@typescript-eslint/parser": 6.7.4 - "@typescript-eslint/rule-schema-to-typescript-types": 6.7.4 - "@typescript-eslint/types": 6.7.4 - "@typescript-eslint/website-eslint": 6.7.4 + "@typescript-eslint/eslint-plugin": 6.7.5 + "@typescript-eslint/parser": 6.7.5 + "@typescript-eslint/rule-schema-to-typescript-types": 6.7.5 + "@typescript-eslint/types": 6.7.5 + "@typescript-eslint/website-eslint": 6.7.5 clsx: ^2.0.0 copy-webpack-plugin: ^11.0.0 cross-fetch: "*" From a9c7928b34adde86078ea27b95f0fd083d9ea573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A1ndor=20Levcs=C3=A1k?= <37511777+levchak0910@users.noreply.github.com> Date: Mon, 9 Oct 2023 23:55:47 +0200 Subject: [PATCH 05/16] docs(eslint-plugin): [explicit-function-return-type] fix typo in option name (#7728) * docs(eslint-plugin): fix typo in option name | rule: explicit-function-return-type * docs(eslint-plugin): add tags | rule: explicit-function-return-type --- .../docs/rules/explicit-function-return-type.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/explicit-function-return-type.md b/packages/eslint-plugin/docs/rules/explicit-function-return-type.md index 0d0e476d576c..c7ac599ac56c 100644 --- a/packages/eslint-plugin/docs/rules/explicit-function-return-type.md +++ b/packages/eslint-plugin/docs/rules/explicit-function-return-type.md @@ -289,9 +289,11 @@ You may pass function/method names you would like this rule to ignore, like so: } ``` -### `allowIIFE` +### `allowIIFEs` -Examples of code for this rule with `{ allowIIFE: true }`: +Examples of code for this rule with `{ allowIIFEs: true }`: + + #### ❌ Incorrect From 6d73b8016a358459996b7dd5ffccd710a56dcb0f Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Wed, 11 Oct 2023 05:30:01 +1030 Subject: [PATCH 06/16] chore: add discord and stackoverflow as links to issue template (#7645) * chore: add discord and stackoverflow as links to issue template IDK if this is the best as it adds more noise But people can't easily find these options right now without jumping through some hoops. * fix trailing space formatting --------- Co-authored-by: Josh Goldberg --- .github/ISSUE_TEMPLATE/config.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 566c2f4fc8a6..f8f0ec0f29d9 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -6,3 +6,9 @@ contact_links: - name: Getting Started Guide about: If you're looking for help setting up check out our getting started guide url: https://typescript-eslint.io + - name: Ask a question on Discord + about: If you just want to ask a question, consider asking it on Discord! + url: https://discord.gg/FSxKq8Tdyg + - name: Ask a question on StackOverflow + about: If you just want to ask a question, consider asking it on StackOverflow! + url: https://stackoverflow.com/questions/tagged/typescript-eslint From e50d1a39a057b006b99bb47718122728b319eb92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= Date: Tue, 10 Oct 2023 20:14:53 -0400 Subject: [PATCH 07/16] chore: remove Playwright end-to-end website tests (#7730) build: remove playwright --- .github/workflows/ci.yml | 53 -------------- .gitignore | 3 - .prettierignore | 1 - package.json | 1 - packages/website/package.json | 3 - packages/website/playwright.config.ts | 32 --------- packages/website/tests/index.spec.ts | 38 ---------- packages/website/tests/playground.spec.ts | 84 ----------------------- packages/website/tests/rules.spec.ts | 32 --------- yarn.lock | 44 +----------- 10 files changed, 3 insertions(+), 288 deletions(-) delete mode 100644 packages/website/playwright.config.ts delete mode 100644 packages/website/tests/index.spec.ts delete mode 100644 packages/website/tests/playground.spec.ts delete mode 100644 packages/website/tests/rules.spec.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51cbca79ec7b..a7f281997d3f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -240,59 +240,6 @@ jobs: CI: true TYPESCRIPT_ESLINT_EXPERIMENTAL_TSSERVER: true - website_tests: - permissions: - contents: read # to fetch code (actions/checkout) - - name: Website tests - # We technically do not need to wait for build within the pipeline any more because the build we care about is happening within Netlify, however, - # it is highly likely that if the CI one fails, the Netlify one will as well, so in order to not waste unncessary Github Actions minutes/resources, - # we do still keep this requirement here. - needs: [build] - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 2 - - - name: Install - uses: ./.github/actions/prepare-install - with: - node-version: ${{ env.PRIMARY_NODE_VERSION }} - - - name: Build website - if: github.repository != 'typescript-eslint/typescript-eslint' || github.ref != 'refs/heads/main' - run: NX_VERBOSE_LOGGING=true yarn nx build website - - - name: Install Playwright Browsers - run: npx playwright install --with-deps chromium - - - name: Wait for Netlify deployment - if: github.repository == 'typescript-eslint/typescript-eslint' && github.ref == 'refs/heads/main' - uses: ./.github/actions/wait-for-netlify - id: waitForDeployment - with: - netlify_token: ${{ secrets.NETLIFY_TOKEN }} - - - name: Run Playwright tests against the Netlify deployment - if: github.repository == 'typescript-eslint/typescript-eslint' && github.ref == 'refs/heads/main' - run: yarn playwright test --reporter=list - working-directory: packages/website - env: - PLAYWRIGHT_TEST_BASE_URL: ${{ steps.waitForDeployment.outputs.url }} - - - name: Run Playwright tests against local deployment - if: github.repository != 'typescript-eslint/typescript-eslint' || github.ref != 'refs/heads/main' - run: yarn playwright test --reporter=list - working-directory: packages/website - - - if: always() - uses: actions/upload-artifact@v3 - with: - name: playwright-report - path: packages/website/playwright-report - upload_coverage: name: Upload Codecov Coverage needs: [unit_tests] diff --git a/.gitignore b/.gitignore index fb6fcf441bdd..4756d89c4232 100644 --- a/.gitignore +++ b/.gitignore @@ -9,10 +9,7 @@ yarn-error.log* packages/website/.docusaurus packages/website/.cache-loader packages/website/build -packages/website/playwright-report -packages/website/playwright/.cache packages/website/static/sandbox -packages/website/test-results # Runtime data pids diff --git a/.prettierignore b/.prettierignore index dc8cabea0d18..bb98ef6ac961 100644 --- a/.prettierignore +++ b/.prettierignore @@ -29,7 +29,6 @@ CHANGELOG.md packages/website/.docusaurus packages/website/build -packages/website/playwright-report # see the file header in eslint-base.test.js for more info packages/rule-tester/tests/eslint-base diff --git a/package.json b/package.json index a3162ea9d381..972b72dc1b23 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,6 @@ "start": "nx run website:start", "test": "nx run-many --target=test --parallel --exclude integration-tests --exclude website --exclude website-eslint", "test-integration": "nx run integration-tests:test", - "test-website": "nx run-many --target=test --projects=website,website-eslint", "typecheck": "nx run-many --target=typecheck --parallel" }, "engines": { diff --git a/packages/website/package.json b/packages/website/package.json index 0db43591f4bc..ac18315314a4 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -13,7 +13,6 @@ "serve": "docusaurus serve", "start": "nx start", "swizzle": "docusaurus swizzle", - "test": "playwright test", "typecheck": "tsc -b ./tsconfig.json" }, "dependencies": { @@ -46,9 +45,7 @@ "react": "^18.2.0" }, "devDependencies": { - "@axe-core/playwright": "^4.7.3", "@docusaurus/module-type-aliases": "~2.4.1", - "@playwright/test": "^1.36.0", "@types/react": "*", "@types/react-helmet": "^6.1.6", "@types/react-router-dom": "^5.3.3", diff --git a/packages/website/playwright.config.ts b/packages/website/playwright.config.ts deleted file mode 100644 index fa403223152b..000000000000 --- a/packages/website/playwright.config.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { PlaywrightTestConfig } from '@playwright/test'; -import { devices } from '@playwright/test'; - -const config: PlaywrightTestConfig = { - forbidOnly: !!process.env.CI, - fullyParallel: true, - reporter: 'html', - retries: 0, - testDir: './tests', - use: { - baseURL: process.env.PLAYWRIGHT_TEST_BASE_URL ?? 'http://localhost:3000', - trace: 'on-first-retry', - }, - projects: [ - { - name: 'chromium', - use: { - ...devices['Desktop Chrome'], - }, - }, - ], - webServer: process.env.PLAYWRIGHT_TEST_BASE_URL - ? undefined - : { - command: 'yarn start', - port: 3000, - reuseExistingServer: !process.env.CI, - }, - workers: process.env.CI ? 1 : undefined, -}; - -export default config; diff --git a/packages/website/tests/index.spec.ts b/packages/website/tests/index.spec.ts deleted file mode 100644 index b29adeb4bc21..000000000000 --- a/packages/website/tests/index.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import AxeBuilder from '@axe-core/playwright'; -import { expect, test } from '@playwright/test'; - -test.describe('Website', () => { - test.beforeEach(async ({ context }) => { - // Sponsor logos are sometimes changed or removed between deploys - await context.route('https://images.opencollective.com/**/*.png', route => - route.fulfill({ - status: 200, - body: '', - }), - ); - }); - - test('Axe', async ({ page }) => { - await page.goto('/'); - await new AxeBuilder({ page }).analyze(); - }); - - test('should have no errors', async ({ page }) => { - const errorMessages: string[] = []; - page.on('console', msg => { - const type = msg.type(); - if (!['error', 'warning'].includes(type)) { - return; - } - const text = msg.text(); - // this log is fine because the ReactDOM usage is controlled by docusaurus, not us - if (text.includes('ReactDOM.render is no longer supported in React 18')) { - return; - } - errorMessages.push(`[${type}] ${text}`); - }); - await page.goto('/', { waitUntil: 'domcontentloaded' }); - await expect(page).toHaveTitle('typescript-eslint'); - expect(errorMessages).toStrictEqual([]); - }); -}); diff --git a/packages/website/tests/playground.spec.ts b/packages/website/tests/playground.spec.ts deleted file mode 100644 index 67f679359db7..000000000000 --- a/packages/website/tests/playground.spec.ts +++ /dev/null @@ -1,84 +0,0 @@ -import AxeBuilder from '@axe-core/playwright'; -import type { Page } from '@playwright/test'; -import { expect, test } from '@playwright/test'; - -// TODO: fix these tests and reenable them -test.describe.skip('Playground', () => { - test.beforeEach(async ({ page }) => { - await page.goto('/play'); - }); - - test('Accessibility', async ({ page }) => { - await new AxeBuilder({ page }).analyze(); - }); - - test('Usage', async ({ page }) => { - // 1. Type some valid code in the playground - await writeInEditor(page, 'let value: string[];'); - - // 2. Enable a lint rule - await page.getByRole('tab', { name: 'eslintrc' }).click(); - await page.getByRole('button', { name: 'Visual Editor' }).click(); - await page - .getByLabel( - '@typescript-eslint/array-type Require consistently using either `T[]` or `Array` for arrays', - ) - .check(); - await page.getByRole('button', { name: 'Close' }).click(); - - // 3. Make sure it still says "All is ok!" - await expect(page.getByText('All is ok!')).toBeVisible(); - - // 4. Change the code to violate the lint rule - await page.getByRole('tab', { name: 'code' }).click(); - await writeInEditor(page, 'let value: Array;'); - - // 5. Make sure it now says the complaint - await expect( - page.getByText( - `Array type using 'Array' is forbidden. Use 'string[]' instead. 1:12 - 1:25`, - ), - ).toBeVisible(); - - // 6. Press the 'fix' button to autofix that complaint - await page.getByRole('button', { name: 'fix' }).click(); - - // 7. Make sure the code is updated, and it says "All is ok!" - await expect(page.getByText('let value: string[];')).toBeVisible(); - await expect(page.getByText('All is ok!')).toBeVisible(); - }); - - test('AST Viewer', async ({ page }) => { - // 1. Type some valid code in the playground - await writeInEditor(page, 'let value: Array;'); - - // 2. Enable AST viewer - await page - .getByRole('combobox', { name: 'AST Viewer' }) - .selectOption({ label: 'ESTree' }); - - // 3. Type some valid code in the playground - await writeInEditor(page, 'let value: Array;'); - - // 4. Validate variable declaration block exists in AST viewer - await expect( - page.getByRole('link', { name: 'VariableDeclaration' }), - ).toBeVisible(); - }); -}); - -async function writeInEditor(page: Page, text: string): Promise { - const monacoEditor = page.locator('.monaco-editor').nth(0); - await monacoEditor.click(); - - // Select all existing text and delete it first... - await page.keyboard.down('Control'); - await page.keyboard.down('A'); - await page.keyboard.up('Control'); - await page.keyboard.up('A'); - await page.keyboard.down('Delete'); - await page.keyboard.up('Delete'); - - // ...and then type in the text - await page.keyboard.type(text); -} diff --git a/packages/website/tests/rules.spec.ts b/packages/website/tests/rules.spec.ts deleted file mode 100644 index faba1bdd447a..000000000000 --- a/packages/website/tests/rules.spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -import AxeBuilder from '@axe-core/playwright'; -import { expect, test } from '@playwright/test'; - -test.describe('Rules Page', () => { - test.beforeEach(async ({ page }) => { - await page.goto('/rules'); - }); - - test('Accessibility', async ({ page }) => { - await new AxeBuilder({ page }).analyze(); - }); - - test('Rules filters are saved to the URL', async ({ page }) => { - await page.getByText('🔧 fixable').first().click(); - await page.getByText('✅ recommended').first().click(); - await page.getByText('✅ recommended').first().click(); - - expect(new URL(page.url()).search).toBe( - '?supported-rules=xrecommended-fixable', - ); - }); - - test('Rules filters are read from the URL on page load', async ({ page }) => { - await page.goto('/rules?supported-rules=strict-xfixable'); - - const strict = page.getByText('🔒 strict').first(); - const fixable = page.getByText('🔧 fixable').first(); - - await expect(strict).toHaveAttribute('aria-label', /Current: include/); - await expect(fixable).toHaveAttribute('aria-label', /Current: exclude/); - }); -}); diff --git a/yarn.lock b/yarn.lock index 9a478c3e19d2..0030481b4add 100644 --- a/yarn.lock +++ b/yarn.lock @@ -233,17 +233,6 @@ __metadata: languageName: node linkType: hard -"@axe-core/playwright@npm:^4.7.3": - version: 4.7.3 - resolution: "@axe-core/playwright@npm:4.7.3" - dependencies: - axe-core: ^4.7.0 - peerDependencies: - playwright-core: ">= 1.0.0" - checksum: c913cf6a816af283fc733411013460656213cf6c0efffcc36db1fd2984ffac3d780efd0a9aabd3b41ce78e2a536fee9ba5436d19311f660067e4c3560677b115 - languageName: node - linkType: hard - "@babel/code-frame@npm:*, @babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.22.13, @babel/code-frame@npm:^7.22.5, @babel/code-frame@npm:^7.8.3": version: 7.22.13 resolution: "@babel/code-frame@npm:7.22.13" @@ -4526,22 +4515,6 @@ __metadata: languageName: node linkType: hard -"@playwright/test@npm:^1.36.0": - version: 1.36.2 - resolution: "@playwright/test@npm:1.36.2" - dependencies: - "@types/node": "*" - fsevents: 2.3.2 - playwright-core: 1.36.2 - dependenciesMeta: - fsevents: - optional: true - bin: - playwright: cli.js - checksum: 659304e0bbbafb2fa36395fbd8bd2c5db2b7791bbb55fa62409946ec7ec726cf8fff89f2b8a1a74fe831bf50a8780a37a5322a1251a6f7db2a9220a57ac408f0 - languageName: node - linkType: hard - "@polka/url@npm:^1.0.0-next.20": version: 1.0.0-next.21 resolution: "@polka/url@npm:1.0.0-next.21" @@ -6935,7 +6908,7 @@ __metadata: languageName: node linkType: hard -"axe-core@npm:^4.6.2, axe-core@npm:^4.7.0": +"axe-core@npm:^4.6.2": version: 4.7.2 resolution: "axe-core@npm:4.7.2" checksum: 5d86fa0f45213b0e54cbb5d713ce885c4a8fe3a72b92dd915a47aa396d6fd149c4a87fec53aa978511f6d941402256cfeb26f2db35129e370f25a453c688655a @@ -10991,7 +10964,7 @@ __metadata: languageName: node linkType: hard -"fsevents@npm:2.3.2, fsevents@npm:^2.3.2, fsevents@npm:~2.3.2": +"fsevents@npm:^2.3.2, fsevents@npm:~2.3.2": version: 2.3.2 resolution: "fsevents@npm:2.3.2" dependencies: @@ -11001,7 +10974,7 @@ __metadata: languageName: node linkType: hard -"fsevents@patch:fsevents@2.3.2#~builtin, fsevents@patch:fsevents@^2.3.2#~builtin, fsevents@patch:fsevents@~2.3.2#~builtin": +"fsevents@patch:fsevents@^2.3.2#~builtin, fsevents@patch:fsevents@~2.3.2#~builtin": version: 2.3.2 resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin::version=2.3.2&hash=df0bf1" dependencies: @@ -16342,15 +16315,6 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.36.2": - version: 1.36.2 - resolution: "playwright-core@npm:1.36.2" - bin: - playwright-core: cli.js - checksum: 2193ce802ef93c28b9b5e11a0b1d7b60778c686015659978d1cbf0eb9cda2cdc85ec5575b887c1346e9d161cc2805bf27638d76a2f7f857dffeae968e6ceffcd - languageName: node - linkType: hard - "pluralize@npm:^8.0.0": version: 8.0.0 resolution: "pluralize@npm:8.0.0" @@ -20773,7 +20737,6 @@ __metadata: version: 0.0.0-use.local resolution: "website@workspace:packages/website" dependencies: - "@axe-core/playwright": ^4.7.3 "@babel/runtime": ^7.22.6 "@docusaurus/core": ~2.4.1 "@docusaurus/module-type-aliases": ~2.4.1 @@ -20782,7 +20745,6 @@ __metadata: "@docusaurus/remark-plugin-npm2yarn": ~2.4.1 "@docusaurus/theme-common": ~2.4.1 "@mdx-js/react": 1.6.22 - "@playwright/test": ^1.36.0 "@types/react": "*" "@types/react-helmet": ^6.1.6 "@types/react-router-dom": ^5.3.3 From afee34c0a8d01595414c85af5018f1e219f1513d Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Wed, 11 Oct 2023 19:34:31 +0800 Subject: [PATCH 08/16] chore: use named import for `util` (#7669) * refactor: use named export for `util` * fix: revert isTypeFlagSet switch * chore: conflicts * chore: adding back comments * fix: conflicts --------- Co-authored-by: Josh Goldberg --- .../src/rules/adjacent-overload-signatures.ts | 16 +-- .../eslint-plugin/src/rules/array-type.ts | 6 +- .../eslint-plugin/src/rules/await-thenable.ts | 25 ++-- .../eslint-plugin/src/rules/ban-ts-comment.ts | 7 +- .../src/rules/ban-tslint-comment.ts | 4 +- packages/eslint-plugin/src/rules/ban-types.ts | 6 +- .../eslint-plugin/src/rules/block-spacing.ts | 14 ++- .../src/rules/class-literal-property-style.ts | 4 +- .../src/rules/class-methods-use-this.ts | 15 ++- .../eslint-plugin/src/rules/comma-dangle.ts | 16 ++- .../src/rules/consistent-type-assertions.ts | 25 ++-- .../src/rules/consistent-type-definitions.ts | 4 +- .../src/rules/consistent-type-exports.ts | 42 ++++--- .../src/rules/consistent-type-imports.ts | 114 ++++++++++-------- .../src/rules/enum-utils/shared.ts | 4 +- .../rules/explicit-function-return-type.ts | 4 +- .../rules/explicit-member-accessibility.ts | 8 +- .../rules/explicit-module-boundary-types.ts | 6 +- .../src/rules/func-call-spacing.ts | 18 ++- packages/eslint-plugin/src/rules/indent.ts | 12 +- .../eslint-plugin/src/rules/key-spacing.ts | 23 ++-- .../src/rules/keyword-spacing.ts | 18 +-- .../src/rules/lines-around-comment.ts | 28 +++-- .../src/rules/lines-between-class-members.ts | 14 ++- .../src/rules/member-delimiter-style.ts | 8 +- .../src/rules/member-ordering.ts | 17 ++- .../src/rules/method-signature-style.ts | 21 ++-- .../naming-convention-utils/parse-options.ts | 4 +- .../rules/naming-convention-utils/schema.ts | 17 ++- .../naming-convention-utils/validator.ts | 4 +- .../src/rules/naming-convention.ts | 15 ++- .../src/rules/no-array-constructor.ts | 6 +- .../src/rules/no-base-to-string.ts | 12 +- .../rules/no-confusing-non-null-assertion.ts | 4 +- .../src/rules/no-confusing-void-expression.ts | 41 ++++--- .../src/rules/no-dupe-class-members.ts | 12 +- .../src/rules/no-duplicate-enum-values.ts | 4 +- .../rules/no-duplicate-type-constituents.ts | 6 +- .../src/rules/no-dynamic-delete.ts | 4 +- .../src/rules/no-empty-function.ts | 14 ++- .../src/rules/no-empty-interface.ts | 6 +- .../src/rules/no-explicit-any.ts | 4 +- .../src/rules/no-extra-non-null-assertion.ts | 4 +- .../src/rules/no-extra-parens.ts | 58 ++++----- .../eslint-plugin/src/rules/no-extra-semi.ts | 12 +- .../src/rules/no-extraneous-class.ts | 4 +- .../src/rules/no-floating-promises.ts | 14 ++- .../src/rules/no-for-in-array.ts | 15 ++- .../src/rules/no-implied-eval.ts | 6 +- .../src/rules/no-import-type-side-effects.ts | 22 ++-- .../src/rules/no-inferrable-types.ts | 4 +- .../src/rules/no-invalid-void-type.ts | 4 +- .../eslint-plugin/src/rules/no-loop-func.ts | 12 +- .../src/rules/no-loss-of-precision.ts | 14 ++- .../src/rules/no-magic-numbers.ts | 14 ++- .../src/rules/no-meaningless-void-operator.ts | 7 +- .../eslint-plugin/src/rules/no-misused-new.ts | 4 +- .../src/rules/no-misused-promises.ts | 10 +- .../eslint-plugin/src/rules/no-mixed-enums.ts | 6 +- .../eslint-plugin/src/rules/no-namespace.ts | 6 +- ...no-non-null-asserted-nullish-coalescing.ts | 11 +- .../no-non-null-asserted-optional-chain.ts | 4 +- .../src/rules/no-non-null-assertion.ts | 8 +- .../eslint-plugin/src/rules/no-redeclare.ts | 6 +- .../rules/no-redundant-type-constituents.ts | 34 ++++-- .../src/rules/no-require-imports.ts | 4 +- packages/eslint-plugin/src/rules/no-shadow.ts | 4 +- .../eslint-plugin/src/rules/no-this-alias.ts | 4 +- .../src/rules/no-throw-literal.ts | 15 ++- .../eslint-plugin/src/rules/no-type-alias.ts | 4 +- .../no-unnecessary-boolean-literal-compare.ts | 8 +- .../src/rules/no-unnecessary-qualifier.ts | 6 +- .../rules/no-unnecessary-type-arguments.ts | 17 ++- .../rules/no-unnecessary-type-assertion.ts | 40 +++--- .../rules/no-unnecessary-type-constraint.ts | 4 +- .../src/rules/no-unsafe-argument.ts | 29 +++-- .../src/rules/no-unsafe-assignment.ts | 53 ++++---- .../eslint-plugin/src/rules/no-unsafe-call.ts | 21 ++-- .../rules/no-unsafe-declaration-merging.ts | 4 +- .../src/rules/no-unsafe-enum-comparison.ts | 10 +- .../src/rules/no-unsafe-member-access.ts | 21 ++-- .../src/rules/no-unsafe-return.ts | 48 +++++--- .../src/rules/no-unused-expressions.ts | 12 +- .../eslint-plugin/src/rules/no-unused-vars.ts | 24 ++-- .../src/rules/no-use-before-define.ts | 4 +- .../src/rules/no-useless-constructor.ts | 12 +- .../src/rules/no-useless-empty-export.ts | 4 +- .../src/rules/no-var-requires.ts | 4 +- .../non-nullable-type-assertion-style.ts | 17 ++- .../rules/padding-line-between-statements.ts | 28 +++-- .../src/rules/parameter-properties.ts | 4 +- .../src/rules/prefer-as-const.ts | 4 +- .../src/rules/prefer-enum-initializers.ts | 4 +- .../eslint-plugin/src/rules/prefer-for-of.ts | 4 +- .../src/rules/prefer-function-type.ts | 4 +- .../src/rules/prefer-namespace-keyword.ts | 4 +- .../src/rules/prefer-nullish-coalescing.ts | 37 ++++-- .../analyzeChain.ts | 41 ++++--- .../gatherLogicalOperands.ts | 6 +- .../src/rules/prefer-optional-chain.ts | 15 ++- .../rules/prefer-readonly-parameter-types.ts | 25 ++-- .../src/rules/prefer-readonly.ts | 7 +- .../src/rules/prefer-reduce-type-parameter.ts | 18 +-- .../src/rules/prefer-ts-expect-error.ts | 4 +- .../src/rules/promise-function-async.ts | 22 ++-- packages/eslint-plugin/src/rules/quotes.ts | 12 +- .../src/rules/require-array-sort-compare.ts | 23 ++-- .../eslint-plugin/src/rules/require-await.ts | 36 +++--- .../src/rules/restrict-plus-operands.ts | 24 ++-- .../rules/restrict-template-expressions.ts | 33 ++--- .../eslint-plugin/src/rules/return-await.ts | 21 ++-- packages/eslint-plugin/src/rules/semi.ts | 12 +- .../src/rules/sort-type-constituents.ts | 5 +- .../src/rules/space-before-blocks.ts | 14 ++- .../src/rules/space-before-function-paren.ts | 9 +- .../src/rules/space-infix-ops.ts | 14 ++- .../src/rules/strict-boolean-expressions.ts | 90 +++++++------- .../src/rules/triple-slash-reference.ts | 4 +- .../src/rules/type-annotation-spacing.ts | 4 +- packages/eslint-plugin/src/rules/typedef.ts | 4 +- .../eslint-plugin/src/rules/unbound-method.ts | 14 ++- .../src/rules/unified-signatures.ts | 11 +- .../tests/areOptionsValid.test.ts | 4 +- packages/eslint-plugin/tests/util.test.ts | 8 +- .../tests/util/getWrappedCode.test.ts | 14 ++- 125 files changed, 1079 insertions(+), 784 deletions(-) diff --git a/packages/eslint-plugin/src/rules/adjacent-overload-signatures.ts b/packages/eslint-plugin/src/rules/adjacent-overload-signatures.ts index 0534cc8ce0d1..8af3cee44af2 100644 --- a/packages/eslint-plugin/src/rules/adjacent-overload-signatures.ts +++ b/packages/eslint-plugin/src/rules/adjacent-overload-signatures.ts @@ -1,7 +1,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule, getNameFromMember, MemberNameType } from '../util'; type RuleNode = | TSESTree.BlockStatement @@ -15,7 +15,7 @@ type Member = | TSESTree.ProgramStatement | TSESTree.TypeElement; -export default util.createRule({ +export default createRule({ name: 'adjacent-overload-signatures', meta: { type: 'suggestion', @@ -36,7 +36,7 @@ export default util.createRule({ name: string; static: boolean; callSignature: boolean; - type: util.MemberNameType; + type: MemberNameType; } /** @@ -72,12 +72,12 @@ export default util.createRule({ name, static: isStatic, callSignature: false, - type: util.MemberNameType.Normal, + type: MemberNameType.Normal, }; } case AST_NODE_TYPES.TSMethodSignature: return { - ...util.getNameFromMember(member, sourceCode), + ...getNameFromMember(member, sourceCode), static: isStatic, callSignature: false, }; @@ -86,18 +86,18 @@ export default util.createRule({ name: 'call', static: isStatic, callSignature: true, - type: util.MemberNameType.Normal, + type: MemberNameType.Normal, }; case AST_NODE_TYPES.TSConstructSignatureDeclaration: return { name: 'new', static: isStatic, callSignature: false, - type: util.MemberNameType.Normal, + type: MemberNameType.Normal, }; case AST_NODE_TYPES.MethodDefinition: return { - ...util.getNameFromMember(member, sourceCode), + ...getNameFromMember(member, sourceCode), static: isStatic, callSignature: false, }; diff --git a/packages/eslint-plugin/src/rules/array-type.ts b/packages/eslint-plugin/src/rules/array-type.ts index cd4a1f89cb2f..bc45356ae4ab 100644 --- a/packages/eslint-plugin/src/rules/array-type.ts +++ b/packages/eslint-plugin/src/rules/array-type.ts @@ -1,7 +1,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule, isParenthesized } from '../util'; /** * Check whatever node can be considered as simple @@ -85,7 +85,7 @@ type MessageIds = | 'errorStringGeneric' | 'errorStringGenericSimple'; -export default util.createRule({ +export default createRule({ name: 'array-type', meta: { type: 'suggestion', @@ -254,7 +254,7 @@ export default util.createRule({ const parentParens = readonlyPrefix && node.parent?.type === AST_NODE_TYPES.TSArrayType && - !util.isParenthesized(node.parent.elementType, sourceCode); + !isParenthesized(node.parent.elementType, sourceCode); const start = `${parentParens ? '(' : ''}${readonlyPrefix}${ typeParens ? '(' : '' diff --git a/packages/eslint-plugin/src/rules/await-thenable.ts b/packages/eslint-plugin/src/rules/await-thenable.ts index f5932dd7f259..37b6ad1c6dd4 100644 --- a/packages/eslint-plugin/src/rules/await-thenable.ts +++ b/packages/eslint-plugin/src/rules/await-thenable.ts @@ -1,9 +1,17 @@ import type { TSESLint } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; -import * as util from '../util'; +import { + createRule, + getParserServices, + isAwaitKeyword, + isTypeAnyType, + isTypeUnknownType, + nullThrows, + NullThrowsReasons, +} from '../util'; -export default util.createRule({ +export default createRule({ name: 'await-thenable', meta: { docs: { @@ -22,13 +30,13 @@ export default util.createRule({ defaultOptions: [], create(context) { - const services = util.getParserServices(context); + const services = getParserServices(context); const checker = services.program.getTypeChecker(); return { AwaitExpression(node): void { const type = services.getTypeAtLocation(node.argument); - if (util.isTypeAnyType(type) || util.isTypeUnknownType(type)) { + if (isTypeAnyType(type) || isTypeUnknownType(type)) { return; } @@ -43,12 +51,9 @@ export default util.createRule({ messageId: 'removeAwait', fix(fixer): TSESLint.RuleFix { const sourceCode = context.getSourceCode(); - const awaitKeyword = util.nullThrows( - sourceCode.getFirstToken(node, util.isAwaitKeyword), - util.NullThrowsReasons.MissingToken( - 'await', - 'await expression', - ), + const awaitKeyword = nullThrows( + sourceCode.getFirstToken(node, isAwaitKeyword), + NullThrowsReasons.MissingToken('await', 'await expression'), ); return fixer.remove(awaitKeyword); diff --git a/packages/eslint-plugin/src/rules/ban-ts-comment.ts b/packages/eslint-plugin/src/rules/ban-ts-comment.ts index 7de0718bde6b..4f64e85f5b9c 100644 --- a/packages/eslint-plugin/src/rules/ban-ts-comment.ts +++ b/packages/eslint-plugin/src/rules/ban-ts-comment.ts @@ -1,6 +1,6 @@ import { AST_TOKEN_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule, getStringLength } from '../util'; type DirectiveConfig = | boolean @@ -22,7 +22,7 @@ type MessageIds = | 'tsDirectiveCommentDescriptionNotMatchPattern' | 'tsDirectiveCommentRequiresDescription'; -export default util.createRule<[Options], MessageIds>({ +export default createRule<[Options], MessageIds>({ name: 'ban-ts-comment', meta: { type: 'problem', @@ -146,8 +146,7 @@ export default util.createRule<[Options], MessageIds>({ } = options; const format = descriptionFormats.get(fullDirective); if ( - util.getStringLength(description.trim()) < - minimumDescriptionLength + getStringLength(description.trim()) < minimumDescriptionLength ) { context.report({ data: { directive, minimumDescriptionLength }, diff --git a/packages/eslint-plugin/src/rules/ban-tslint-comment.ts b/packages/eslint-plugin/src/rules/ban-tslint-comment.ts index 4453649b717e..4e3814245617 100644 --- a/packages/eslint-plugin/src/rules/ban-tslint-comment.ts +++ b/packages/eslint-plugin/src/rules/ban-tslint-comment.ts @@ -1,6 +1,6 @@ import { AST_TOKEN_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; // tslint regex // https://github.com/palantir/tslint/blob/95d9d958833fd9dc0002d18cbe34db20d0fbf437/src/enableDisableRules.ts#L32 @@ -15,7 +15,7 @@ const toText = ( ? ['//', text.trim()].join(' ') : ['/*', text.trim(), '*/'].join(' '); -export default util.createRule({ +export default createRule({ name: 'ban-tslint-comment', meta: { type: 'suggestion', diff --git a/packages/eslint-plugin/src/rules/ban-types.ts b/packages/eslint-plugin/src/rules/ban-types.ts index 8352eff2f2d6..7e81dd58cde9 100644 --- a/packages/eslint-plugin/src/rules/ban-types.ts +++ b/packages/eslint-plugin/src/rules/ban-types.ts @@ -1,7 +1,7 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule, objectReduceKey } from '../util'; type Types = Record< string, @@ -124,7 +124,7 @@ export const TYPE_KEYWORDS = { void: AST_NODE_TYPES.TSVoidKeyword, }; -export default util.createRule({ +export default createRule({ name: 'ban-types', meta: { type: 'suggestion', @@ -256,7 +256,7 @@ export default util.createRule({ }); } - const keywordSelectors = util.objectReduceKey( + const keywordSelectors = objectReduceKey( TYPE_KEYWORDS, (acc: TSESLint.RuleListener, keyword) => { if (bannedTypes.has(keyword)) { diff --git a/packages/eslint-plugin/src/rules/block-spacing.ts b/packages/eslint-plugin/src/rules/block-spacing.ts index 8141a979cf04..f66179002db9 100644 --- a/packages/eslint-plugin/src/rules/block-spacing.ts +++ b/packages/eslint-plugin/src/rules/block-spacing.ts @@ -1,15 +1,19 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_TOKEN_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import type { + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +} from '../util'; +import { createRule, isTokenOnSameLine } from '../util'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; const baseRule = getESLintCoreRule('block-spacing'); -export type Options = util.InferOptionsTypeFromRule; -export type MessageIds = util.InferMessageIdsTypeFromRule; +export type Options = InferOptionsTypeFromRule; +export type MessageIds = InferMessageIdsTypeFromRule; -export default util.createRule({ +export default createRule({ name: 'block-spacing', meta: { type: 'layout', @@ -58,7 +62,7 @@ export default util.createRule({ */ function isValid(left: TSESTree.Token, right: TSESTree.Token): boolean { return ( - !util.isTokenOnSameLine(left, right) || + !isTokenOnSameLine(left, right) || sourceCode.isSpaceBetween!(left, right) === always ); } diff --git a/packages/eslint-plugin/src/rules/class-literal-property-style.ts b/packages/eslint-plugin/src/rules/class-literal-property-style.ts index bd9e0895e719..d771d4bb273d 100644 --- a/packages/eslint-plugin/src/rules/class-literal-property-style.ts +++ b/packages/eslint-plugin/src/rules/class-literal-property-style.ts @@ -1,7 +1,7 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; type Options = ['fields' | 'getters']; type MessageIds = @@ -40,7 +40,7 @@ const isSupportedLiteral = ( return false; }; -export default util.createRule({ +export default createRule({ name: 'class-literal-property-style', meta: { type: 'problem', diff --git a/packages/eslint-plugin/src/rules/class-methods-use-this.ts b/packages/eslint-plugin/src/rules/class-methods-use-this.ts index 948aa4def5ba..3ed2667fe5a5 100644 --- a/packages/eslint-plugin/src/rules/class-methods-use-this.ts +++ b/packages/eslint-plugin/src/rules/class-methods-use-this.ts @@ -1,7 +1,12 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { + createRule, + getFunctionHeadLoc, + getFunctionNameWithKind, + getStaticStringValue, +} from '../util'; type Options = [ { @@ -13,7 +18,7 @@ type Options = [ ]; type MessageIds = 'missingThis'; -export default util.createRule({ +export default createRule({ name: 'class-methods-use-this', meta: { type: 'suggestion', @@ -164,7 +169,7 @@ export default util.createRule({ node.key.type === AST_NODE_TYPES.PrivateIdentifier ? '#' : ''; const name = node.key.type === AST_NODE_TYPES.Literal - ? util.getStaticStringValue(node.key) + ? getStaticStringValue(node.key) : node.key.name || ''; return !exceptMethods.has(hashIfNeeded + (name ?? '')); @@ -193,10 +198,10 @@ export default util.createRule({ if (isIncludedInstanceMethod(stackContext.member)) { context.report({ node, - loc: util.getFunctionHeadLoc(node, sourceCode), + loc: getFunctionHeadLoc(node, sourceCode), messageId: 'missingThis', data: { - name: util.getFunctionNameWithKind(node), + name: getFunctionNameWithKind(node), }, }); } diff --git a/packages/eslint-plugin/src/rules/comma-dangle.ts b/packages/eslint-plugin/src/rules/comma-dangle.ts index 125cb47a325d..5edc00499041 100644 --- a/packages/eslint-plugin/src/rules/comma-dangle.ts +++ b/packages/eslint-plugin/src/rules/comma-dangle.ts @@ -1,13 +1,17 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import type { + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +} from '../util'; +import { createRule, isCommaToken } from '../util'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; const baseRule = getESLintCoreRule('comma-dangle'); -export type Options = util.InferOptionsTypeFromRule; -export type MessageIds = util.InferMessageIdsTypeFromRule; +export type Options = InferOptionsTypeFromRule; +export type MessageIds = InferMessageIdsTypeFromRule; type Option = Options[0]; type NormalizedOptions = Required< @@ -38,7 +42,7 @@ function normalizeOptions(options: Option): NormalizedOptions { }; } -export default util.createRule({ +export default createRule({ name: 'comma-dangle', meta: { type: 'layout', @@ -135,7 +139,7 @@ export default util.createRule({ function forbidComma(node: TSESTree.Node): void { const last = getLastItem(node); const trailing = getTrailingToken(node); - if (last && trailing && util.isCommaToken(trailing)) { + if (last && trailing && isCommaToken(trailing)) { context.report({ node, messageId: 'unexpected', @@ -149,7 +153,7 @@ export default util.createRule({ function forceComma(node: TSESTree.Node): void { const last = getLastItem(node); const trailing = getTrailingToken(node); - if (last && trailing && !util.isCommaToken(trailing)) { + if (last && trailing && !isCommaToken(trailing)) { context.report({ node, messageId: 'missing', diff --git a/packages/eslint-plugin/src/rules/consistent-type-assertions.ts b/packages/eslint-plugin/src/rules/consistent-type-assertions.ts index d2e610255f17..0c3883f81809 100644 --- a/packages/eslint-plugin/src/rules/consistent-type-assertions.ts +++ b/packages/eslint-plugin/src/rules/consistent-type-assertions.ts @@ -2,7 +2,14 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as ts from 'typescript'; -import * as util from '../util'; +import { + createRule, + getOperatorPrecedence, + getParserServices, + isClosingParenToken, + isOpeningParenToken, + isParenthesized, +} from '../util'; import { getWrappedCode } from '../util/getWrappedCode'; // intentionally mirroring the options @@ -23,7 +30,7 @@ type OptUnion = }; export type Options = readonly [OptUnion]; -export default util.createRule({ +export default createRule({ name: 'consistent-type-assertions', meta: { type: 'suggestion', @@ -84,7 +91,7 @@ export default util.createRule({ ], create(context, [options]) { const sourceCode = context.getSourceCode(); - const parserServices = util.getParserServices(context, true); + const parserServices = getParserServices(context, true); function isConst(node: TSESTree.TypeNode): boolean { if (node.type !== AST_NODE_TYPES.TSTypeReference) { @@ -102,14 +109,14 @@ export default util.createRule({ let beforeCount = 0; let afterCount = 0; - if (util.isParenthesized(node, sourceCode)) { + if (isParenthesized(node, sourceCode)) { const bodyOpeningParen = sourceCode.getTokenBefore( node, - util.isOpeningParenToken, + isOpeningParenToken, )!; const bodyClosingParen = sourceCode.getTokenAfter( node, - util.isClosingParenToken, + isClosingParenToken, )!; beforeCount = node.range[0] - bodyOpeningParen.range[0]; @@ -151,11 +158,11 @@ export default util.createRule({ node.typeAnnotation, ); - const asPrecedence = util.getOperatorPrecedence( + const asPrecedence = getOperatorPrecedence( ts.SyntaxKind.AsExpression, ts.SyntaxKind.Unknown, ); - const parentPrecedence = util.getOperatorPrecedence( + const parentPrecedence = getOperatorPrecedence( tsNode.parent.kind, ts.isBinaryExpression(tsNode.parent) ? tsNode.parent.operatorToken.kind @@ -169,7 +176,7 @@ export default util.createRule({ const text = `${expressionCode} as ${typeAnnotationCode}`; return fixer.replaceText( node, - util.isParenthesized(node, sourceCode) + isParenthesized(node, sourceCode) ? text : getWrappedCode(text, asPrecedence, parentPrecedence), ); diff --git a/packages/eslint-plugin/src/rules/consistent-type-definitions.ts b/packages/eslint-plugin/src/rules/consistent-type-definitions.ts index b504081ee4a1..2a9acedd14a5 100644 --- a/packages/eslint-plugin/src/rules/consistent-type-definitions.ts +++ b/packages/eslint-plugin/src/rules/consistent-type-definitions.ts @@ -1,9 +1,9 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; -export default util.createRule({ +export default createRule({ name: 'consistent-type-definitions', meta: { type: 'suggestion', diff --git a/packages/eslint-plugin/src/rules/consistent-type-exports.ts b/packages/eslint-plugin/src/rules/consistent-type-exports.ts index 3c496ee63d61..36e27f91d73a 100644 --- a/packages/eslint-plugin/src/rules/consistent-type-exports.ts +++ b/packages/eslint-plugin/src/rules/consistent-type-exports.ts @@ -2,7 +2,15 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import { SymbolFlags } from 'typescript'; -import * as util from '../util'; +import { + createRule, + formatWordList, + getParserServices, + isClosingBraceToken, + isOpeningBraceToken, + nullThrows, + NullThrowsReasons, +} from '../util'; type Options = [ { @@ -29,7 +37,7 @@ type MessageIds = | 'singleExportIsType' | 'typeOverValue'; -export default util.createRule({ +export default createRule({ name: 'consistent-type-exports', meta: { type: 'suggestion', @@ -68,7 +76,7 @@ export default util.createRule({ create(context, [{ fixMixedExportsWithInlineTypeSpecifier }]) { const sourceCode = context.getSourceCode(); const sourceExportsMap: Record = {}; - const services = util.getParserServices(context); + const services = getParserServices(context); /** * Helper for identifying if an export specifier resolves to a @@ -194,7 +202,7 @@ export default util.createRule({ }, }); } else { - const exportNames = util.formatWordList(allExportNames); + const exportNames = formatWordList(allExportNames); context.report({ node: report.node, @@ -229,20 +237,20 @@ function* fixExportInsertType( sourceCode: Readonly, node: TSESTree.ExportNamedDeclaration, ): IterableIterator { - const exportToken = util.nullThrows( + const exportToken = nullThrows( sourceCode.getFirstToken(node), - util.NullThrowsReasons.MissingToken('export', node.type), + NullThrowsReasons.MissingToken('export', node.type), ); yield fixer.insertTextAfter(exportToken, ' type'); for (const specifier of node.specifiers) { if (specifier.exportKind === 'type') { - const kindToken = util.nullThrows( + const kindToken = nullThrows( sourceCode.getFirstToken(specifier), - util.NullThrowsReasons.MissingToken('export', specifier.type), + NullThrowsReasons.MissingToken('export', specifier.type), ); - const firstTokenAfter = util.nullThrows( + const firstTokenAfter = nullThrows( sourceCode.getTokenAfter(kindToken, { includeComments: true, }), @@ -270,22 +278,22 @@ function* fixSeparateNamedExports( const source = getSourceFromExport(node); const specifierNames = typeSpecifiers.map(getSpecifierText).join(', '); - const exportToken = util.nullThrows( + const exportToken = nullThrows( sourceCode.getFirstToken(node), - util.NullThrowsReasons.MissingToken('export', node.type), + NullThrowsReasons.MissingToken('export', node.type), ); // Filter the bad exports from the current line. const filteredSpecifierNames = valueSpecifiers .map(getSpecifierText) .join(', '); - const openToken = util.nullThrows( - sourceCode.getFirstToken(node, util.isOpeningBraceToken), - util.NullThrowsReasons.MissingToken('{', node.type), + const openToken = nullThrows( + sourceCode.getFirstToken(node, isOpeningBraceToken), + NullThrowsReasons.MissingToken('{', node.type), ); - const closeToken = util.nullThrows( - sourceCode.getLastToken(node, util.isClosingBraceToken), - util.NullThrowsReasons.MissingToken('}', node.type), + const closeToken = nullThrows( + sourceCode.getLastToken(node, isClosingBraceToken), + NullThrowsReasons.MissingToken('}', node.type), ); // Remove exports from the current line which we're going to re-insert. diff --git a/packages/eslint-plugin/src/rules/consistent-type-imports.ts b/packages/eslint-plugin/src/rules/consistent-type-imports.ts index 9aaa296a4b0c..a99a09e7bc1c 100644 --- a/packages/eslint-plugin/src/rules/consistent-type-imports.ts +++ b/packages/eslint-plugin/src/rules/consistent-type-imports.ts @@ -1,7 +1,17 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { + createRule, + formatWordList, + isClosingBraceToken, + isCommaToken, + isImportKeyword, + isOpeningBraceToken, + isTypeKeyword, + nullThrows, + NullThrowsReasons, +} from '../util'; type Prefer = 'no-type-imports' | 'type-imports'; type FixStyle = 'inline-type-imports' | 'separate-type-imports'; @@ -40,7 +50,7 @@ type MessageIds = | 'someImportsInDecoMeta' | 'typeOverValue' | 'valueOverType'; -export default util.createRule({ +export default createRule({ name: 'consistent-type-imports', meta: { type: 'suggestion', @@ -287,7 +297,7 @@ export default util.createRule({ messageId: MessageIds; data: Record; } => { - const typeImports = util.formatWordList(importNames); + const typeImports = formatWordList(importNames); if (importNames.length === 1) { if (isTypeImport) { @@ -428,24 +438,24 @@ export default util.createRule({ if (subsetNamedSpecifiers.length === allNamedSpecifiers.length) { // import Foo, {Type1, Type2} from 'foo' // import DefType, {Type1, Type2} from 'foo' - const openingBraceToken = util.nullThrows( + const openingBraceToken = nullThrows( sourceCode.getTokenBefore( subsetNamedSpecifiers[0], - util.isOpeningBraceToken, + isOpeningBraceToken, ), - util.NullThrowsReasons.MissingToken('{', node.type), + NullThrowsReasons.MissingToken('{', node.type), ); - const commaToken = util.nullThrows( - sourceCode.getTokenBefore(openingBraceToken, util.isCommaToken), - util.NullThrowsReasons.MissingToken(',', node.type), + const commaToken = nullThrows( + sourceCode.getTokenBefore(openingBraceToken, isCommaToken), + NullThrowsReasons.MissingToken(',', node.type), ); - const closingBraceToken = util.nullThrows( + const closingBraceToken = nullThrows( sourceCode.getFirstTokenBetween( openingBraceToken, node.source, - util.isClosingBraceToken, + isClosingBraceToken, ), - util.NullThrowsReasons.MissingToken('}', node.type), + NullThrowsReasons.MissingToken('}', node.type), ); // import DefType, {...} from 'foo' @@ -506,7 +516,7 @@ export default util.createRule({ const textRange: TSESTree.Range = [...removeRange]; const before = sourceCode.getTokenBefore(first)!; textRange[0] = before.range[1]; - if (util.isCommaToken(before)) { + if (isCommaToken(before)) { removeRange[0] = before.range[0]; } else { removeRange[0] = before.range[1]; @@ -517,7 +527,7 @@ export default util.createRule({ const after = sourceCode.getTokenAfter(last)!; textRange[1] = after.range[0]; if (isFirst || isLast) { - if (util.isCommaToken(after)) { + if (isCommaToken(after)) { removeRange[1] = after.range[1]; } } @@ -539,16 +549,16 @@ export default util.createRule({ target: TSESTree.ImportDeclaration, insertText: string, ): TSESLint.RuleFix { - const closingBraceToken = util.nullThrows( + const closingBraceToken = nullThrows( sourceCode.getFirstTokenBetween( sourceCode.getFirstToken(target)!, target.source, - util.isClosingBraceToken, + isClosingBraceToken, ), - util.NullThrowsReasons.MissingToken('}', target.type), + NullThrowsReasons.MissingToken('}', target.type), ); const before = sourceCode.getTokenBefore(closingBraceToken)!; - if (!util.isCommaToken(before) && !util.isOpeningBraceToken(before)) { + if (!isCommaToken(before) && !isOpeningBraceToken(before)) { insertText = `,${insertText}`; } return fixer.insertTextBefore(closingBraceToken, insertText); @@ -710,9 +720,9 @@ export default util.createRule({ // import Foo, * as Type from 'foo' // import DefType, * as Type from 'foo' // import DefType, * as Type from 'foo' - const commaToken = util.nullThrows( - sourceCode.getTokenBefore(namespaceSpecifier, util.isCommaToken), - util.NullThrowsReasons.MissingToken(',', node.type), + const commaToken = nullThrows( + sourceCode.getTokenBefore(namespaceSpecifier, isCommaToken), + NullThrowsReasons.MissingToken(',', node.type), ); // import Def, * as Ns from 'foo' @@ -735,17 +745,17 @@ export default util.createRule({ report.typeSpecifiers.includes(defaultSpecifier) ) { if (report.typeSpecifiers.length === node.specifiers.length) { - const importToken = util.nullThrows( - sourceCode.getFirstToken(node, util.isImportKeyword), - util.NullThrowsReasons.MissingToken('import', node.type), + const importToken = nullThrows( + sourceCode.getFirstToken(node, isImportKeyword), + NullThrowsReasons.MissingToken('import', node.type), ); // import type Type from 'foo' // ^^^^ insert yield fixer.insertTextAfter(importToken, ' type'); } else { - const commaToken = util.nullThrows( - sourceCode.getTokenAfter(defaultSpecifier, util.isCommaToken), - util.NullThrowsReasons.MissingToken(',', defaultSpecifier.type), + const commaToken = nullThrows( + sourceCode.getTokenAfter(defaultSpecifier, isCommaToken), + NullThrowsReasons.MissingToken(',', defaultSpecifier.type), ); // import Type , {...} from 'foo' // ^^^^^ pick @@ -758,9 +768,9 @@ export default util.createRule({ node.source, )};\n`, ); - const afterToken = util.nullThrows( + const afterToken = nullThrows( sourceCode.getTokenAfter(commaToken, { includeComments: true }), - util.NullThrowsReasons.MissingToken('any token', node.type), + NullThrowsReasons.MissingToken('any token', node.type), ); // import Type , {...} from 'foo' // ^^^^^^^ remove @@ -784,9 +794,9 @@ export default util.createRule({ ): IterableIterator { // import type Foo from 'foo' // ^^^^^ insert - const importToken = util.nullThrows( - sourceCode.getFirstToken(node, util.isImportKeyword), - util.NullThrowsReasons.MissingToken('import', node.type), + const importToken = nullThrows( + sourceCode.getFirstToken(node, isImportKeyword), + NullThrowsReasons.MissingToken('import', node.type), ); yield fixer.insertTextAfter(importToken, ' type'); @@ -795,21 +805,21 @@ export default util.createRule({ const openingBraceToken = sourceCode.getFirstTokenBetween( importToken, node.source, - util.isOpeningBraceToken, + isOpeningBraceToken, ); if (openingBraceToken) { // Only braces. e.g. import Foo, {} from 'foo' - const commaToken = util.nullThrows( - sourceCode.getTokenBefore(openingBraceToken, util.isCommaToken), - util.NullThrowsReasons.MissingToken(',', node.type), + const commaToken = nullThrows( + sourceCode.getTokenBefore(openingBraceToken, isCommaToken), + NullThrowsReasons.MissingToken(',', node.type), ); - const closingBraceToken = util.nullThrows( + const closingBraceToken = nullThrows( sourceCode.getFirstTokenBetween( openingBraceToken, node.source, - util.isClosingBraceToken, + isClosingBraceToken, ), - util.NullThrowsReasons.MissingToken('}', node.type), + NullThrowsReasons.MissingToken('}', node.type), ); // import type Foo, {} from 'foo' @@ -929,21 +939,21 @@ export default util.createRule({ ): IterableIterator { // import type Foo from 'foo' // ^^^^ remove - const importToken = util.nullThrows( - sourceCode.getFirstToken(node, util.isImportKeyword), - util.NullThrowsReasons.MissingToken('import', node.type), + const importToken = nullThrows( + sourceCode.getFirstToken(node, isImportKeyword), + NullThrowsReasons.MissingToken('import', node.type), ); - const typeToken = util.nullThrows( + const typeToken = nullThrows( sourceCode.getFirstTokenBetween( importToken, node.specifiers[0]?.local ?? node.source, - util.isTypeKeyword, + isTypeKeyword, ), - util.NullThrowsReasons.MissingToken('type', node.type), + NullThrowsReasons.MissingToken('type', node.type), ); - const afterToken = util.nullThrows( + const afterToken = nullThrows( sourceCode.getTokenAfter(typeToken, { includeComments: true }), - util.NullThrowsReasons.MissingToken('any token', node.type), + NullThrowsReasons.MissingToken('any token', node.type), ); yield fixer.removeRange([typeToken.range[0], afterToken.range[0]]); } @@ -954,13 +964,13 @@ export default util.createRule({ ): IterableIterator { // import { type Foo } from 'foo' // ^^^^ remove - const typeToken = util.nullThrows( - sourceCode.getFirstToken(node, util.isTypeKeyword), - util.NullThrowsReasons.MissingToken('type', node.type), + const typeToken = nullThrows( + sourceCode.getFirstToken(node, isTypeKeyword), + NullThrowsReasons.MissingToken('type', node.type), ); - const afterToken = util.nullThrows( + const afterToken = nullThrows( sourceCode.getTokenAfter(typeToken, { includeComments: true }), - util.NullThrowsReasons.MissingToken('any token', node.type), + NullThrowsReasons.MissingToken('any token', node.type), ); yield fixer.removeRange([typeToken.range[0], afterToken.range[0]]); } diff --git a/packages/eslint-plugin/src/rules/enum-utils/shared.ts b/packages/eslint-plugin/src/rules/enum-utils/shared.ts index e629d00e7be7..39fca8af9113 100644 --- a/packages/eslint-plugin/src/rules/enum-utils/shared.ts +++ b/packages/eslint-plugin/src/rules/enum-utils/shared.ts @@ -1,7 +1,7 @@ import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../../util'; +import { isTypeFlagSet } from '../../util'; /* * If passed an enum member, returns the type of the parent. Otherwise, @@ -35,6 +35,6 @@ export function getEnumTypes( ): ts.Type[] { return tsutils .unionTypeParts(type) - .filter(subType => util.isTypeFlagSet(subType, ts.TypeFlags.EnumLiteral)) + .filter(subType => isTypeFlagSet(subType, ts.TypeFlags.EnumLiteral)) .map(type => getBaseEnumType(typeChecker, type)); } diff --git a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts index e57465be8365..59b223912c3b 100644 --- a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts +++ b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts @@ -1,7 +1,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; import { ancestorHasReturnType, checkFunctionReturnType, @@ -22,7 +22,7 @@ type Options = [ ]; type MessageIds = 'missingReturnType'; -export default util.createRule({ +export default createRule({ name: 'explicit-function-return-type', meta: { type: 'problem', diff --git a/packages/eslint-plugin/src/rules/explicit-member-accessibility.ts b/packages/eslint-plugin/src/rules/explicit-member-accessibility.ts index d95a58dc281e..ff99eb77b4a8 100644 --- a/packages/eslint-plugin/src/rules/explicit-member-accessibility.ts +++ b/packages/eslint-plugin/src/rules/explicit-member-accessibility.ts @@ -1,7 +1,7 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule, getNameFromMember } from '../util'; type AccessibilityLevel = | 'explicit' // require an accessor (including public) @@ -27,7 +27,7 @@ type MessageIds = | 'missingAccessibility' | 'unwantedPublicAccessibility'; -export default util.createRule({ +export default createRule({ name: 'explicit-member-accessibility', meta: { hasSuggestions: true, @@ -135,7 +135,7 @@ export default util.createRule({ break; } - const { name: methodName } = util.getNameFromMember( + const { name: methodName } = getNameFromMember( methodDefinition, sourceCode, ); @@ -269,7 +269,7 @@ export default util.createRule({ const nodeType = 'class property'; - const { name: propertyName } = util.getNameFromMember( + const { name: propertyName } = getNameFromMember( propertyDefinition, sourceCode, ); diff --git a/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts b/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts index 1ac7e70bb9f8..d2cb5f5306f8 100644 --- a/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts +++ b/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts @@ -2,7 +2,7 @@ import { DefinitionType } from '@typescript-eslint/scope-manager'; import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule, isFunction } from '../util'; import type { FunctionExpression, FunctionNode, @@ -31,7 +31,7 @@ type MessageIds = | 'missingArgTypeUnnamed' | 'missingReturnType'; -export default util.createRule({ +export default createRule({ name: 'explicit-module-boundary-types', meta: { type: 'problem', @@ -277,7 +277,7 @@ export default util.createRule({ } if ( - !util.isFunction(current) || + !isFunction(current) || !doesImmediatelyReturnFunctionExpression(current) ) { return false; diff --git a/packages/eslint-plugin/src/rules/func-call-spacing.ts b/packages/eslint-plugin/src/rules/func-call-spacing.ts index b72c54951f92..95007fdcd3df 100644 --- a/packages/eslint-plugin/src/rules/func-call-spacing.ts +++ b/packages/eslint-plugin/src/rules/func-call-spacing.ts @@ -1,6 +1,12 @@ import type { TSESTree } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { + createRule, + isNotOptionalChainPunctuator, + isOpeningParenToken, + isOptionalCallExpression, + LINEBREAK_MATCHER, +} from '../util'; export type Options = [ 'always' | 'never', @@ -13,7 +19,7 @@ export type MessageIds = | 'unexpectedNewline' | 'unexpectedWhitespace'; -export default util.createRule({ +export default createRule({ name: 'func-call-spacing', meta: { type: 'layout', @@ -80,7 +86,7 @@ export default util.createRule({ function checkSpacing( node: TSESTree.CallExpression | TSESTree.NewExpression, ): void { - const isOptionalCall = util.isOptionalCallExpression(node); + const isOptionalCall = isOptionalCallExpression(node); const closingParenToken = sourceCode.getLastToken(node)!; const lastCalleeTokenWithoutPossibleParens = sourceCode.getLastToken( @@ -89,7 +95,7 @@ export default util.createRule({ const openingParenToken = sourceCode.getFirstTokenBetween( lastCalleeTokenWithoutPossibleParens, closingParenToken, - util.isOpeningParenToken, + isOpeningParenToken, ); if (!openingParenToken || openingParenToken.range[1] >= node.range[1]) { // new expression with no parens... @@ -97,7 +103,7 @@ export default util.createRule({ } const lastCalleeToken = sourceCode.getTokenBefore( openingParenToken, - util.isNotOptionalChainPunctuator, + isNotOptionalChainPunctuator, )!; const textBetweenTokens = text @@ -105,7 +111,7 @@ export default util.createRule({ .replace(/\/\*.*?\*\//gu, ''); const hasWhitespace = /\s/u.test(textBetweenTokens); const hasNewline = - hasWhitespace && util.LINEBREAK_MATCHER.test(textBetweenTokens); + hasWhitespace && LINEBREAK_MATCHER.test(textBetweenTokens); if (option === 'never') { if (hasWhitespace) { diff --git a/packages/eslint-plugin/src/rules/indent.ts b/packages/eslint-plugin/src/rules/indent.ts index adcf4152d3bc..ae8f6f60415d 100644 --- a/packages/eslint-plugin/src/rules/indent.ts +++ b/packages/eslint-plugin/src/rules/indent.ts @@ -8,13 +8,17 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import type { + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +} from '../util'; +import { createRule } from '../util'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; const baseRule = getESLintCoreRule('indent'); -type Options = util.InferOptionsTypeFromRule; -type MessageIds = util.InferMessageIdsTypeFromRule; +type Options = InferOptionsTypeFromRule; +type MessageIds = InferMessageIdsTypeFromRule; const KNOWN_NODES = new Set([ // Class properties aren't yet supported by eslint... @@ -84,7 +88,7 @@ const KNOWN_NODES = new Set([ AST_NODE_TYPES.Decorator, ]); -export default util.createRule({ +export default createRule({ name: 'indent', meta: { type: 'layout', diff --git a/packages/eslint-plugin/src/rules/key-spacing.ts b/packages/eslint-plugin/src/rules/key-spacing.ts index 20d7f577ecfb..707c9dc4431b 100644 --- a/packages/eslint-plugin/src/rules/key-spacing.ts +++ b/packages/eslint-plugin/src/rules/key-spacing.ts @@ -1,13 +1,22 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import type { + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +} from '../util'; +import { + createRule, + getStringLength, + isClosingBracketToken, + isColonToken, +} from '../util'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; const baseRule = getESLintCoreRule('key-spacing'); -export type Options = util.InferOptionsTypeFromRule; -export type MessageIds = util.InferMessageIdsTypeFromRule; +export type Options = InferOptionsTypeFromRule; +export type MessageIds = InferMessageIdsTypeFromRule; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const baseSchema = Array.isArray(baseRule.meta.schema) @@ -24,7 +33,7 @@ function at(arr: T[], position: number): T | undefined { return arr[position]; } -export default util.createRule({ +export default createRule({ name: 'key-spacing', meta: { type: 'layout', @@ -49,7 +58,7 @@ export default util.createRule({ */ function adjustedColumn(position: TSESTree.Position): number { const line = position.line - 1; // position.line is 1-indexed - return util.getStringLength( + return getStringLength( at(sourceCode.lines, line)!.slice(0, position.column), ); } @@ -59,7 +68,7 @@ export default util.createRule({ * until it finds the last token before a colon punctuator and returns it. */ function getLastTokenBeforeColon(node: TSESTree.Node): TSESTree.Token { - const colonToken = sourceCode.getTokenAfter(node, util.isColonToken)!; + const colonToken = sourceCode.getTokenAfter(node, isColonToken)!; return sourceCode.getTokenBefore(colonToken)!; } @@ -106,7 +115,7 @@ export default util.createRule({ 0, sourceCode.getTokenAfter( at(node.parameters, -1)!, - util.isClosingBracketToken, + isClosingBracketToken, )!.range[1] - node.range[0], ); } diff --git a/packages/eslint-plugin/src/rules/keyword-spacing.ts b/packages/eslint-plugin/src/rules/keyword-spacing.ts index 893c70db7674..50fbdc18d22b 100644 --- a/packages/eslint-plugin/src/rules/keyword-spacing.ts +++ b/packages/eslint-plugin/src/rules/keyword-spacing.ts @@ -2,19 +2,23 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/utils'; import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema'; -import * as util from '../util'; +import type { + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +} from '../util'; +import { createRule, deepMerge, nullThrows, NullThrowsReasons } from '../util'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; const baseRule = getESLintCoreRule('keyword-spacing'); -export type Options = util.InferOptionsTypeFromRule; -export type MessageIds = util.InferMessageIdsTypeFromRule; +export type Options = InferOptionsTypeFromRule; +export type MessageIds = InferMessageIdsTypeFromRule; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const baseSchema = Array.isArray(baseRule.meta.schema) ? baseRule.meta.schema[0] : baseRule.meta.schema; -const schema = util.deepMerge( +const schema = deepMerge( // eslint-disable-next-line @typescript-eslint/no-unsafe-argument -- https://github.com/microsoft/TypeScript/issues/17002 baseSchema, { @@ -29,7 +33,7 @@ const schema = util.deepMerge( }, ) as unknown as JSONSchema4; -export default util.createRule({ +export default createRule({ name: 'keyword-spacing', meta: { type: 'layout', @@ -50,12 +54,12 @@ export default util.createRule({ return { ...baseRules, TSAsExpression(node): void { - const asToken = util.nullThrows( + const asToken = nullThrows( sourceCode.getTokenAfter( node.expression, token => token.value === 'as', ), - util.NullThrowsReasons.MissingToken('as', node.type), + NullThrowsReasons.MissingToken('as', node.type), ); const oldTokenType = asToken.type; // as is a contextual keyword, so it's always reported as an Identifier diff --git a/packages/eslint-plugin/src/rules/lines-around-comment.ts b/packages/eslint-plugin/src/rules/lines-around-comment.ts index f7cdef33b2e4..1855c8ae5b8c 100644 --- a/packages/eslint-plugin/src/rules/lines-around-comment.ts +++ b/packages/eslint-plugin/src/rules/lines-around-comment.ts @@ -1,13 +1,17 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import type { + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +} from '../util'; +import { createRule, isCommentToken, isTokenOnSameLine } from '../util'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; const baseRule = getESLintCoreRule('lines-around-comment'); -export type Options = util.InferOptionsTypeFromRule; -export type MessageIds = util.InferMessageIdsTypeFromRule; +export type Options = InferOptionsTypeFromRule; +export type MessageIds = InferMessageIdsTypeFromRule; const COMMENTS_IGNORE_PATTERN = /^\s*(?:eslint|jshint\s+|jslint\s+|istanbul\s+|globals?\s+|exported\s+|jscs)/u; @@ -42,7 +46,7 @@ function getCommentLineNums(comments: TSESTree.Comment[]): number[] { return lines; } -export default util.createRule({ +export default createRule({ name: 'lines-around-comment', meta: { type: 'layout', @@ -162,9 +166,9 @@ export default util.createRule({ currentToken = sourceCode.getTokenBefore(currentToken, { includeComments: true, }); - } while (currentToken && util.isCommentToken(currentToken)); + } while (currentToken && isCommentToken(currentToken)); - if (currentToken && util.isTokenOnSameLine(currentToken, token)) { + if (currentToken && isTokenOnSameLine(currentToken, token)) { return true; } @@ -173,9 +177,9 @@ export default util.createRule({ currentToken = sourceCode.getTokenAfter(currentToken, { includeComments: true, }); - } while (currentToken && util.isCommentToken(currentToken)); + } while (currentToken && isCommentToken(currentToken)); - if (currentToken && util.isTokenOnSameLine(token, currentToken)) { + if (currentToken && isTokenOnSameLine(token, currentToken)) { return true; } @@ -352,8 +356,8 @@ export default util.createRule({ before && !commentAndEmptyLines.has(prevLineNum) && !( - util.isCommentToken(previousTokenOrComment!) && - util.isTokenOnSameLine(previousTokenOrComment, token) + isCommentToken(previousTokenOrComment!) && + isTokenOnSameLine(previousTokenOrComment, token) ) ) { const lineStart = token.range[0] - token.loc.start.column; @@ -374,8 +378,8 @@ export default util.createRule({ after && !commentAndEmptyLines.has(nextLineNum) && !( - util.isCommentToken(nextTokenOrComment!) && - util.isTokenOnSameLine(token, nextTokenOrComment) + isCommentToken(nextTokenOrComment!) && + isTokenOnSameLine(token, nextTokenOrComment) ) ) { context.report({ diff --git a/packages/eslint-plugin/src/rules/lines-between-class-members.ts b/packages/eslint-plugin/src/rules/lines-between-class-members.ts index e88e42d477af..2383142387a7 100644 --- a/packages/eslint-plugin/src/rules/lines-between-class-members.ts +++ b/packages/eslint-plugin/src/rules/lines-between-class-members.ts @@ -2,16 +2,20 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema'; -import * as util from '../util'; +import type { + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +} from '../util'; +import { createRule, deepMerge } from '../util'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; const baseRule = getESLintCoreRule('lines-between-class-members'); -type Options = util.InferOptionsTypeFromRule; -type MessageIds = util.InferMessageIdsTypeFromRule; +type Options = InferOptionsTypeFromRule; +type MessageIds = InferMessageIdsTypeFromRule; const schema = Object.values( - util.deepMerge( + deepMerge( { ...baseRule.meta.schema }, { 1: { @@ -26,7 +30,7 @@ const schema = Object.values( ), ) as JSONSchema4[]; -export default util.createRule({ +export default createRule({ name: 'lines-between-class-members', meta: { type: 'layout', diff --git a/packages/eslint-plugin/src/rules/member-delimiter-style.ts b/packages/eslint-plugin/src/rules/member-delimiter-style.ts index e0055a385e17..2a0880cd21fb 100644 --- a/packages/eslint-plugin/src/rules/member-delimiter-style.ts +++ b/packages/eslint-plugin/src/rules/member-delimiter-style.ts @@ -2,7 +2,7 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema'; -import * as util from '../util'; +import { createRule, deepMerge } from '../util'; type Delimiter = 'comma' | 'none' | 'semi'; // need type's implicit index sig for deepMerge @@ -132,7 +132,7 @@ const BASE_SCHEMA: JSONSchema4 = { additionalProperties: false, }; -export default util.createRule({ +export default createRule({ name: 'member-delimiter-style', meta: { type: 'layout', @@ -205,11 +205,11 @@ export default util.createRule({ // use the base options as the defaults for the cases const baseOptions = options; const overrides = baseOptions.overrides ?? {}; - const interfaceOptions: BaseOptions = util.deepMerge( + const interfaceOptions: BaseOptions = deepMerge( baseOptions, overrides.interface, ); - const typeLiteralOptions: BaseOptions = util.deepMerge( + const typeLiteralOptions: BaseOptions = deepMerge( baseOptions, overrides.typeLiteral, ); diff --git a/packages/eslint-plugin/src/rules/member-ordering.ts b/packages/eslint-plugin/src/rules/member-ordering.ts index f7ad60c58feb..84d34d4c596c 100644 --- a/packages/eslint-plugin/src/rules/member-ordering.ts +++ b/packages/eslint-plugin/src/rules/member-ordering.ts @@ -2,7 +2,12 @@ import type { JSONSchema, TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import naturalCompare from 'natural-compare'; -import * as util from '../util'; +import { + createRule, + getNameFromIndexSignature, + getNameFromMember, + MemberNameType, +} from '../util'; export type MessageIds = | 'incorrectGroupOrder' @@ -380,12 +385,12 @@ function getMemberRawName( | TSESTree.TSPropertySignature, sourceCode: TSESLint.SourceCode, ): string { - const { name, type } = util.getNameFromMember(member, sourceCode); + const { name, type } = getNameFromMember(member, sourceCode); - if (type === util.MemberNameType.Quoted) { + if (type === MemberNameType.Quoted) { return name.slice(1, -1); } - if (type === util.MemberNameType.Private) { + if (type === MemberNameType.Private) { return name.slice(1); } return name; @@ -417,7 +422,7 @@ function getMemberName( case AST_NODE_TYPES.TSCallSignatureDeclaration: return 'call'; case AST_NODE_TYPES.TSIndexSignature: - return util.getNameFromIndexSignature(node); + return getNameFromIndexSignature(node); case AST_NODE_TYPES.StaticBlock: return 'static block'; default: @@ -611,7 +616,7 @@ function getLowestRank( return lowestRanks.map(rank => rank.replace(/-/g, ' ')).join(', '); } -export default util.createRule({ +export default createRule({ name: 'member-ordering', meta: { type: 'suggestion', diff --git a/packages/eslint-plugin/src/rules/method-signature-style.ts b/packages/eslint-plugin/src/rules/method-signature-style.ts index ee8ea18ebf83..20a56b54ecbe 100644 --- a/packages/eslint-plugin/src/rules/method-signature-style.ts +++ b/packages/eslint-plugin/src/rules/method-signature-style.ts @@ -1,12 +1,19 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { + createRule, + isClosingParenToken, + isCommaToken, + isOpeningParenToken, + isSemicolonToken, + nullThrows, +} from '../util'; export type Options = [('method' | 'property')?]; export type MessageIds = 'errorMethod' | 'errorProperty'; -export default util.createRule({ +export default createRule({ name: 'method-signature-style', meta: { type: 'suggestion', @@ -53,14 +60,14 @@ export default util.createRule({ ): string { let params = '()'; if (node.params.length > 0) { - const openingParen = util.nullThrows( - sourceCode.getTokenBefore(node.params[0], util.isOpeningParenToken), + const openingParen = nullThrows( + sourceCode.getTokenBefore(node.params[0], isOpeningParenToken), 'Missing opening paren before first parameter', ); - const closingParen = util.nullThrows( + const closingParen = nullThrows( sourceCode.getTokenAfter( node.params[node.params.length - 1], - util.isClosingParenToken, + isClosingParenToken, ), 'Missing closing paren after last parameter', ); @@ -91,7 +98,7 @@ export default util.createRule({ const lastToken = sourceCode.getLastToken(node); if ( lastToken && - (util.isSemicolonToken(lastToken) || util.isCommaToken(lastToken)) + (isSemicolonToken(lastToken) || isCommaToken(lastToken)) ) { return lastToken.value; } diff --git a/packages/eslint-plugin/src/rules/naming-convention-utils/parse-options.ts b/packages/eslint-plugin/src/rules/naming-convention-utils/parse-options.ts index 945777dd7fbd..885c25a8035f 100644 --- a/packages/eslint-plugin/src/rules/naming-convention-utils/parse-options.ts +++ b/packages/eslint-plugin/src/rules/naming-convention-utils/parse-options.ts @@ -1,4 +1,4 @@ -import * as util from '../../util'; +import { getEnumNames } from '../../util'; import { MetaSelectors, Modifiers, @@ -84,7 +84,7 @@ function parseOptions(context: Context): ParsedOptions { .map(opt => normalizeOption(opt)) .reduce((acc, val) => acc.concat(val), []); - const result = util.getEnumNames(Selectors).reduce((acc, k) => { + const result = getEnumNames(Selectors).reduce((acc, k) => { acc[k] = createValidator(k, context, normalizedOptions); return acc; }, {} as ParsedOptions); diff --git a/packages/eslint-plugin/src/rules/naming-convention-utils/schema.ts b/packages/eslint-plugin/src/rules/naming-convention-utils/schema.ts index 2cb6d9fed62b..3e44a0c34954 100644 --- a/packages/eslint-plugin/src/rules/naming-convention-utils/schema.ts +++ b/packages/eslint-plugin/src/rules/naming-convention-utils/schema.ts @@ -1,6 +1,6 @@ import type { JSONSchema } from '@typescript-eslint/utils'; -import * as util from '../../util'; +import { getEnumNames } from '../../util'; import type { IndividualAndMetaSelectorsString, ModifiersString, @@ -18,15 +18,15 @@ const $DEFS: Record = { // enums underscoreOptions: { type: 'string', - enum: util.getEnumNames(UnderscoreOptions), + enum: getEnumNames(UnderscoreOptions), }, predefinedFormats: { type: 'string', - enum: util.getEnumNames(PredefinedFormats), + enum: getEnumNames(PredefinedFormats), }, typeModifiers: { type: 'string', - enum: util.getEnumNames(TypeModifiers), + enum: getEnumNames(TypeModifiers), }, // repeated types @@ -160,10 +160,7 @@ function selectorsSchema(): JSONSchema.JSONSchema4 { type: 'array', items: { type: 'string', - enum: [ - ...util.getEnumNames(MetaSelectors), - ...util.getEnumNames(Selectors), - ], + enum: [...getEnumNames(MetaSelectors), ...getEnumNames(Selectors)], }, additionalItems: false, }, @@ -171,7 +168,7 @@ function selectorsSchema(): JSONSchema.JSONSchema4 { type: 'array', items: { type: 'string', - enum: util.getEnumNames(Modifiers), + enum: getEnumNames(Modifiers), }, additionalItems: false, }, @@ -195,7 +192,7 @@ const SCHEMA: JSONSchema.JSONSchema4 = { items: { oneOf: [ selectorsSchema(), - ...selectorSchema('default', false, util.getEnumNames(Modifiers)), + ...selectorSchema('default', false, getEnumNames(Modifiers)), ...selectorSchema('variableLike', false, ['unused', 'async']), ...selectorSchema('variable', true, [ diff --git a/packages/eslint-plugin/src/rules/naming-convention-utils/validator.ts b/packages/eslint-plugin/src/rules/naming-convention-utils/validator.ts index 4c80a167a0f7..d7ce337b1a11 100644 --- a/packages/eslint-plugin/src/rules/naming-convention-utils/validator.ts +++ b/packages/eslint-plugin/src/rules/naming-convention-utils/validator.ts @@ -2,7 +2,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import type * as ts from 'typescript'; -import * as util from '../../util'; +import { getParserServices } from '../../util'; import type { SelectorsString } from './enums'; import { MetaSelectors, @@ -435,7 +435,7 @@ function isCorrectType( return true; } - const services = util.getParserServices(context); + const services = getParserServices(context); const checker = services.program.getTypeChecker(); const type = services .getTypeAtLocation(node) diff --git a/packages/eslint-plugin/src/rules/naming-convention.ts b/packages/eslint-plugin/src/rules/naming-convention.ts index d3e52d377cf2..dd287ccadd1c 100644 --- a/packages/eslint-plugin/src/rules/naming-convention.ts +++ b/packages/eslint-plugin/src/rules/naming-convention.ts @@ -3,7 +3,12 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES, TSESLint } from '@typescript-eslint/utils'; import type { ScriptTarget } from 'typescript'; -import * as util from '../util'; +import { + collectUnusedVariables, + createRule, + getParserServices, + requiresQuoting as _requiresQuoting, +} from '../util'; import type { Context, Selector, @@ -47,7 +52,7 @@ const defaultCamelCaseAllTheThingsConfig: Options = [ }, ]; -export default util.createRule({ +export default createRule({ name: 'naming-convention', meta: { docs: { @@ -90,7 +95,7 @@ export default util.createRule({ const validators = parseOptions(context); const compilerOptions = - util.getParserServices(context, true).program?.getCompilerOptions() ?? {}; + getParserServices(context, true).program?.getCompilerOptions() ?? {}; function handleMember( validator: ValidatorFunction, node: @@ -150,7 +155,7 @@ export default util.createRule({ return modifiers; } - const unusedVariables = util.collectUnusedVariables(context); + const unusedVariables = collectUnusedVariables(context); function isUnused( name: string, initialScope: TSESLint.Scope.Scope | null = context.getScope(), @@ -719,7 +724,7 @@ function requiresQuoting( node.type === AST_NODE_TYPES.PrivateIdentifier ? node.name : `${node.value}`; - return util.requiresQuoting(name, target); + return _requiresQuoting(name, target); } export { MessageIds, Options }; diff --git a/packages/eslint-plugin/src/rules/no-array-constructor.ts b/packages/eslint-plugin/src/rules/no-array-constructor.ts index fc71f275d7c3..52fbf7ee0252 100644 --- a/packages/eslint-plugin/src/rules/no-array-constructor.ts +++ b/packages/eslint-plugin/src/rules/no-array-constructor.ts @@ -1,9 +1,9 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule, isOptionalCallExpression } from '../util'; -export default util.createRule({ +export default createRule({ name: 'no-array-constructor', meta: { type: 'suggestion', @@ -32,7 +32,7 @@ export default util.createRule({ node.callee.type === AST_NODE_TYPES.Identifier && node.callee.name === 'Array' && !node.typeArguments && - !util.isOptionalCallExpression(node) + !isOptionalCallExpression(node) ) { context.report({ node, diff --git a/packages/eslint-plugin/src/rules/no-base-to-string.ts b/packages/eslint-plugin/src/rules/no-base-to-string.ts index 9d74c87117c5..eff3753b16c6 100644 --- a/packages/eslint-plugin/src/rules/no-base-to-string.ts +++ b/packages/eslint-plugin/src/rules/no-base-to-string.ts @@ -2,7 +2,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as ts from 'typescript'; -import * as util from '../util'; +import { createRule, getParserServices, getTypeName } from '../util'; enum Usefulness { Always = 'always', @@ -17,7 +17,7 @@ type Options = [ ]; type MessageIds = 'baseToString'; -export default util.createRule({ +export default createRule({ name: 'no-base-to-string', meta: { docs: { @@ -52,7 +52,7 @@ export default util.createRule({ }, ], create(context, [option]) { - const services = util.getParserServices(context); + const services = getParserServices(context); const checker = services.program.getTypeChecker(); const ignoredTypeNames = option.ignoredTypeNames ?? []; @@ -93,7 +93,7 @@ export default util.createRule({ return Usefulness.Always; } - if (ignoredTypeNames.includes(util.getTypeName(checker, type))) { + if (ignoredTypeNames.includes(getTypeName(checker, type))) { return Usefulness.Always; } @@ -155,10 +155,10 @@ export default util.createRule({ const leftType = services.getTypeAtLocation(node.left); const rightType = services.getTypeAtLocation(node.right); - if (util.getTypeName(checker, leftType) === 'string') { + if (getTypeName(checker, leftType) === 'string') { checkExpression(node.right, rightType); } else if ( - util.getTypeName(checker, rightType) === 'string' && + getTypeName(checker, rightType) === 'string' && node.left.type !== AST_NODE_TYPES.PrivateIdentifier ) { checkExpression(node.left, leftType); diff --git a/packages/eslint-plugin/src/rules/no-confusing-non-null-assertion.ts b/packages/eslint-plugin/src/rules/no-confusing-non-null-assertion.ts index 5e91950ed202..7b42603f2ba6 100644 --- a/packages/eslint-plugin/src/rules/no-confusing-non-null-assertion.ts +++ b/packages/eslint-plugin/src/rules/no-confusing-non-null-assertion.ts @@ -1,9 +1,9 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; -export default util.createRule({ +export default createRule({ name: 'no-confusing-non-null-assertion', meta: { type: 'problem', diff --git a/packages/eslint-plugin/src/rules/no-confusing-void-expression.ts b/packages/eslint-plugin/src/rules/no-confusing-void-expression.ts index 66ac9e28c512..4a41a66a4922 100644 --- a/packages/eslint-plugin/src/rules/no-confusing-void-expression.ts +++ b/packages/eslint-plugin/src/rules/no-confusing-void-expression.ts @@ -3,7 +3,16 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../util'; +import { + createRule, + getConstrainedTypeAtLocation, + getParserServices, + isClosingParenToken, + isOpeningParenToken, + isParenthesized, + nullThrows, + NullThrowsReasons, +} from '../util'; export type Options = [ { @@ -22,7 +31,7 @@ export type MessageId = | 'invalidVoidExprWrapVoid' | 'voidExprWrapVoid'; -export default util.createRule({ +export default createRule({ name: 'no-confusing-void-expression', meta: { docs: { @@ -80,8 +89,8 @@ export default util.createRule({ | TSESTree.CallExpression | TSESTree.TaggedTemplateExpression, ): void { - const services = util.getParserServices(context); - const type = util.getConstrainedTypeAtLocation(services, node); + const services = getParserServices(context); + const type = getConstrainedTypeAtLocation(services, node); if (!tsutils.isTypeFlagSet(type, ts.TypeFlags.VoidLike)) { // not a void expression return; @@ -121,14 +130,14 @@ export default util.createRule({ const arrowBody = arrowFunction.body; const arrowBodyText = sourceCode.getText(arrowBody); const newArrowBodyText = `{ ${arrowBodyText}; }`; - if (util.isParenthesized(arrowBody, sourceCode)) { + if (isParenthesized(arrowBody, sourceCode)) { const bodyOpeningParen = sourceCode.getTokenBefore( arrowBody, - util.isOpeningParenToken, + isOpeningParenToken, )!; const bodyClosingParen = sourceCode.getTokenAfter( arrowBody, - util.isClosingParenToken, + isClosingParenToken, )!; return fixer.replaceTextRange( [bodyOpeningParen.range[0], bodyClosingParen.range[1]], @@ -220,10 +229,7 @@ export default util.createRule({ * @returns Invalid ancestor node if it was found. `null` otherwise. */ function findInvalidAncestor(node: TSESTree.Node): TSESTree.Node | null { - const parent = util.nullThrows( - node.parent, - util.NullThrowsReasons.MissingParent, - ); + const parent = nullThrows(node.parent, NullThrowsReasons.MissingParent); if (parent.type === AST_NODE_TYPES.SequenceExpression) { if (node !== parent.expressions[parent.expressions.length - 1]) { return null; @@ -282,19 +288,16 @@ export default util.createRule({ /** Checks whether the return statement is the last statement in a function body. */ function isFinalReturn(node: TSESTree.ReturnStatement): boolean { // the parent must be a block - const block = util.nullThrows( - node.parent, - util.NullThrowsReasons.MissingParent, - ); + const block = nullThrows(node.parent, NullThrowsReasons.MissingParent); if (block.type !== AST_NODE_TYPES.BlockStatement) { // e.g. `if (cond) return;` (not in a block) return false; } // the block's parent must be a function - const blockParent = util.nullThrows( + const blockParent = nullThrows( block.parent, - util.NullThrowsReasons.MissingParent, + NullThrowsReasons.MissingParent, ); if ( ![ @@ -327,9 +330,9 @@ export default util.createRule({ node: TSESTree.Expression, sourceCode: Readonly, ): boolean { - const startToken = util.nullThrows( + const startToken = nullThrows( sourceCode.getFirstToken(node), - util.NullThrowsReasons.MissingToken('first token', node.type), + NullThrowsReasons.MissingToken('first token', node.type), ); return ['(', '[', '`'].includes(startToken.value); diff --git a/packages/eslint-plugin/src/rules/no-dupe-class-members.ts b/packages/eslint-plugin/src/rules/no-dupe-class-members.ts index 95689cae513c..09c734a75585 100644 --- a/packages/eslint-plugin/src/rules/no-dupe-class-members.ts +++ b/packages/eslint-plugin/src/rules/no-dupe-class-members.ts @@ -1,15 +1,19 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import type { + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +} from '../util'; +import { createRule } from '../util'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; const baseRule = getESLintCoreRule('no-dupe-class-members'); -type Options = util.InferOptionsTypeFromRule; -type MessageIds = util.InferMessageIdsTypeFromRule; +type Options = InferOptionsTypeFromRule; +type MessageIds = InferMessageIdsTypeFromRule; -export default util.createRule({ +export default createRule({ name: 'no-dupe-class-members', meta: { type: 'problem', diff --git a/packages/eslint-plugin/src/rules/no-duplicate-enum-values.ts b/packages/eslint-plugin/src/rules/no-duplicate-enum-values.ts index 8aeb1c4200b3..f5a58ce14f12 100644 --- a/packages/eslint-plugin/src/rules/no-duplicate-enum-values.ts +++ b/packages/eslint-plugin/src/rules/no-duplicate-enum-values.ts @@ -1,9 +1,9 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; -export default util.createRule({ +export default createRule({ name: 'no-duplicate-enum-values', meta: { type: 'problem', diff --git a/packages/eslint-plugin/src/rules/no-duplicate-type-constituents.ts b/packages/eslint-plugin/src/rules/no-duplicate-type-constituents.ts index c6e31acf5864..316259a064a5 100644 --- a/packages/eslint-plugin/src/rules/no-duplicate-type-constituents.ts +++ b/packages/eslint-plugin/src/rules/no-duplicate-type-constituents.ts @@ -2,7 +2,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import type { Type } from 'typescript'; -import * as util from '../util'; +import { createRule, getParserServices } from '../util'; export type Options = [ { @@ -66,7 +66,7 @@ const isSameAstNode = (actualNode: unknown, expectedNode: unknown): boolean => { return false; }; -export default util.createRule({ +export default createRule({ name: 'no-duplicate-type-constituents', meta: { type: 'suggestion', @@ -102,7 +102,7 @@ export default util.createRule({ }, ], create(context, [{ ignoreIntersections, ignoreUnions }]) { - const parserServices = util.getParserServices(context); + const parserServices = getParserServices(context); const checker = parserServices.program.getTypeChecker(); function checkDuplicate( diff --git a/packages/eslint-plugin/src/rules/no-dynamic-delete.ts b/packages/eslint-plugin/src/rules/no-dynamic-delete.ts index 0d1127f8a923..cf113350701b 100644 --- a/packages/eslint-plugin/src/rules/no-dynamic-delete.ts +++ b/packages/eslint-plugin/src/rules/no-dynamic-delete.ts @@ -2,9 +2,9 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; -import * as util from '../util'; +import { createRule } from '../util'; -export default util.createRule({ +export default createRule({ name: 'no-dynamic-delete', meta: { docs: { diff --git a/packages/eslint-plugin/src/rules/no-empty-function.ts b/packages/eslint-plugin/src/rules/no-empty-function.ts index e77981eab301..363b393e9d27 100644 --- a/packages/eslint-plugin/src/rules/no-empty-function.ts +++ b/packages/eslint-plugin/src/rules/no-empty-function.ts @@ -2,15 +2,19 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema'; -import * as util from '../util'; +import type { + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +} from '../util'; +import { createRule, deepMerge } from '../util'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; const baseRule = getESLintCoreRule('no-empty-function'); -type Options = util.InferOptionsTypeFromRule; -type MessageIds = util.InferMessageIdsTypeFromRule; +type Options = InferOptionsTypeFromRule; +type MessageIds = InferMessageIdsTypeFromRule; -const schema = util.deepMerge( +const schema = deepMerge( // eslint-disable-next-line @typescript-eslint/no-unsafe-argument -- https://github.com/microsoft/TypeScript/issues/17002 Array.isArray(baseRule.meta.schema) ? baseRule.meta.schema[0] @@ -42,7 +46,7 @@ const schema = util.deepMerge( }, ) as unknown as JSONSchema4; -export default util.createRule({ +export default createRule({ name: 'no-empty-function', meta: { type: 'suggestion', diff --git a/packages/eslint-plugin/src/rules/no-empty-interface.ts b/packages/eslint-plugin/src/rules/no-empty-interface.ts index 12499f3b95c6..2ca3a27fdf28 100644 --- a/packages/eslint-plugin/src/rules/no-empty-interface.ts +++ b/packages/eslint-plugin/src/rules/no-empty-interface.ts @@ -2,7 +2,7 @@ import { ScopeType } from '@typescript-eslint/scope-manager'; import type { TSESLint } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule, isDefinitionFile } from '../util'; type Options = [ { @@ -11,7 +11,7 @@ type Options = [ ]; type MessageIds = 'noEmpty' | 'noEmptyWithSuper'; -export default util.createRule({ +export default createRule({ name: 'no-empty-interface', meta: { type: 'suggestion', @@ -84,7 +84,7 @@ export default util.createRule({ ); const isInAmbientDeclaration = !!( - util.isDefinitionFile(filename) && + isDefinitionFile(filename) && scope.type === ScopeType.tsModule && scope.block.declare ); diff --git a/packages/eslint-plugin/src/rules/no-explicit-any.ts b/packages/eslint-plugin/src/rules/no-explicit-any.ts index fd2ddeefbe2b..ccf4cf47fb0f 100644 --- a/packages/eslint-plugin/src/rules/no-explicit-any.ts +++ b/packages/eslint-plugin/src/rules/no-explicit-any.ts @@ -1,7 +1,7 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; export type Options = [ { @@ -11,7 +11,7 @@ export type Options = [ ]; export type MessageIds = 'suggestNever' | 'suggestUnknown' | 'unexpectedAny'; -export default util.createRule({ +export default createRule({ name: 'no-explicit-any', meta: { type: 'suggestion', diff --git a/packages/eslint-plugin/src/rules/no-extra-non-null-assertion.ts b/packages/eslint-plugin/src/rules/no-extra-non-null-assertion.ts index 082c3d212a69..ee1858fe7d95 100644 --- a/packages/eslint-plugin/src/rules/no-extra-non-null-assertion.ts +++ b/packages/eslint-plugin/src/rules/no-extra-non-null-assertion.ts @@ -1,8 +1,8 @@ import type { TSESTree } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; -export default util.createRule({ +export default createRule({ name: 'no-extra-non-null-assertion', meta: { type: 'problem', diff --git a/packages/eslint-plugin/src/rules/no-extra-parens.ts b/packages/eslint-plugin/src/rules/no-extra-parens.ts index 5d26f8a5efb7..ab708faa83db 100644 --- a/packages/eslint-plugin/src/rules/no-extra-parens.ts +++ b/packages/eslint-plugin/src/rules/no-extra-parens.ts @@ -4,15 +4,19 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import type { + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +} from '../util'; +import { createRule, isOpeningParenToken, isTypeAssertion } from '../util'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; const baseRule = getESLintCoreRule('no-extra-parens'); -type Options = util.InferOptionsTypeFromRule; -type MessageIds = util.InferMessageIdsTypeFromRule; +type Options = InferOptionsTypeFromRule; +type MessageIds = InferMessageIdsTypeFromRule; -export default util.createRule({ +export default createRule({ name: 'no-extra-parens', meta: { type: 'layout', @@ -36,8 +40,8 @@ export default util.createRule({ const rule = rules.BinaryExpression as (n: typeof node) => void; // makes the rule think it should skip the left or right - const isLeftTypeAssertion = util.isTypeAssertion(node.left); - const isRightTypeAssertion = util.isTypeAssertion(node.right); + const isLeftTypeAssertion = isTypeAssertion(node.left); + const isRightTypeAssertion = isTypeAssertion(node.right); if (isLeftTypeAssertion && isRightTypeAssertion) { return; // ignore } @@ -67,7 +71,7 @@ export default util.createRule({ ): void { const rule = rules.CallExpression as (n: typeof node) => void; - if (util.isTypeAssertion(node.callee)) { + if (isTypeAssertion(node.callee)) { // reduces the precedence of the node so the rule thinks it needs to be wrapped return rule({ ...node, @@ -81,8 +85,8 @@ export default util.createRule({ if ( node.arguments.length === 1 && // is there any opening parenthesis in type arguments - sourceCode.getTokenAfter(node.callee, util.isOpeningParenToken) !== - sourceCode.getTokenBefore(node.arguments[0], util.isOpeningParenToken) + sourceCode.getTokenAfter(node.callee, isOpeningParenToken) !== + sourceCode.getTokenBefore(node.arguments[0], isOpeningParenToken) ) { return rule({ ...node, @@ -102,7 +106,7 @@ export default util.createRule({ ): void { const rule = rules.UnaryExpression as (n: typeof node) => void; - if (util.isTypeAssertion(node.argument)) { + if (isTypeAssertion(node.argument)) { // reduces the precedence of the node so the rule thinks it needs to be wrapped return rule({ ...node, @@ -119,13 +123,13 @@ export default util.createRule({ const overrides: TSESLint.RuleListener = { // ArrayExpression ArrowFunctionExpression(node) { - if (!util.isTypeAssertion(node.body)) { + if (!isTypeAssertion(node.body)) { return rules.ArrowFunctionExpression(node); } }, // AssignmentExpression AwaitExpression(node) { - if (util.isTypeAssertion(node.argument)) { + if (isTypeAssertion(node.argument)) { // reduces the precedence of the node so the rule thinks it needs to be wrapped return rules.AwaitExpression({ ...node, @@ -165,7 +169,7 @@ export default util.createRule({ }, ConditionalExpression(node) { // reduces the precedence of the node so the rule thinks it needs to be wrapped - if (util.isTypeAssertion(node.test)) { + if (isTypeAssertion(node.test)) { return rules.ConditionalExpression({ ...node, test: { @@ -174,7 +178,7 @@ export default util.createRule({ }, }); } - if (util.isTypeAssertion(node.consequent)) { + if (isTypeAssertion(node.consequent)) { return rules.ConditionalExpression({ ...node, consequent: { @@ -183,7 +187,7 @@ export default util.createRule({ }, }); } - if (util.isTypeAssertion(node.alternate)) { + if (isTypeAssertion(node.alternate)) { // reduces the precedence of the node so the rule thinks it needs to be wrapped return rules.ConditionalExpression({ ...node, @@ -199,19 +203,19 @@ export default util.createRule({ // ForIn and ForOf are guarded by eslint version ForStatement(node) { // make the rule skip the piece by removing it entirely - if (node.init && util.isTypeAssertion(node.init)) { + if (node.init && isTypeAssertion(node.init)) { return rules.ForStatement({ ...node, init: null, }); } - if (node.test && util.isTypeAssertion(node.test)) { + if (node.test && isTypeAssertion(node.test)) { return rules.ForStatement({ ...node, test: null, }); } - if (node.update && util.isTypeAssertion(node.update)) { + if (node.update && isTypeAssertion(node.update)) { return rules.ForStatement({ ...node, update: null, @@ -221,14 +225,14 @@ export default util.createRule({ return rules.ForStatement(node); }, 'ForStatement > *.init:exit'(node: TSESTree.Node) { - if (!util.isTypeAssertion(node)) { + if (!isTypeAssertion(node)) { return rules['ForStatement > *.init:exit'](node); } }, // IfStatement LogicalExpression: binaryExp, MemberExpression(node) { - if (util.isTypeAssertion(node.object)) { + if (isTypeAssertion(node.object)) { // reduces the precedence of the node so the rule thinks it needs to be wrapped return rules.MemberExpression({ ...node, @@ -246,18 +250,18 @@ export default util.createRule({ // ReturnStatement // SequenceExpression SpreadElement(node) { - if (!util.isTypeAssertion(node.argument)) { + if (!isTypeAssertion(node.argument)) { return rules.SpreadElement(node); } }, SwitchCase(node) { - if (node.test && !util.isTypeAssertion(node.test)) { + if (node.test && !isTypeAssertion(node.test)) { return rules.SwitchCase(node); } }, // SwitchStatement ThrowStatement(node) { - if (node.argument && !util.isTypeAssertion(node.argument)) { + if (node.argument && !isTypeAssertion(node.argument)) { return rules.ThrowStatement(node); } }, @@ -267,14 +271,14 @@ export default util.createRule({ // WhileStatement // WithStatement - i'm not going to even bother implementing this terrible and never used feature YieldExpression(node) { - if (node.argument && !util.isTypeAssertion(node.argument)) { + if (node.argument && !isTypeAssertion(node.argument)) { return rules.YieldExpression(node); } }, }; if (rules.ForInStatement && rules.ForOfStatement) { overrides.ForInStatement = function (node): void { - if (util.isTypeAssertion(node.right)) { + if (isTypeAssertion(node.right)) { // as of 7.20.0 there's no way to skip checking the right of the ForIn // so just don't validate it at all return; @@ -283,7 +287,7 @@ export default util.createRule({ return rules.ForInStatement(node); }; overrides.ForOfStatement = function (node): void { - if (util.isTypeAssertion(node.right)) { + if (isTypeAssertion(node.right)) { // makes the rule skip checking of the right return rules.ForOfStatement({ ...node, @@ -301,7 +305,7 @@ export default util.createRule({ overrides['ForInStatement, ForOfStatement'] = function ( node: TSESTree.ForInStatement | TSESTree.ForOfStatement, ): void { - if (util.isTypeAssertion(node.right)) { + if (isTypeAssertion(node.right)) { // makes the rule skip checking of the right return rules['ForInStatement, ForOfStatement']({ ...node, diff --git a/packages/eslint-plugin/src/rules/no-extra-semi.ts b/packages/eslint-plugin/src/rules/no-extra-semi.ts index d2860771c53b..84903111bb71 100644 --- a/packages/eslint-plugin/src/rules/no-extra-semi.ts +++ b/packages/eslint-plugin/src/rules/no-extra-semi.ts @@ -1,12 +1,16 @@ -import * as util from '../util'; +import type { + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +} from '../util'; +import { createRule } from '../util'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; const baseRule = getESLintCoreRule('no-extra-semi'); -type Options = util.InferOptionsTypeFromRule; -type MessageIds = util.InferMessageIdsTypeFromRule; +type Options = InferOptionsTypeFromRule; +type MessageIds = InferMessageIdsTypeFromRule; -export default util.createRule({ +export default createRule({ name: 'no-extra-semi', meta: { type: 'suggestion', diff --git a/packages/eslint-plugin/src/rules/no-extraneous-class.ts b/packages/eslint-plugin/src/rules/no-extraneous-class.ts index 21dda4c686dd..009da2a21a75 100644 --- a/packages/eslint-plugin/src/rules/no-extraneous-class.ts +++ b/packages/eslint-plugin/src/rules/no-extraneous-class.ts @@ -1,7 +1,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; type Options = [ { @@ -13,7 +13,7 @@ type Options = [ ]; type MessageIds = 'empty' | 'onlyConstructor' | 'onlyStatic'; -export default util.createRule({ +export default createRule({ name: 'no-extraneous-class', meta: { type: 'suggestion', diff --git a/packages/eslint-plugin/src/rules/no-floating-promises.ts b/packages/eslint-plugin/src/rules/no-floating-promises.ts index bd1aadaeab2f..066469c3507d 100644 --- a/packages/eslint-plugin/src/rules/no-floating-promises.ts +++ b/packages/eslint-plugin/src/rules/no-floating-promises.ts @@ -3,8 +3,12 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../util'; -import { OperatorPrecedence } from '../util'; +import { + createRule, + getOperatorPrecedence, + getParserServices, + OperatorPrecedence, +} from '../util'; type Options = [ { @@ -31,7 +35,7 @@ const messageBaseVoid = const messageRejectionHandler = 'A rejection handler that is not a function will be ignored.'; -export default util.createRule({ +export default createRule({ name: 'no-floating-promises', meta: { docs: { @@ -78,7 +82,7 @@ export default util.createRule({ ], create(context, [options]) { - const services = util.getParserServices(context); + const services = getParserServices(context); const checker = services.program.getTypeChecker(); return { @@ -171,7 +175,7 @@ export default util.createRule({ const operator = ts.isBinaryExpression(node) ? node.operatorToken.kind : ts.SyntaxKind.Unknown; - const nodePrecedence = util.getOperatorPrecedence(node.kind, operator); + const nodePrecedence = getOperatorPrecedence(node.kind, operator); return nodePrecedence > OperatorPrecedence.Unary; } diff --git a/packages/eslint-plugin/src/rules/no-for-in-array.ts b/packages/eslint-plugin/src/rules/no-for-in-array.ts index ab6e98321656..75a04de8b9c0 100644 --- a/packages/eslint-plugin/src/rules/no-for-in-array.ts +++ b/packages/eslint-plugin/src/rules/no-for-in-array.ts @@ -1,8 +1,13 @@ import * as ts from 'typescript'; -import * as util from '../util'; +import { + createRule, + getConstrainedTypeAtLocation, + getParserServices, + isTypeArrayTypeOrUnionOfArrayTypes, +} from '../util'; -export default util.createRule({ +export default createRule({ name: 'no-for-in-array', meta: { docs: { @@ -21,13 +26,13 @@ export default util.createRule({ create(context) { return { ForInStatement(node): void { - const services = util.getParserServices(context); + const services = getParserServices(context); const checker = services.program.getTypeChecker(); - const type = util.getConstrainedTypeAtLocation(services, node.right); + const type = getConstrainedTypeAtLocation(services, node.right); if ( - util.isTypeArrayTypeOrUnionOfArrayTypes(type, checker) || + isTypeArrayTypeOrUnionOfArrayTypes(type, checker) || (type.flags & ts.TypeFlags.StringLike) !== 0 ) { context.report({ diff --git a/packages/eslint-plugin/src/rules/no-implied-eval.ts b/packages/eslint-plugin/src/rules/no-implied-eval.ts index 0560d7647c42..eede26dce3cd 100644 --- a/packages/eslint-plugin/src/rules/no-implied-eval.ts +++ b/packages/eslint-plugin/src/rules/no-implied-eval.ts @@ -3,7 +3,7 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../util'; +import { createRule, getParserServices } from '../util'; const FUNCTION_CONSTRUCTOR = 'Function'; const GLOBAL_CANDIDATES = new Set(['global', 'window', 'globalThis']); @@ -14,7 +14,7 @@ const EVAL_LIKE_METHODS = new Set([ 'execScript', ]); -export default util.createRule({ +export default createRule({ name: 'no-implied-eval', meta: { docs: { @@ -33,7 +33,7 @@ export default util.createRule({ }, defaultOptions: [], create(context) { - const services = util.getParserServices(context); + const services = getParserServices(context); const checker = services.program.getTypeChecker(); function getCalleeName( diff --git a/packages/eslint-plugin/src/rules/no-import-type-side-effects.ts b/packages/eslint-plugin/src/rules/no-import-type-side-effects.ts index 0e814a0ca48d..8501c9fd4aea 100644 --- a/packages/eslint-plugin/src/rules/no-import-type-side-effects.ts +++ b/packages/eslint-plugin/src/rules/no-import-type-side-effects.ts @@ -1,12 +1,18 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { + createRule, + isImportKeyword, + isTypeKeyword, + nullThrows, + NullThrowsReasons, +} from '../util'; type Options = []; type MessageIds = 'useTopLevelQualifier'; -export default util.createRule({ +export default createRule({ name: 'no-import-type-side-effects', meta: { type: 'problem', @@ -49,9 +55,9 @@ export default util.createRule({ fix(fixer) { const fixes: TSESLint.RuleFix[] = []; for (const specifier of specifiers) { - const qualifier = util.nullThrows( - sourceCode.getFirstToken(specifier, util.isTypeKeyword), - util.NullThrowsReasons.MissingToken( + const qualifier = nullThrows( + sourceCode.getFirstToken(specifier, isTypeKeyword), + NullThrowsReasons.MissingToken( 'type keyword', 'import specifier', ), @@ -64,9 +70,9 @@ export default util.createRule({ ); } - const importKeyword = util.nullThrows( - sourceCode.getFirstToken(node, util.isImportKeyword), - util.NullThrowsReasons.MissingToken('import keyword', 'import'), + const importKeyword = nullThrows( + sourceCode.getFirstToken(node, isImportKeyword), + NullThrowsReasons.MissingToken('import keyword', 'import'), ); fixes.push(fixer.insertTextAfter(importKeyword, ' type')); diff --git a/packages/eslint-plugin/src/rules/no-inferrable-types.ts b/packages/eslint-plugin/src/rules/no-inferrable-types.ts index f63beda74401..15f88ca85c07 100644 --- a/packages/eslint-plugin/src/rules/no-inferrable-types.ts +++ b/packages/eslint-plugin/src/rules/no-inferrable-types.ts @@ -2,7 +2,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; type Options = [ { @@ -12,7 +12,7 @@ type Options = [ ]; type MessageIds = 'noInferrableType'; -export default util.createRule({ +export default createRule({ name: 'no-inferrable-types', meta: { type: 'suggestion', diff --git a/packages/eslint-plugin/src/rules/no-invalid-void-type.ts b/packages/eslint-plugin/src/rules/no-invalid-void-type.ts index 4808a439f5a3..fa849d8ac915 100644 --- a/packages/eslint-plugin/src/rules/no-invalid-void-type.ts +++ b/packages/eslint-plugin/src/rules/no-invalid-void-type.ts @@ -1,7 +1,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; interface Options { allowInGenericTypeArguments?: string[] | boolean; @@ -16,7 +16,7 @@ type MessageIds = | 'invalidVoidNotReturnOrThisParamOrGeneric' | 'invalidVoidUnionConstituent'; -export default util.createRule<[Options], MessageIds>({ +export default createRule<[Options], MessageIds>({ name: 'no-invalid-void-type', meta: { type: 'problem', diff --git a/packages/eslint-plugin/src/rules/no-loop-func.ts b/packages/eslint-plugin/src/rules/no-loop-func.ts index f4e4b50825c9..03f7662f9e33 100644 --- a/packages/eslint-plugin/src/rules/no-loop-func.ts +++ b/packages/eslint-plugin/src/rules/no-loop-func.ts @@ -1,15 +1,19 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import type { + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +} from '../util'; +import { createRule } from '../util'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; const baseRule = getESLintCoreRule('no-loop-func'); -type Options = util.InferOptionsTypeFromRule; -type MessageIds = util.InferMessageIdsTypeFromRule; +type Options = InferOptionsTypeFromRule; +type MessageIds = InferMessageIdsTypeFromRule; -export default util.createRule({ +export default createRule({ name: 'no-loop-func', meta: { type: 'suggestion', diff --git a/packages/eslint-plugin/src/rules/no-loss-of-precision.ts b/packages/eslint-plugin/src/rules/no-loss-of-precision.ts index 8a07f975ab15..ed3747884abd 100644 --- a/packages/eslint-plugin/src/rules/no-loss-of-precision.ts +++ b/packages/eslint-plugin/src/rules/no-loss-of-precision.ts @@ -1,16 +1,18 @@ import type { TSESTree } from '@typescript-eslint/utils'; -import * as util from '../util'; +import type { + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +} from '../util'; +import { createRule } from '../util'; import { maybeGetESLintCoreRule } from '../util/getESLintCoreRule'; const baseRule = maybeGetESLintCoreRule('no-loss-of-precision'); -type Options = util.InferOptionsTypeFromRule>; -type MessageIds = util.InferMessageIdsTypeFromRule< - NonNullable ->; +type Options = InferOptionsTypeFromRule>; +type MessageIds = InferMessageIdsTypeFromRule>; -export default util.createRule({ +export default createRule({ name: 'no-loss-of-precision', meta: { type: 'problem', diff --git a/packages/eslint-plugin/src/rules/no-magic-numbers.ts b/packages/eslint-plugin/src/rules/no-magic-numbers.ts index 92a03c9078d4..54e559d3365c 100644 --- a/packages/eslint-plugin/src/rules/no-magic-numbers.ts +++ b/packages/eslint-plugin/src/rules/no-magic-numbers.ts @@ -2,16 +2,20 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema'; -import * as util from '../util'; +import type { + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +} from '../util'; +import { createRule, deepMerge } from '../util'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; const baseRule = getESLintCoreRule('no-magic-numbers'); -type Options = util.InferOptionsTypeFromRule; -type MessageIds = util.InferMessageIdsTypeFromRule; +type Options = InferOptionsTypeFromRule; +type MessageIds = InferMessageIdsTypeFromRule; // Extend base schema with additional property to ignore TS numeric literal types -const schema = util.deepMerge( +const schema = deepMerge( // eslint-disable-next-line @typescript-eslint/no-unsafe-argument -- https://github.com/microsoft/TypeScript/issues/17002 Array.isArray(baseRule.meta.schema) ? baseRule.meta.schema[0] @@ -34,7 +38,7 @@ const schema = util.deepMerge( }, ) as unknown as JSONSchema4; -export default util.createRule({ +export default createRule({ name: 'no-magic-numbers', meta: { type: 'suggestion', diff --git a/packages/eslint-plugin/src/rules/no-meaningless-void-operator.ts b/packages/eslint-plugin/src/rules/no-meaningless-void-operator.ts index 524c54387889..0b371f9cf349 100644 --- a/packages/eslint-plugin/src/rules/no-meaningless-void-operator.ts +++ b/packages/eslint-plugin/src/rules/no-meaningless-void-operator.ts @@ -3,7 +3,7 @@ import { ESLintUtils } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../util'; +import { createRule } from '../util'; type Options = [ { @@ -11,10 +11,7 @@ type Options = [ }, ]; -export default util.createRule< - Options, - 'meaninglessVoidOperator' | 'removeVoid' ->({ +export default createRule({ name: 'no-meaningless-void-operator', meta: { type: 'suggestion', diff --git a/packages/eslint-plugin/src/rules/no-misused-new.ts b/packages/eslint-plugin/src/rules/no-misused-new.ts index 41df0cb5f997..049101a110e0 100644 --- a/packages/eslint-plugin/src/rules/no-misused-new.ts +++ b/packages/eslint-plugin/src/rules/no-misused-new.ts @@ -1,9 +1,9 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; -export default util.createRule({ +export default createRule({ name: 'no-misused-new', meta: { type: 'problem', diff --git a/packages/eslint-plugin/src/rules/no-misused-promises.ts b/packages/eslint-plugin/src/rules/no-misused-promises.ts index a5fe0721b88d..7fd6fb9ca71c 100644 --- a/packages/eslint-plugin/src/rules/no-misused-promises.ts +++ b/packages/eslint-plugin/src/rules/no-misused-promises.ts @@ -3,7 +3,7 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../util'; +import { createRule, getParserServices, getTypeArguments } from '../util'; type Options = [ { @@ -58,7 +58,7 @@ function parseChecksVoidReturn( } } -export default util.createRule({ +export default createRule({ name: 'no-misused-promises', meta: { docs: { @@ -121,7 +121,7 @@ export default util.createRule({ ], create(context, [{ checksConditionals, checksVoidReturn, checksSpreads }]) { - const services = util.getParserServices(context); + const services = getParserServices(context); const checker = services.program.getTypeChecker(); const checkedNodes = new Set(); @@ -556,7 +556,7 @@ function voidFunctionArguments( // Unwrap 'Array' to 'MaybeVoidFunction', // so that we'll handle it in the same way as a non-rest // 'param: MaybeVoidFunction' - type = util.getTypeArguments(type, checker)[0]; + type = getTypeArguments(type, checker)[0]; for (let i = index; i < node.arguments.length; i++) { checkThenableOrVoidArgument( checker, @@ -570,7 +570,7 @@ function voidFunctionArguments( } else if (checker.isTupleType(type)) { // Check each type in the tuple - for example, [boolean, () => void] would // add the index of the second tuple parameter to 'voidReturnIndices' - const typeArgs = util.getTypeArguments(type, checker); + const typeArgs = getTypeArguments(type, checker); for ( let i = index; i < node.arguments.length && i - index < typeArgs.length; diff --git a/packages/eslint-plugin/src/rules/no-mixed-enums.ts b/packages/eslint-plugin/src/rules/no-mixed-enums.ts index 33ad352b1b69..71344fa5a689 100644 --- a/packages/eslint-plugin/src/rules/no-mixed-enums.ts +++ b/packages/eslint-plugin/src/rules/no-mixed-enums.ts @@ -5,7 +5,7 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../util'; +import { createRule, getParserServices } from '../util'; enum AllowedType { Number, @@ -13,7 +13,7 @@ enum AllowedType { Unknown, } -export default util.createRule({ +export default createRule({ name: 'no-mixed-enums', meta: { docs: { @@ -29,7 +29,7 @@ export default util.createRule({ }, defaultOptions: [], create(context) { - const parserServices = util.getParserServices(context); + const parserServices = getParserServices(context); const typeChecker = parserServices.program.getTypeChecker(); interface CollectedDefinitions { diff --git a/packages/eslint-plugin/src/rules/no-namespace.ts b/packages/eslint-plugin/src/rules/no-namespace.ts index 145ddc3ad16b..516225271956 100644 --- a/packages/eslint-plugin/src/rules/no-namespace.ts +++ b/packages/eslint-plugin/src/rules/no-namespace.ts @@ -1,7 +1,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule, isDefinitionFile } from '../util'; type Options = [ { @@ -11,7 +11,7 @@ type Options = [ ]; type MessageIds = 'moduleSyntaxIsPreferred'; -export default util.createRule({ +export default createRule({ name: 'no-namespace', meta: { type: 'suggestion', @@ -68,7 +68,7 @@ export default util.createRule({ ): void { if ( node.parent.type === AST_NODE_TYPES.TSModuleDeclaration || - (allowDefinitionFiles && util.isDefinitionFile(filename)) || + (allowDefinitionFiles && isDefinitionFile(filename)) || (allowDeclarations && isDeclaration(node)) ) { return; diff --git a/packages/eslint-plugin/src/rules/no-non-null-asserted-nullish-coalescing.ts b/packages/eslint-plugin/src/rules/no-non-null-asserted-nullish-coalescing.ts index a79fa4062b1f..44d540cd44ea 100644 --- a/packages/eslint-plugin/src/rules/no-non-null-asserted-nullish-coalescing.ts +++ b/packages/eslint-plugin/src/rules/no-non-null-asserted-nullish-coalescing.ts @@ -3,7 +3,7 @@ import { DefinitionType } from '@typescript-eslint/scope-manager'; import type { TSESLint } from '@typescript-eslint/utils'; import { ASTUtils, TSESTree } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule, nullThrows, NullThrowsReasons } from '../util'; function hasAssignmentBeforeNode( variable: TSESLint.Scope.Variable, @@ -31,7 +31,7 @@ function isDefinitionWithAssignment(definition: Definition): boolean { ); } -export default util.createRule({ +export default createRule({ name: 'no-non-null-asserted-nullish-coalescing', meta: { type: 'problem', @@ -85,15 +85,12 @@ export default util.createRule({ { messageId: 'suggestRemovingNonNull', fix(fixer): TSESLint.RuleFix { - const exclamationMark = util.nullThrows( + const exclamationMark = nullThrows( sourceCode.getLastToken( node, ASTUtils.isNonNullAssertionPunctuator, ), - util.NullThrowsReasons.MissingToken( - '!', - 'Non-null Assertion', - ), + NullThrowsReasons.MissingToken('!', 'Non-null Assertion'), ); return fixer.remove(exclamationMark); }, diff --git a/packages/eslint-plugin/src/rules/no-non-null-asserted-optional-chain.ts b/packages/eslint-plugin/src/rules/no-non-null-asserted-optional-chain.ts index 3939fbdebb2a..efc8fc26cf5a 100644 --- a/packages/eslint-plugin/src/rules/no-non-null-asserted-optional-chain.ts +++ b/packages/eslint-plugin/src/rules/no-non-null-asserted-optional-chain.ts @@ -1,8 +1,8 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; -export default util.createRule({ +export default createRule({ name: 'no-non-null-asserted-optional-chain', meta: { type: 'problem', diff --git a/packages/eslint-plugin/src/rules/no-non-null-assertion.ts b/packages/eslint-plugin/src/rules/no-non-null-assertion.ts index ba8b88158def..6883b908bb54 100644 --- a/packages/eslint-plugin/src/rules/no-non-null-assertion.ts +++ b/packages/eslint-plugin/src/rules/no-non-null-assertion.ts @@ -1,11 +1,11 @@ import type { TSESLint } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule, isNonNullAssertionPunctuator } from '../util'; type MessageIds = 'noNonNull' | 'suggestOptionalChain'; -export default util.createRule<[], MessageIds>({ +export default createRule<[], MessageIds>({ name: 'no-non-null-assertion', meta: { type: 'problem', @@ -34,7 +34,7 @@ export default util.createRule<[], MessageIds>({ return (fixer: TSESLint.RuleFixer): TSESLint.RuleFix | null => { const operator = sourceCode.getTokenAfter( node.expression, - util.isNonNullAssertionPunctuator, + isNonNullAssertionPunctuator, ); if (operator) { return fixer.replaceText(operator, replacement); @@ -47,7 +47,7 @@ export default util.createRule<[], MessageIds>({ return (fixer: TSESLint.RuleFixer): TSESLint.RuleFix | null => { const operator = sourceCode.getTokenAfter( node.expression, - util.isNonNullAssertionPunctuator, + isNonNullAssertionPunctuator, ); if (operator) { return fixer.remove(operator); diff --git a/packages/eslint-plugin/src/rules/no-redeclare.ts b/packages/eslint-plugin/src/rules/no-redeclare.ts index 1f47b575c813..296dc4a6d14f 100644 --- a/packages/eslint-plugin/src/rules/no-redeclare.ts +++ b/packages/eslint-plugin/src/rules/no-redeclare.ts @@ -2,7 +2,7 @@ import { ScopeType } from '@typescript-eslint/scope-manager'; import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule, getNameLocationInGlobalDirectiveComment } from '../util'; type MessageIds = 'redeclared' | 'redeclaredAsBuiltin' | 'redeclaredBySyntax'; type Options = [ @@ -12,7 +12,7 @@ type Options = [ }, ]; -export default util.createRule({ +export default createRule({ name: 'no-redeclare', meta: { type: 'suggestion', @@ -91,7 +91,7 @@ export default util.createRule({ yield { type: 'comment', node: comment, - loc: util.getNameLocationInGlobalDirectiveComment( + loc: getNameLocationInGlobalDirectiveComment( sourceCode, comment, variable.name, diff --git a/packages/eslint-plugin/src/rules/no-redundant-type-constituents.ts b/packages/eslint-plugin/src/rules/no-redundant-type-constituents.ts index e70637256bfd..f38d6c6ad6f1 100644 --- a/packages/eslint-plugin/src/rules/no-redundant-type-constituents.ts +++ b/packages/eslint-plugin/src/rules/no-redundant-type-constituents.ts @@ -2,7 +2,18 @@ import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../util'; +import { + arrayGroupByToMap, + createRule, + getParserServices, + isFunction, + isFunctionType, + isTypeAnyType, + isTypeBigIntLiteralType, + isTypeNeverType, + isTypeTemplateLiteralType, + isTypeUnknownType, +} from '../util'; const literalToPrimitiveTypeFlags = { [ts.TypeFlags.BigIntLiteral]: ts.TypeFlags.BigInt, @@ -82,7 +93,7 @@ function describeLiteralType(type: ts.Type): string { return JSON.stringify(type.value); } - if (util.isTypeBigIntLiteralType(type)) { + if (isTypeBigIntLiteralType(type)) { return `${type.value.negative ? '-' : ''}${type.value.base10Value}n`; } @@ -91,23 +102,23 @@ function describeLiteralType(type: ts.Type): string { return type.value.toString(); } - if (util.isTypeAnyType(type)) { + if (isTypeAnyType(type)) { return 'any'; } - if (util.isTypeNeverType(type)) { + if (isTypeNeverType(type)) { return 'never'; } - if (util.isTypeUnknownType(type)) { + if (isTypeUnknownType(type)) { return 'unknown'; } - if (util.isTypeTemplateLiteralType(type)) { + if (isTypeTemplateLiteralType(type)) { return 'template literal type'; } - if (util.isTypeBigIntLiteralType(type)) { + if (isTypeBigIntLiteralType(type)) { return `${type.value.negative ? '-' : ''}${type.value.base10Value}n`; } @@ -160,8 +171,7 @@ function describeLiteralTypeNode(typeNode: TSESTree.TypeNode): string { function isNodeInsideReturnType(node: TSESTree.TSUnionType): boolean { return !!( node.parent?.type === AST_NODE_TYPES.TSTypeAnnotation && - (util.isFunctionType(node.parent.parent) || - util.isFunction(node.parent.parent)) + (isFunctionType(node.parent.parent) || isFunction(node.parent.parent)) ); } @@ -177,7 +187,7 @@ function unionTypePartsUnlessBoolean(type: ts.Type): ts.Type[] { : tsutils.unionTypeParts(type); } -export default util.createRule({ +export default createRule({ name: 'no-redundant-type-constituents', meta: { docs: { @@ -197,7 +207,7 @@ export default util.createRule({ }, defaultOptions: [], create(context) { - const services = util.getParserServices(context); + const services = getParserServices(context); const typesCache = new Map(); function getTypeNodeTypePartFlags( @@ -438,7 +448,7 @@ export default util.createRule({ // group those literals by their primitive type, // then report each primitive type with all its literals for (const [typeNode, typeFlagsWithText] of overriddenTypeNodes) { - const grouped = util.arrayGroupByToMap( + const grouped = arrayGroupByToMap( typeFlagsWithText, pair => pair.primitiveTypeFlag, ); diff --git a/packages/eslint-plugin/src/rules/no-require-imports.ts b/packages/eslint-plugin/src/rules/no-require-imports.ts index 2f9310b38fcd..32a365436b96 100644 --- a/packages/eslint-plugin/src/rules/no-require-imports.ts +++ b/packages/eslint-plugin/src/rules/no-require-imports.ts @@ -1,9 +1,9 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { ASTUtils } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; -export default util.createRule({ +export default createRule({ name: 'no-require-imports', meta: { type: 'problem', diff --git a/packages/eslint-plugin/src/rules/no-shadow.ts b/packages/eslint-plugin/src/rules/no-shadow.ts index e8dc7a260f8d..b26e8b4a957f 100644 --- a/packages/eslint-plugin/src/rules/no-shadow.ts +++ b/packages/eslint-plugin/src/rules/no-shadow.ts @@ -6,7 +6,7 @@ import { DefinitionType, ScopeType } from '@typescript-eslint/scope-manager'; import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES, ASTUtils } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; type MessageIds = 'noShadow' | 'noShadowGlobal'; type Options = [ @@ -26,7 +26,7 @@ const allowedFunctionVariableDefTypes = new Set([ AST_NODE_TYPES.TSMethodSignature, ]); -export default util.createRule({ +export default createRule({ name: 'no-shadow', meta: { type: 'suggestion', diff --git a/packages/eslint-plugin/src/rules/no-this-alias.ts b/packages/eslint-plugin/src/rules/no-this-alias.ts index 57a326e2e808..ece937cff3df 100644 --- a/packages/eslint-plugin/src/rules/no-this-alias.ts +++ b/packages/eslint-plugin/src/rules/no-this-alias.ts @@ -1,7 +1,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; type Options = [ { @@ -11,7 +11,7 @@ type Options = [ ]; type MessageIds = 'thisAssignment' | 'thisDestructure'; -export default util.createRule({ +export default createRule({ name: 'no-this-alias', meta: { type: 'suggestion', diff --git a/packages/eslint-plugin/src/rules/no-throw-literal.ts b/packages/eslint-plugin/src/rules/no-throw-literal.ts index 55145507d657..f1129c252036 100644 --- a/packages/eslint-plugin/src/rules/no-throw-literal.ts +++ b/packages/eslint-plugin/src/rules/no-throw-literal.ts @@ -2,7 +2,12 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as ts from 'typescript'; -import * as util from '../util'; +import { + createRule, + getParserServices, + isTypeAnyType, + isTypeUnknownType, +} from '../util'; type MessageIds = 'object' | 'undef'; @@ -13,7 +18,7 @@ type Options = [ }, ]; -export default util.createRule({ +export default createRule({ name: 'no-throw-literal', meta: { type: 'problem', @@ -49,7 +54,7 @@ export default util.createRule({ }, ], create(context, [options]) { - const services = util.getParserServices(context); + const services = getParserServices(context); const checker = services.program.getTypeChecker(); function isErrorLike(type: ts.Type): boolean { @@ -101,11 +106,11 @@ export default util.createRule({ return; } - if (options.allowThrowingAny && util.isTypeAnyType(type)) { + if (options.allowThrowingAny && isTypeAnyType(type)) { return; } - if (options.allowThrowingUnknown && util.isTypeUnknownType(type)) { + if (options.allowThrowingUnknown && isTypeUnknownType(type)) { return; } diff --git a/packages/eslint-plugin/src/rules/no-type-alias.ts b/packages/eslint-plugin/src/rules/no-type-alias.ts index cc568a6fa9db..b72c1f8b991a 100644 --- a/packages/eslint-plugin/src/rules/no-type-alias.ts +++ b/packages/eslint-plugin/src/rules/no-type-alias.ts @@ -1,7 +1,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; type Values = | 'always' @@ -32,7 +32,7 @@ interface TypeWithLabel { compositionType: CompositionType | null; } -export default util.createRule({ +export default createRule({ name: 'no-type-alias', meta: { deprecated: true, diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-boolean-literal-compare.ts b/packages/eslint-plugin/src/rules/no-unnecessary-boolean-literal-compare.ts index d0aba2defc7a..9a25eeb5f415 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-boolean-literal-compare.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-boolean-literal-compare.ts @@ -3,7 +3,7 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../util'; +import { createRule, getParserServices, isStrongPrecedenceNode } from '../util'; type MessageIds = | 'comparingNullableToFalse' @@ -29,7 +29,7 @@ interface BooleanComparisonWithTypeInformation extends BooleanComparison { expressionIsNullableBoolean: boolean; } -export default util.createRule({ +export default createRule({ name: 'no-unnecessary-boolean-literal-compare', meta: { docs: { @@ -78,7 +78,7 @@ export default util.createRule({ }, ], create(context, [options]) { - const services = util.getParserServices(context); + const services = getParserServices(context); const sourceCode = context.getSourceCode(); function getBooleanComparison( @@ -240,7 +240,7 @@ export default util.createRule({ yield fixer.insertTextBefore(mutatedNode, '!'); // if the expression `exp` is not a strong precedence node, wrap it in parentheses - if (!util.isStrongPrecedenceNode(comparison.expression)) { + if (!isStrongPrecedenceNode(comparison.expression)) { yield fixer.insertTextBefore(mutatedNode, '('); yield fixer.insertTextAfter(mutatedNode, ')'); } diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-qualifier.ts b/packages/eslint-plugin/src/rules/no-unnecessary-qualifier.ts index c1c558dab8a0..56286b8510cb 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-qualifier.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-qualifier.ts @@ -3,9 +3,9 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../util'; +import { createRule, getParserServices } from '../util'; -export default util.createRule({ +export default createRule({ name: 'no-unnecessary-qualifier', meta: { docs: { @@ -24,7 +24,7 @@ export default util.createRule({ create(context) { const namespacesInScope: ts.Node[] = []; let currentFailedNamespaceExpression: TSESTree.Node | null = null; - const services = util.getParserServices(context); + const services = getParserServices(context); const esTreeNodeToTSNodeMap = services.esTreeNodeToTSNodeMap; const checker = services.program.getTypeChecker(); const sourceCode = context.getSourceCode(); diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-type-arguments.ts b/packages/eslint-plugin/src/rules/no-unnecessary-type-arguments.ts index cb3b881e8feb..d766257d6c6c 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-type-arguments.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-type-arguments.ts @@ -2,8 +2,13 @@ import type { TSESTree } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../util'; -import { findFirstResult } from '../util'; +import { + createRule, + findFirstResult, + getParserServices, + getTypeArguments, + isTypeReferenceType, +} from '../util'; type ParameterCapableTSNode = | ts.CallExpression @@ -18,7 +23,7 @@ type ParameterCapableTSNode = type MessageIds = 'unnecessaryTypeParameter'; -export default util.createRule<[], MessageIds>({ +export default createRule<[], MessageIds>({ name: 'no-unnecessary-type-arguments', meta: { docs: { @@ -36,17 +41,17 @@ export default util.createRule<[], MessageIds>({ }, defaultOptions: [], create(context) { - const services = util.getParserServices(context); + const services = getParserServices(context); const checker = services.program.getTypeChecker(); function getTypeForComparison(type: ts.Type): { type: ts.Type; typeArguments: readonly ts.Type[]; } { - if (util.isTypeReferenceType(type)) { + if (isTypeReferenceType(type)) { return { type: type.target, - typeArguments: util.getTypeArguments(type, checker), + typeArguments: getTypeArguments(type, checker), }; } return { diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts b/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts index d466b59fe076..6029cf192da3 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts @@ -3,7 +3,15 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../util'; +import { + createRule, + getConstrainedTypeAtLocation, + getContextualType, + getDeclaration, + getParserServices, + isNullableType, + isTypeFlagSet, +} from '../util'; type Options = [ { @@ -12,7 +20,7 @@ type Options = [ ]; type MessageIds = 'contextuallyUnnecessary' | 'unnecessaryAssertion'; -export default util.createRule({ +export default createRule({ name: 'no-unnecessary-type-assertion', meta: { docs: { @@ -48,7 +56,7 @@ export default util.createRule({ defaultOptions: [{}], create(context, [options]) { const sourceCode = context.getSourceCode(); - const services = util.getParserServices(context); + const services = getParserServices(context); const checker = services.program.getTypeChecker(); const compilerOptions = services.program.getCompilerOptions(); @@ -87,7 +95,7 @@ export default util.createRule({ * Returns true if there's a chance the variable has been used before a value has been assigned to it */ function isPossiblyUsedBeforeAssigned(node: TSESTree.Expression): boolean { - const declaration = util.getDeclaration(services, node); + const declaration = getDeclaration(services, node); if (!declaration) { // don't know what the declaration is for some reason, so just assume the worst return true; @@ -109,7 +117,7 @@ export default util.createRule({ ) { // check if the defined variable type has changed since assignment const declarationType = checker.getTypeFromTypeNode(declaration.type); - const type = util.getConstrainedTypeAtLocation(services, node); + const type = getConstrainedTypeAtLocation(services, node); if (declarationType === type) { // possibly used before assigned, so just skip it // better to false negative and skip it, than false positive and fix to compile erroring code @@ -157,12 +165,9 @@ export default util.createRule({ const originalNode = services.esTreeNodeToTSNodeMap.get(node); - const type = util.getConstrainedTypeAtLocation( - services, - node.expression, - ); + const type = getConstrainedTypeAtLocation(services, node.expression); - if (!util.isNullableType(type)) { + if (!isNullableType(type)) { if (isPossiblyUsedBeforeAssigned(node.expression)) { return; } @@ -181,24 +186,21 @@ export default util.createRule({ // we know it's a nullable type // so figure out if the variable is used in a place that accepts nullable types - const contextualType = util.getContextualType(checker, originalNode); + const contextualType = getContextualType(checker, originalNode); if (contextualType) { // in strict mode you can't assign null to undefined, so we have to make sure that // the two types share a nullable type - const typeIncludesUndefined = util.isTypeFlagSet( + const typeIncludesUndefined = isTypeFlagSet( type, ts.TypeFlags.Undefined, ); - const typeIncludesNull = util.isTypeFlagSet( - type, - ts.TypeFlags.Null, - ); + const typeIncludesNull = isTypeFlagSet(type, ts.TypeFlags.Null); - const contextualTypeIncludesUndefined = util.isTypeFlagSet( + const contextualTypeIncludesUndefined = isTypeFlagSet( contextualType, ts.TypeFlags.Undefined, ); - const contextualTypeIncludesNull = util.isTypeFlagSet( + const contextualTypeIncludesNull = isTypeFlagSet( contextualType, ts.TypeFlags.Null, ); @@ -242,7 +244,7 @@ export default util.createRule({ const castType = services.getTypeAtLocation(node); if ( - tsutils.isTypeFlagSet(castType, ts.TypeFlags.Literal) || + isTypeFlagSet(castType, ts.TypeFlags.Literal) || (tsutils.isObjectType(castType) && (tsutils.isObjectFlagSet(castType, ts.ObjectFlags.Tuple) || couldBeTupleType(castType))) diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-type-constraint.ts b/packages/eslint-plugin/src/rules/no-unnecessary-type-constraint.ts index 7ca1106f7174..21a98de67a45 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-type-constraint.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-type-constraint.ts @@ -3,7 +3,7 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import { extname } from 'path'; import * as ts from 'typescript'; -import * as util from '../util'; +import { createRule } from '../util'; type MakeRequired = Omit & { [K in Key]-?: NonNullable; @@ -13,7 +13,7 @@ type TypeParameterWithConstraint = MakeRequired< 'constraint' >; -export default util.createRule({ +export default createRule({ name: 'no-unnecessary-type-constraint', meta: { docs: { diff --git a/packages/eslint-plugin/src/rules/no-unsafe-argument.ts b/packages/eslint-plugin/src/rules/no-unsafe-argument.ts index dab8c33be89c..fe74d1360969 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-argument.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-argument.ts @@ -2,7 +2,14 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as ts from 'typescript'; -import * as util from '../util'; +import { + createRule, + getParserServices, + getTypeArguments, + isTypeAnyArrayType, + isTypeAnyType, + isUnsafeAssignment, +} from '../util'; type MessageIds = | 'unsafeArgument' @@ -57,13 +64,13 @@ class FunctionSignature { // is a rest param if (checker.isArrayType(type)) { restType = { - type: util.getTypeArguments(type, checker)[0], + type: getTypeArguments(type, checker)[0], kind: RestTypeKind.Array, index: i, }; } else if (checker.isTupleType(type)) { restType = { - typeArguments: util.getTypeArguments(type, checker), + typeArguments: getTypeArguments(type, checker), kind: RestTypeKind.Tuple, index: i, }; @@ -131,7 +138,7 @@ class FunctionSignature { } } -export default util.createRule<[], MessageIds>({ +export default createRule<[], MessageIds>({ name: 'no-unsafe-argument', meta: { type: 'problem', @@ -152,7 +159,7 @@ export default util.createRule<[], MessageIds>({ }, defaultOptions: [], create(context) { - const services = util.getParserServices(context); + const services = getParserServices(context); const checker = services.program.getTypeChecker(); return { @@ -164,7 +171,7 @@ export default util.createRule<[], MessageIds>({ } // ignore any-typed calls as these are caught by no-unsafe-call - if (util.isTypeAnyType(services.getTypeAtLocation(node.callee))) { + if (isTypeAnyType(services.getTypeAtLocation(node.callee))) { return; } @@ -182,13 +189,13 @@ export default util.createRule<[], MessageIds>({ argument.argument, ); - if (util.isTypeAnyType(spreadArgType)) { + if (isTypeAnyType(spreadArgType)) { // foo(...any) context.report({ node: argument, messageId: 'unsafeSpread', }); - } else if (util.isTypeAnyArrayType(spreadArgType, checker)) { + } else if (isTypeAnyArrayType(spreadArgType, checker)) { // foo(...any[]) // TODO - we could break down the spread and compare the array type against each argument @@ -198,7 +205,7 @@ export default util.createRule<[], MessageIds>({ }); } else if (checker.isTupleType(spreadArgType)) { // foo(...[tuple1, tuple2]) - const spreadTypeArguments = util.getTypeArguments( + const spreadTypeArguments = getTypeArguments( spreadArgType, checker, ); @@ -207,7 +214,7 @@ export default util.createRule<[], MessageIds>({ if (parameterType == null) { continue; } - const result = util.isUnsafeAssignment( + const result = isUnsafeAssignment( tupleType, parameterType, checker, @@ -246,7 +253,7 @@ export default util.createRule<[], MessageIds>({ } const argumentType = services.getTypeAtLocation(argument); - const result = util.isUnsafeAssignment( + const result = isUnsafeAssignment( argumentType, parameterType, checker, diff --git a/packages/eslint-plugin/src/rules/no-unsafe-assignment.ts b/packages/eslint-plugin/src/rules/no-unsafe-assignment.ts index 7e929071e19e..819959b781d7 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-assignment.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-assignment.ts @@ -3,8 +3,20 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import type * as ts from 'typescript'; -import * as util from '../util'; -import { getThisExpression } from '../util'; +import { + createRule, + getConstrainedTypeAtLocation, + getContextualType, + getParserServices, + getThisExpression, + getTypeArguments, + isTypeAnyArrayType, + isTypeAnyType, + isTypeUnknownType, + isUnsafeAssignment, + nullThrows, + NullThrowsReasons, +} from '../util'; const enum ComparisonType { /** Do no assignment comparison */ @@ -15,7 +27,7 @@ const enum ComparisonType { Contextual, } -export default util.createRule({ +export default createRule({ name: 'no-unsafe-assignment', meta: { type: 'problem', @@ -42,7 +54,7 @@ export default util.createRule({ }, defaultOptions: [], create(context) { - const services = util.getParserServices(context); + const services = getParserServices(context); const checker = services.program.getTypeChecker(); const compilerOptions = services.program.getCompilerOptions(); const isNoImplicitThis = tsutils.isStrictCompilerOptionEnabled( @@ -73,7 +85,7 @@ export default util.createRule({ ): boolean { // any array // const [x] = ([] as any[]); - if (util.isTypeAnyArrayType(senderType, checker)) { + if (isTypeAnyArrayType(senderType, checker)) { context.report({ node: receiverNode, messageId: 'unsafeArrayPattern', @@ -85,7 +97,7 @@ export default util.createRule({ return true; } - const tupleElements = util.getTypeArguments(senderType, checker); + const tupleElements = getTypeArguments(senderType, checker); // tuple with any // const [x] = [1 as any]; @@ -111,7 +123,7 @@ export default util.createRule({ } // check for the any type first so we can handle [[[x]]] = [any] - if (util.isTypeAnyType(senderType)) { + if (isTypeAnyType(senderType)) { context.report({ node: receiverElement, messageId: 'unsafeArrayPatternFromTuple', @@ -197,7 +209,7 @@ export default util.createRule({ } // check for the any type first so we can handle {x: {y: z}} = {x: any} - if (util.isTypeAnyType(senderType)) { + if (isTypeAnyType(senderType)) { context.report({ node: receiverProperty.value, messageId: 'unsafeArrayPatternFromTuple', @@ -235,14 +247,14 @@ export default util.createRule({ const receiverTsNode = services.esTreeNodeToTSNodeMap.get(receiverNode); const receiverType = comparisonType === ComparisonType.Contextual - ? util.getContextualType(checker, receiverTsNode as ts.Expression) ?? + ? getContextualType(checker, receiverTsNode as ts.Expression) ?? services.getTypeAtLocation(receiverNode) : services.getTypeAtLocation(receiverNode); const senderType = services.getTypeAtLocation(senderNode); - if (util.isTypeAnyType(senderType)) { + if (isTypeAnyType(senderType)) { // handle cases when we assign any ==> unknown. - if (util.isTypeUnknownType(receiverType)) { + if (isTypeUnknownType(receiverType)) { return false; } @@ -253,8 +265,8 @@ export default util.createRule({ const thisExpression = getThisExpression(senderNode); if ( thisExpression && - util.isTypeAnyType( - util.getConstrainedTypeAtLocation(services, thisExpression), + isTypeAnyType( + getConstrainedTypeAtLocation(services, thisExpression), ) ) { messageId = 'anyAssignmentThis'; @@ -272,7 +284,7 @@ export default util.createRule({ return false; } - const result = util.isUnsafeAssignment( + const result = isUnsafeAssignment( senderType, receiverType, checker, @@ -308,9 +320,9 @@ export default util.createRule({ 'VariableDeclarator[init != null]'( node: TSESTree.VariableDeclarator, ): void { - const init = util.nullThrows( + const init = nullThrows( node.init, - util.NullThrowsReasons.MissingToken(node.type, 'init'), + NullThrowsReasons.MissingToken(node.type, 'init'), ); let didReport = checkAssignment( node.id, @@ -368,10 +380,7 @@ export default util.createRule({ }, 'ArrayExpression > SpreadElement'(node: TSESTree.SpreadElement): void { const restType = services.getTypeAtLocation(node.argument); - if ( - util.isTypeAnyType(restType) || - util.isTypeAnyArrayType(restType, checker) - ) { + if (isTypeAnyType(restType) || isTypeAnyArrayType(restType, checker)) { context.report({ node: node, messageId: 'unsafeArraySpread', @@ -379,9 +388,9 @@ export default util.createRule({ } }, 'JSXAttribute[value != null]'(node: TSESTree.JSXAttribute): void { - const value = util.nullThrows( + const value = nullThrows( node.value, - util.NullThrowsReasons.MissingToken(node.type, 'value'), + NullThrowsReasons.MissingToken(node.type, 'value'), ); if ( value.type !== AST_NODE_TYPES.JSXExpressionContainer || diff --git a/packages/eslint-plugin/src/rules/no-unsafe-call.ts b/packages/eslint-plugin/src/rules/no-unsafe-call.ts index b47d3ee9d85d..b4ec6379f2e1 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-call.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-call.ts @@ -1,8 +1,13 @@ import type { TSESTree } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; -import * as util from '../util'; -import { getThisExpression } from '../util'; +import { + createRule, + getConstrainedTypeAtLocation, + getParserServices, + getThisExpression, + isTypeAnyType, +} from '../util'; type MessageIds = | 'unsafeCall' @@ -10,7 +15,7 @@ type MessageIds = | 'unsafeNew' | 'unsafeTemplateTag'; -export default util.createRule<[], MessageIds>({ +export default createRule<[], MessageIds>({ name: 'no-unsafe-call', meta: { type: 'problem', @@ -32,7 +37,7 @@ export default util.createRule<[], MessageIds>({ }, defaultOptions: [], create(context) { - const services = util.getParserServices(context); + const services = getParserServices(context); const compilerOptions = services.program.getCompilerOptions(); const isNoImplicitThis = tsutils.isStrictCompilerOptionEnabled( compilerOptions, @@ -44,16 +49,16 @@ export default util.createRule<[], MessageIds>({ reportingNode: TSESTree.Node, messageId: MessageIds, ): void { - const type = util.getConstrainedTypeAtLocation(services, node); + const type = getConstrainedTypeAtLocation(services, node); - if (util.isTypeAnyType(type)) { + if (isTypeAnyType(type)) { if (!isNoImplicitThis) { // `this()` or `this.foo()` or `this.foo[bar]()` const thisExpression = getThisExpression(node); if ( thisExpression && - util.isTypeAnyType( - util.getConstrainedTypeAtLocation(services, thisExpression), + isTypeAnyType( + getConstrainedTypeAtLocation(services, thisExpression), ) ) { messageId = 'unsafeCallThis'; diff --git a/packages/eslint-plugin/src/rules/no-unsafe-declaration-merging.ts b/packages/eslint-plugin/src/rules/no-unsafe-declaration-merging.ts index 3e034ba458a3..b7004f06a9dd 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-declaration-merging.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-declaration-merging.ts @@ -2,9 +2,9 @@ import type { Scope } from '@typescript-eslint/scope-manager'; import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; -export default util.createRule({ +export default createRule({ name: 'no-unsafe-declaration-merging', meta: { type: 'problem', diff --git a/packages/eslint-plugin/src/rules/no-unsafe-enum-comparison.ts b/packages/eslint-plugin/src/rules/no-unsafe-enum-comparison.ts index 677eb918831f..ca08f2f7a2cd 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-enum-comparison.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-enum-comparison.ts @@ -2,7 +2,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../util'; +import { createRule, getParserServices } from '../util'; import { getEnumTypes } from './enum-utils/shared'; /** @@ -29,14 +29,14 @@ function typeViolates(leftTypeParts: ts.Type[], right: ts.Type): boolean { * @returns What type a type's enum value is (number or string), if either. */ function getEnumValueType(type: ts.Type): ts.TypeFlags | undefined { - return util.isTypeFlagSet(type, ts.TypeFlags.EnumLike) - ? util.isTypeFlagSet(type, ts.TypeFlags.NumberLiteral) + return tsutils.isTypeFlagSet(type, ts.TypeFlags.EnumLike) + ? tsutils.isTypeFlagSet(type, ts.TypeFlags.NumberLiteral) ? ts.TypeFlags.Number : ts.TypeFlags.String : undefined; } -export default util.createRule({ +export default createRule({ name: 'no-unsafe-enum-comparison', meta: { type: 'suggestion', @@ -53,7 +53,7 @@ export default util.createRule({ }, defaultOptions: [], create(context) { - const parserServices = util.getParserServices(context); + const parserServices = getParserServices(context); const typeChecker = parserServices.program.getTypeChecker(); return { diff --git a/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts b/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts index a5a8d3c6c4b7..45aefe49e534 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts @@ -2,15 +2,20 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; -import * as util from '../util'; -import { getThisExpression } from '../util'; +import { + createRule, + getConstrainedTypeAtLocation, + getParserServices, + getThisExpression, + isTypeAnyType, +} from '../util'; const enum State { Unsafe = 1, Safe = 2, } -export default util.createRule({ +export default createRule({ name: 'no-unsafe-member-access', meta: { type: 'problem', @@ -33,7 +38,7 @@ export default util.createRule({ }, defaultOptions: [], create(context) { - const services = util.getParserServices(context); + const services = getParserServices(context); const compilerOptions = services.program.getCompilerOptions(); const isNoImplicitThis = tsutils.isStrictCompilerOptionEnabled( compilerOptions, @@ -60,7 +65,7 @@ export default util.createRule({ } const type = services.getTypeAtLocation(node.object); - const state = util.isTypeAnyType(type) ? State.Unsafe : State.Safe; + const state = isTypeAnyType(type) ? State.Unsafe : State.Safe; stateCache.set(node, state); if (state === State.Unsafe) { @@ -75,8 +80,8 @@ export default util.createRule({ if ( thisExpression && - util.isTypeAnyType( - util.getConstrainedTypeAtLocation(services, thisExpression), + isTypeAnyType( + getConstrainedTypeAtLocation(services, thisExpression), ) ) { messageId = 'unsafeThisMemberExpression'; @@ -116,7 +121,7 @@ export default util.createRule({ const type = services.getTypeAtLocation(node); - if (util.isTypeAnyType(type)) { + if (isTypeAnyType(type)) { const propertyName = sourceCode.getText(node); context.report({ node, diff --git a/packages/eslint-plugin/src/rules/no-unsafe-return.ts b/packages/eslint-plugin/src/rules/no-unsafe-return.ts index 93a1226e9e4a..e5fb73a3ac92 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-return.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-return.ts @@ -3,10 +3,21 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../util'; -import { getThisExpression } from '../util'; - -export default util.createRule({ +import { + AnyType, + createRule, + getConstrainedTypeAtLocation, + getContextualType, + getParserServices, + getThisExpression, + isAnyOrAnyArrayTypeDiscriminated, + isTypeAnyType, + isTypeUnknownArrayType, + isTypeUnknownType, + isUnsafeAssignment, +} from '../util'; + +export default createRule({ name: 'no-unsafe-return', meta: { type: 'problem', @@ -28,7 +39,7 @@ export default util.createRule({ }, defaultOptions: [], create(context) { - const services = util.getParserServices(context); + const services = getParserServices(context); const checker = services.program.getTypeChecker(); const compilerOptions = services.program.getCompilerOptions(); const isNoImplicitThis = tsutils.isStrictCompilerOptionEnabled( @@ -66,17 +77,14 @@ export default util.createRule({ reportingNode: TSESTree.Node = returnNode, ): void { const tsNode = services.esTreeNodeToTSNodeMap.get(returnNode); - const anyType = util.isAnyOrAnyArrayTypeDiscriminated(tsNode, checker); + const anyType = isAnyOrAnyArrayTypeDiscriminated(tsNode, checker); const functionNode = getParentFunctionNode(returnNode); /* istanbul ignore if */ if (!functionNode) { return; } // function has an explicit return type, so ensure it's a safe return - const returnNodeType = util.getConstrainedTypeAtLocation( - services, - returnNode, - ); + const returnNodeType = getConstrainedTypeAtLocation(services, returnNode); const functionTSNode = services.esTreeNodeToTSNodeMap.get(functionNode); // function expressions will not have their return type modified based on receiver typing @@ -86,7 +94,7 @@ export default util.createRule({ let functionType = ts.isFunctionExpression(functionTSNode) || ts.isArrowFunction(functionTSNode) - ? util.getContextualType(checker, functionTSNode) + ? getContextualType(checker, functionTSNode) : services.getTypeAtLocation(functionNode); if (!functionType) { functionType = services.getTypeAtLocation(functionNode); @@ -102,20 +110,20 @@ export default util.createRule({ } } - if (anyType !== util.AnyType.Safe) { + if (anyType !== AnyType.Safe) { // Allow cases when the declared return type of the function is either unknown or unknown[] // and the function is returning any or any[]. for (const signature of functionType.getCallSignatures()) { const functionReturnType = signature.getReturnType(); if ( - anyType === util.AnyType.Any && - util.isTypeUnknownType(functionReturnType) + anyType === AnyType.Any && + isTypeUnknownType(functionReturnType) ) { return; } if ( - anyType === util.AnyType.AnyArray && - util.isTypeUnknownArrayType(functionReturnType, checker) + anyType === AnyType.AnyArray && + isTypeUnknownArrayType(functionReturnType, checker) ) { return; } @@ -128,8 +136,8 @@ export default util.createRule({ const thisExpression = getThisExpression(returnNode); if ( thisExpression && - util.isTypeAnyType( - util.getConstrainedTypeAtLocation(services, thisExpression), + isTypeAnyType( + getConstrainedTypeAtLocation(services, thisExpression), ) ) { messageId = 'unsafeReturnThis'; @@ -141,14 +149,14 @@ export default util.createRule({ node: reportingNode, messageId, data: { - type: anyType === util.AnyType.Any ? 'any' : 'any[]', + type: anyType === AnyType.Any ? 'any' : 'any[]', }, }); } for (const signature of functionType.getCallSignatures()) { const functionReturnType = signature.getReturnType(); - const result = util.isUnsafeAssignment( + const result = isUnsafeAssignment( returnNodeType, functionReturnType, checker, diff --git a/packages/eslint-plugin/src/rules/no-unused-expressions.ts b/packages/eslint-plugin/src/rules/no-unused-expressions.ts index d5eb14c93501..3c9652e46d8a 100644 --- a/packages/eslint-plugin/src/rules/no-unused-expressions.ts +++ b/packages/eslint-plugin/src/rules/no-unused-expressions.ts @@ -1,15 +1,19 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import type { + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +} from '../util'; +import { createRule } from '../util'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; const baseRule = getESLintCoreRule('no-unused-expressions'); -type MessageIds = util.InferMessageIdsTypeFromRule; -type Options = util.InferOptionsTypeFromRule; +type MessageIds = InferMessageIdsTypeFromRule; +type Options = InferOptionsTypeFromRule; -export default util.createRule({ +export default createRule({ name: 'no-unused-expressions', meta: { type: 'suggestion', diff --git a/packages/eslint-plugin/src/rules/no-unused-vars.ts b/packages/eslint-plugin/src/rules/no-unused-vars.ts index 7c174482dcdc..eec4e9d6ef4f 100644 --- a/packages/eslint-plugin/src/rules/no-unused-vars.ts +++ b/packages/eslint-plugin/src/rules/no-unused-vars.ts @@ -2,7 +2,15 @@ import { PatternVisitor } from '@typescript-eslint/scope-manager'; import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES, TSESLint } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { + collectUnusedVariables as _collectUnusedVariables, + createRule, + getNameLocationInGlobalDirectiveComment, + isDefinitionFile, + isFunction, + nullThrows, + NullThrowsReasons, +} from '../util'; export type MessageIds = 'unusedVar'; export type Options = [ @@ -31,7 +39,7 @@ interface TranslatedOptions { destructuredArrayIgnorePattern?: RegExp; } -export default util.createRule({ +export default createRule({ name: 'no-unused-vars', meta: { type: 'problem', @@ -197,7 +205,7 @@ export default util.createRule({ ); } - const unusedVariablesOriginal = util.collectUnusedVariables(context); + const unusedVariablesOriginal = _collectUnusedVariables(context); const unusedVariablesReturn: TSESLint.Scope.Variable[] = []; for (const variable of unusedVariablesOriginal) { // explicit global variables don't have definitions. @@ -258,7 +266,7 @@ export default util.createRule({ // if "args" option is "after-used", skip used variables if ( options.args === 'after-used' && - util.isFunction(def.name.parent) && + isFunction(def.name.parent) && !isAfterLastUsedArg(variable) ) { continue; @@ -294,7 +302,7 @@ export default util.createRule({ [ambientDeclarationSelector(AST_NODE_TYPES.Program, true)]( node: DeclarationSelectorNode, ): void { - if (!util.isDefinitionFile(filename)) { + if (!isDefinitionFile(filename)) { return; } markDeclarationChildAsUsed(node); @@ -330,9 +338,9 @@ export default util.createRule({ 'TSModuleDeclaration[declare = true] > TSModuleBlock', false, )](node: DeclarationSelectorNode): void { - const moduleDecl = util.nullThrows( + const moduleDecl = nullThrows( node.parent?.parent, - util.NullThrowsReasons.MissingParent, + NullThrowsReasons.MissingParent, ) as TSESTree.TSModuleDeclaration; // declared ambient modules with an `export =` statement will only export that one thing @@ -451,7 +459,7 @@ export default util.createRule({ context.report({ node: programNode, - loc: util.getNameLocationInGlobalDirectiveComment( + loc: getNameLocationInGlobalDirectiveComment( sourceCode, directiveComment, unusedVar.name, diff --git a/packages/eslint-plugin/src/rules/no-use-before-define.ts b/packages/eslint-plugin/src/rules/no-use-before-define.ts index 7d15cd25a19d..67f6ee524b86 100644 --- a/packages/eslint-plugin/src/rules/no-use-before-define.ts +++ b/packages/eslint-plugin/src/rules/no-use-before-define.ts @@ -2,7 +2,7 @@ import { DefinitionType } from '@typescript-eslint/scope-manager'; import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES, TSESLint } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; const SENTINEL_TYPE = /^(?:(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|CatchClause|ImportDeclaration|ExportNamedDeclaration)$/; @@ -236,7 +236,7 @@ interface Config { type Options = [Config | 'nofunc']; type MessageIds = 'noUseBeforeDefine'; -export default util.createRule({ +export default createRule({ name: 'no-use-before-define', meta: { type: 'problem', diff --git a/packages/eslint-plugin/src/rules/no-useless-constructor.ts b/packages/eslint-plugin/src/rules/no-useless-constructor.ts index 6409b8a48c34..8066674e5408 100644 --- a/packages/eslint-plugin/src/rules/no-useless-constructor.ts +++ b/packages/eslint-plugin/src/rules/no-useless-constructor.ts @@ -1,13 +1,17 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import type { + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +} from '../util'; +import { createRule } from '../util'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; const baseRule = getESLintCoreRule('no-useless-constructor'); -type Options = util.InferOptionsTypeFromRule; -type MessageIds = util.InferMessageIdsTypeFromRule; +type Options = InferOptionsTypeFromRule; +type MessageIds = InferMessageIdsTypeFromRule; /** * Check if method with accessibility is not useless @@ -41,7 +45,7 @@ function checkParams(node: TSESTree.MethodDefinition): boolean { ); } -export default util.createRule({ +export default createRule({ name: 'no-useless-constructor', meta: { type: 'problem', diff --git a/packages/eslint-plugin/src/rules/no-useless-empty-export.ts b/packages/eslint-plugin/src/rules/no-useless-empty-export.ts index 7c2b8ca3ea22..5d6b091e2abb 100644 --- a/packages/eslint-plugin/src/rules/no-useless-empty-export.ts +++ b/packages/eslint-plugin/src/rules/no-useless-empty-export.ts @@ -1,7 +1,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; function isEmptyExport( node: TSESTree.Node, @@ -23,7 +23,7 @@ const exportOrImportNodeTypes = new Set([ AST_NODE_TYPES.TSImportEqualsDeclaration, ]); -export default util.createRule({ +export default createRule({ name: 'no-useless-empty-export', meta: { docs: { diff --git a/packages/eslint-plugin/src/rules/no-var-requires.ts b/packages/eslint-plugin/src/rules/no-var-requires.ts index b8655d049d30..61a300678215 100644 --- a/packages/eslint-plugin/src/rules/no-var-requires.ts +++ b/packages/eslint-plugin/src/rules/no-var-requires.ts @@ -1,12 +1,12 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES, ASTUtils } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; type Options = []; type MessageIds = 'noVarReqs'; -export default util.createRule({ +export default createRule({ name: 'no-var-requires', meta: { type: 'problem', diff --git a/packages/eslint-plugin/src/rules/non-nullable-type-assertion-style.ts b/packages/eslint-plugin/src/rules/non-nullable-type-assertion-style.ts index 4523715d1fbd..c9dcdf8fee9a 100644 --- a/packages/eslint-plugin/src/rules/non-nullable-type-assertion-style.ts +++ b/packages/eslint-plugin/src/rules/non-nullable-type-assertion-style.ts @@ -3,9 +3,14 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../util'; - -export default util.createRule({ +import { + createRule, + getOperatorPrecedence, + getParserServices, + OperatorPrecedence, +} from '../util'; + +export default createRule({ name: 'non-nullable-type-assertion-style', meta: { docs: { @@ -24,7 +29,7 @@ export default util.createRule({ defaultOptions: [], create(context) { - const services = util.getParserServices(context); + const services = getParserServices(context); const sourceCode = context.getSourceCode(); const getTypesIfNotLoose = (node: TSESTree.Node): ts.Type[] | undefined => { @@ -117,10 +122,10 @@ export default util.createRule({ const expressionSourceCode = sourceCode.getText(node.expression); const higherPrecedenceThanUnary = - util.getOperatorPrecedence( + getOperatorPrecedence( services.esTreeNodeToTSNodeMap.get(node.expression).kind, ts.SyntaxKind.Unknown, - ) > util.OperatorPrecedence.Unary; + ) > OperatorPrecedence.Unary; context.report({ fix(fixer) { diff --git a/packages/eslint-plugin/src/rules/padding-line-between-statements.ts b/packages/eslint-plugin/src/rules/padding-line-between-statements.ts index d2342adc8699..255ceb0c712a 100644 --- a/packages/eslint-plugin/src/rules/padding-line-between-statements.ts +++ b/packages/eslint-plugin/src/rules/padding-line-between-statements.ts @@ -1,7 +1,15 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { + createRule, + isClosingBraceToken, + isFunction, + isNotSemicolonToken, + isParenthesized, + isSemicolonToken, + isTokenOnSameLine, +} from '../util'; /** * This rule is a replica of padding-line-between-statements. @@ -141,7 +149,7 @@ function isIIFEStatement(node: TSESTree.Node): boolean { while (node.type === AST_NODE_TYPES.SequenceExpression) { node = node.expressions[node.expressions.length - 1]; } - return util.isFunction(node); + return isFunction(node); } } return false; @@ -201,9 +209,9 @@ function isBlockLikeStatement( } // Checks the last token is a closing brace of blocks. - const lastToken = sourceCode.getLastToken(node, util.isNotSemicolonToken); + const lastToken = sourceCode.getLastToken(node, isNotSemicolonToken); const belongingNode = - lastToken && util.isClosingBraceToken(lastToken) + lastToken && isClosingBraceToken(lastToken) ? sourceCode.getNodeByRangeIndex(lastToken.range[0]) : null; @@ -228,10 +236,10 @@ function isDirective( node.type === AST_NODE_TYPES.ExpressionStatement && (node.parent?.type === AST_NODE_TYPES.Program || (node.parent?.type === AST_NODE_TYPES.BlockStatement && - util.isFunction(node.parent.parent))) && + isFunction(node.parent.parent))) && node.expression.type === AST_NODE_TYPES.Literal && typeof node.expression.value === 'string' && - !util.isParenthesized(node.expression, sourceCode) + !isParenthesized(node.expression, sourceCode) ); } @@ -332,7 +340,7 @@ function getActualLastToken( prevToken && nextToken && prevToken.range[0] >= node.range[0] && - util.isSemicolonToken(semiToken) && + isSemicolonToken(semiToken) && semiToken.loc.start.line !== prevToken.loc.end.line && semiToken.loc.end.line === nextToken.loc.start.line; @@ -464,14 +472,14 @@ function verifyForAlways( * @private */ filter(token) { - if (util.isTokenOnSameLine(prevToken, token)) { + if (isTokenOnSameLine(prevToken, token)) { prevToken = token; return false; } return true; }, })! || nextNode; - const insertText = util.isTokenOnSameLine(prevToken, nextToken) + const insertText = isTokenOnSameLine(prevToken, nextToken) ? '\n\n' : '\n'; @@ -581,7 +589,7 @@ const StatementTypes: Record = { // Rule Definition //------------------------------------------------------------------------------ -export default util.createRule({ +export default createRule({ name: 'padding-line-between-statements', meta: { type: 'layout', diff --git a/packages/eslint-plugin/src/rules/parameter-properties.ts b/packages/eslint-plugin/src/rules/parameter-properties.ts index 8ee987caaf3b..1d7d5d7ccadb 100644 --- a/packages/eslint-plugin/src/rules/parameter-properties.ts +++ b/packages/eslint-plugin/src/rules/parameter-properties.ts @@ -1,7 +1,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; type Modifier = | 'private readonly' @@ -23,7 +23,7 @@ type Options = [ type MessageIds = 'preferClassProperty' | 'preferParameterProperty'; -export default util.createRule({ +export default createRule({ name: 'parameter-properties', meta: { type: 'problem', diff --git a/packages/eslint-plugin/src/rules/prefer-as-const.ts b/packages/eslint-plugin/src/rules/prefer-as-const.ts index 5372e0ed3b0e..f13430b59fed 100644 --- a/packages/eslint-plugin/src/rules/prefer-as-const.ts +++ b/packages/eslint-plugin/src/rules/prefer-as-const.ts @@ -1,9 +1,9 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; -export default util.createRule({ +export default createRule({ name: 'prefer-as-const', meta: { type: 'suggestion', diff --git a/packages/eslint-plugin/src/rules/prefer-enum-initializers.ts b/packages/eslint-plugin/src/rules/prefer-enum-initializers.ts index 50ce4a7de6b9..a1df9525e801 100644 --- a/packages/eslint-plugin/src/rules/prefer-enum-initializers.ts +++ b/packages/eslint-plugin/src/rules/prefer-enum-initializers.ts @@ -1,10 +1,10 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; type MessageIds = 'defineInitializer' | 'defineInitializerSuggestion'; -export default util.createRule<[], MessageIds>({ +export default createRule<[], MessageIds>({ name: 'prefer-enum-initializers', meta: { type: 'suggestion', diff --git a/packages/eslint-plugin/src/rules/prefer-for-of.ts b/packages/eslint-plugin/src/rules/prefer-for-of.ts index d326b1114fd8..a7ee36868bd9 100644 --- a/packages/eslint-plugin/src/rules/prefer-for-of.ts +++ b/packages/eslint-plugin/src/rules/prefer-for-of.ts @@ -1,9 +1,9 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; -export default util.createRule({ +export default createRule({ name: 'prefer-for-of', meta: { type: 'suggestion', diff --git a/packages/eslint-plugin/src/rules/prefer-function-type.ts b/packages/eslint-plugin/src/rules/prefer-function-type.ts index a861104ce869..9655093236eb 100644 --- a/packages/eslint-plugin/src/rules/prefer-function-type.ts +++ b/packages/eslint-plugin/src/rules/prefer-function-type.ts @@ -1,14 +1,14 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; export const phrases = { [AST_NODE_TYPES.TSTypeLiteral]: 'Type literal', [AST_NODE_TYPES.TSInterfaceDeclaration]: 'Interface', } as const; -export default util.createRule({ +export default createRule({ name: 'prefer-function-type', meta: { docs: { diff --git a/packages/eslint-plugin/src/rules/prefer-namespace-keyword.ts b/packages/eslint-plugin/src/rules/prefer-namespace-keyword.ts index 1aa0919d04b3..0c945a6b29d5 100644 --- a/packages/eslint-plugin/src/rules/prefer-namespace-keyword.ts +++ b/packages/eslint-plugin/src/rules/prefer-namespace-keyword.ts @@ -1,8 +1,8 @@ import { AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; -export default util.createRule({ +export default createRule({ name: 'prefer-namespace-keyword', meta: { type: 'suggestion', diff --git a/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts b/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts index d4f790770a51..e9e340f93240 100644 --- a/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts +++ b/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts @@ -3,7 +3,18 @@ import { AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../util'; +import { + createRule, + getParserServices, + getTypeFlags, + isLogicalOrOperator, + isNodeEqual, + isNullableType, + isNullLiteral, + isUndefinedIdentifier, + nullThrows, + NullThrowsReasons, +} from '../util'; export type Options = [ { @@ -28,7 +39,7 @@ export type MessageIds = | 'preferNullishOverTernary' | 'suggestNullish'; -export default util.createRule({ +export default createRule({ name: 'prefer-nullish-coalescing', meta: { type: 'suggestion', @@ -112,7 +123,7 @@ export default util.createRule({ }, ], ) { - const parserServices = util.getParserServices(context); + const parserServices = getParserServices(context); const compilerOptions = parserServices.program.getCompilerOptions(); const sourceCode = context.getSourceCode(); const checker = parserServices.program.getTypeChecker(); @@ -208,18 +219,18 @@ export default util.createRule({ // we check that the test only contains null, undefined and the identifier for (const testNode of nodesInsideTestExpression) { - if (util.isNullLiteral(testNode)) { + if (isNullLiteral(testNode)) { hasNullCheck = true; - } else if (util.isUndefinedIdentifier(testNode)) { + } else if (isUndefinedIdentifier(testNode)) { hasUndefinedCheck = true; } else if ( (operator === '!==' || operator === '!=') && - util.isNodeEqual(testNode, node.consequent) + isNodeEqual(testNode, node.consequent) ) { identifier = testNode; } else if ( (operator === '===' || operator === '==') && - util.isNodeEqual(testNode, node.alternate) + isNodeEqual(testNode, node.alternate) ) { identifier = testNode; } else { @@ -244,7 +255,7 @@ export default util.createRule({ const tsNode = parserServices.esTreeNodeToTSNodeMap.get(identifier); const type = checker.getTypeAtLocation(tsNode); - const flags = util.getTypeFlags(type); + const flags = getTypeFlags(type); if (flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) { return false; @@ -297,7 +308,7 @@ export default util.createRule({ ): void { const tsNode = parserServices.esTreeNodeToTSNodeMap.get(node); const type = checker.getTypeAtLocation(tsNode.left); - const isNullish = util.isNullableType(type, { allowUndefined: true }); + const isNullish = isNullableType(type, { allowUndefined: true }); if (!isNullish) { return; } @@ -333,24 +344,24 @@ export default util.createRule({ return; } - const barBarOperator = util.nullThrows( + const barBarOperator = nullThrows( sourceCode.getTokenAfter( node.left, token => token.type === AST_TOKEN_TYPES.Punctuator && token.value === node.operator, ), - util.NullThrowsReasons.MissingToken('operator', node.type), + NullThrowsReasons.MissingToken('operator', node.type), ); function* fix( fixer: TSESLint.RuleFixer, ): IterableIterator { - if (node.parent && util.isLogicalOrOperator(node.parent)) { + if (node.parent && isLogicalOrOperator(node.parent)) { // '&&' and '??' operations cannot be mixed without parentheses (e.g. a && b ?? c) if ( node.left.type === AST_NODE_TYPES.LogicalExpression && - !util.isLogicalOrOperator(node.left.left) + !isLogicalOrOperator(node.left.left) ) { yield fixer.insertTextBefore(node.left.right, '('); } else { diff --git a/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/analyzeChain.ts b/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/analyzeChain.ts index 27c8941af7ea..dea7b6f490b7 100644 --- a/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/analyzeChain.ts +++ b/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/analyzeChain.ts @@ -12,7 +12,14 @@ import type { import { unionTypeParts } from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../../util'; +import { + getOperatorPrecedenceForNode, + isOpeningParenToken, + isTypeFlagSet, + nullThrows, + NullThrowsReasons, + OperatorPrecedence, +} from '../../util'; import { compareNodes, NodeComparisonResult } from './compareNodes'; import type { ValidOperand } from './gatherLogicalOperands'; import { NullishComparisonType } from './gatherLogicalOperands'; @@ -29,7 +36,7 @@ function includesType( const typeFlag = typeFlagIn | ts.TypeFlags.Any | ts.TypeFlags.Unknown; const types = unionTypeParts(parserServices.getTypeAtLocation(node)); for (const type of types) { - if (util.isTypeFlagSet(type, typeFlag)) { + if (isTypeFlagSet(type, typeFlag)) { return true; } } @@ -306,8 +313,8 @@ function getFixer( } } if ( - part.precedence !== util.OperatorPrecedence.Invalid && - part.precedence < util.OperatorPrecedence.Member + part.precedence !== OperatorPrecedence.Invalid && + part.precedence < OperatorPrecedence.Member ) { str += `(${part.text})`; } else { @@ -362,7 +369,7 @@ function getFixer( interface FlattenedChain { nonNull: boolean; optional: boolean; - precedence: util.OperatorPrecedence; + precedence: OperatorPrecedence; requiresDot: boolean; text: string; } @@ -376,23 +383,17 @@ function getFixer( case AST_NODE_TYPES.CallExpression: { const argumentsText = (() => { - const closingParenToken = util.nullThrows( + const closingParenToken = nullThrows( sourceCode.getLastToken(node), - util.NullThrowsReasons.MissingToken( - 'closing parenthesis', - node.type, - ), + NullThrowsReasons.MissingToken('closing parenthesis', node.type), ); - const openingParenToken = util.nullThrows( + const openingParenToken = nullThrows( sourceCode.getFirstTokenBetween( node.typeArguments ?? node.callee, closingParenToken, - util.isOpeningParenToken, - ), - util.NullThrowsReasons.MissingToken( - 'opening parenthesis', - node.type, + isOpeningParenToken, ), + NullThrowsReasons.MissingToken('opening parenthesis', node.type), ); return sourceCode.text.substring( openingParenToken.range[0], @@ -414,7 +415,7 @@ function getFixer( nonNull: false, optional: node.optional, // no precedence for this - precedence: util.OperatorPrecedence.Invalid, + precedence: OperatorPrecedence.Invalid, requiresDot: false, text: typeArgumentsText + argumentsText, }, @@ -430,8 +431,8 @@ function getFixer( optional: node.optional, precedence: node.computed ? // computed is already wrapped in [] so no need to wrap in () as well - util.OperatorPrecedence.Invalid - : util.getOperatorPrecedenceForNode(node.property), + OperatorPrecedence.Invalid + : getOperatorPrecedenceForNode(node.property), requiresDot: !node.computed, text: node.computed ? `[${propertyText}]` : propertyText, }, @@ -446,7 +447,7 @@ function getFixer( { nonNull: false, optional: false, - precedence: util.getOperatorPrecedenceForNode(node), + precedence: getOperatorPrecedenceForNode(node), requiresDot: false, text: sourceCode.getText(node), }, diff --git a/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/gatherLogicalOperands.ts b/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/gatherLogicalOperands.ts index 4b033fded576..73ce6d9255aa 100644 --- a/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/gatherLogicalOperands.ts +++ b/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/gatherLogicalOperands.ts @@ -12,7 +12,7 @@ import { } from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../../util'; +import { isTypeFlagSet } from '../../util'; import type { PreferOptionalChainOptions } from './PreferOptionalChainOptions'; const enum ComparisonValueType { @@ -94,7 +94,7 @@ function isValidFalseBooleanCheckType( } if (options.requireNullish === true) { - return types.some(t => util.isTypeFlagSet(t, NULLISH_FLAGS)); + return types.some(t => isTypeFlagSet(t, NULLISH_FLAGS)); } let allowedFlags = NULLISH_FLAGS | ts.TypeFlags.Object; @@ -116,7 +116,7 @@ function isValidFalseBooleanCheckType( if (options.checkBigInt === true) { allowedFlags |= ts.TypeFlags.BigIntLike; } - return types.every(t => util.isTypeFlagSet(t, allowedFlags)); + return types.every(t => isTypeFlagSet(t, allowedFlags)); } export function gatherLogicalOperands( diff --git a/packages/eslint-plugin/src/rules/prefer-optional-chain.ts b/packages/eslint-plugin/src/rules/prefer-optional-chain.ts index f88e37cb7371..a1e9bb95f22d 100644 --- a/packages/eslint-plugin/src/rules/prefer-optional-chain.ts +++ b/packages/eslint-plugin/src/rules/prefer-optional-chain.ts @@ -3,7 +3,12 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import type { RuleFix } from '@typescript-eslint/utils/ts-eslint'; import * as ts from 'typescript'; -import * as util from '../util'; +import { + createRule, + getOperatorPrecedence, + getParserServices, + OperatorPrecedence, +} from '../util'; import { analyzeChain } from './prefer-optional-chain-utils/analyzeChain'; import type { ValidOperand } from './prefer-optional-chain-utils/gatherLogicalOperands'; import { @@ -15,7 +20,7 @@ import type { PreferOptionalChainOptions, } from './prefer-optional-chain-utils/PreferOptionalChainOptions'; -export default util.createRule< +export default createRule< [PreferOptionalChainOptions], PreferOptionalChainMessageIds >({ @@ -98,7 +103,7 @@ export default util.createRule< ], create(context, [options]) { const sourceCode = context.getSourceCode(); - const parserServices = util.getParserServices(context); + const parserServices = getParserServices(context); const seenLogicals = new Set(); @@ -131,12 +136,12 @@ export default util.createRule< const operator = ts.isBinaryExpression(logicalTsNode) ? logicalTsNode.operatorToken.kind : ts.SyntaxKind.Unknown; - const leftPrecedence = util.getOperatorPrecedence( + const leftPrecedence = getOperatorPrecedence( leftTsNode.kind, operator, ); - return leftPrecedence < util.OperatorPrecedence.LeftHandSide; + return leftPrecedence < OperatorPrecedence.LeftHandSide; } context.report({ node: parentNode, diff --git a/packages/eslint-plugin/src/rules/prefer-readonly-parameter-types.ts b/packages/eslint-plugin/src/rules/prefer-readonly-parameter-types.ts index e22ab9885e4a..72b73a883520 100644 --- a/packages/eslint-plugin/src/rules/prefer-readonly-parameter-types.ts +++ b/packages/eslint-plugin/src/rules/prefer-readonly-parameter-types.ts @@ -1,11 +1,18 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import type { TypeOrValueSpecifier } from '../util'; +import { + createRule, + getParserServices, + isTypeReadonly, + readonlynessOptionsDefaults, + readonlynessOptionsSchema, +} from '../util'; type Options = [ { - allow?: util.TypeOrValueSpecifier[]; + allow?: TypeOrValueSpecifier[]; checkParameterProperties?: boolean; ignoreInferredTypes?: boolean; treatMethodsAsReadonly?: boolean; @@ -13,7 +20,7 @@ type Options = [ ]; type MessageIds = 'shouldBeReadonly'; -export default util.createRule({ +export default createRule({ name: 'prefer-readonly-parameter-types', meta: { type: 'suggestion', @@ -27,7 +34,7 @@ export default util.createRule({ type: 'object', additionalProperties: false, properties: { - allow: util.readonlynessOptionsSchema.properties.allow, + allow: readonlynessOptionsSchema.properties.allow, checkParameterProperties: { type: 'boolean', }, @@ -35,7 +42,7 @@ export default util.createRule({ type: 'boolean', }, treatMethodsAsReadonly: - util.readonlynessOptionsSchema.properties.treatMethodsAsReadonly, + readonlynessOptionsSchema.properties.treatMethodsAsReadonly, }, }, ], @@ -45,11 +52,11 @@ export default util.createRule({ }, defaultOptions: [ { - allow: util.readonlynessOptionsDefaults.allow, + allow: readonlynessOptionsDefaults.allow, checkParameterProperties: true, ignoreInferredTypes: false, treatMethodsAsReadonly: - util.readonlynessOptionsDefaults.treatMethodsAsReadonly, + readonlynessOptionsDefaults.treatMethodsAsReadonly, }, ], create( @@ -63,7 +70,7 @@ export default util.createRule({ }, ], ) { - const services = util.getParserServices(context); + const services = getParserServices(context); return { [[ @@ -106,7 +113,7 @@ export default util.createRule({ } const type = services.getTypeAtLocation(actualParam); - const isReadOnly = util.isTypeReadonly(services.program, type, { + const isReadOnly = isTypeReadonly(services.program, type, { treatMethodsAsReadonly: treatMethodsAsReadonly!, allow, }); diff --git a/packages/eslint-plugin/src/rules/prefer-readonly.ts b/packages/eslint-plugin/src/rules/prefer-readonly.ts index 713a703a56f0..f5fe608bb15b 100644 --- a/packages/eslint-plugin/src/rules/prefer-readonly.ts +++ b/packages/eslint-plugin/src/rules/prefer-readonly.ts @@ -3,8 +3,7 @@ import { AST_NODE_TYPES, ASTUtils } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../util'; -import { typeIsOrHasBaseType } from '../util'; +import { createRule, getParserServices, typeIsOrHasBaseType } from '../util'; type MessageIds = 'preferReadonly'; type Options = [ @@ -20,7 +19,7 @@ const functionScopeBoundaries = [ AST_NODE_TYPES.MethodDefinition, ].join(', '); -export default util.createRule({ +export default createRule({ name: 'prefer-readonly', meta: { docs: { @@ -48,7 +47,7 @@ export default util.createRule({ }, defaultOptions: [{ onlyInlineLambdas: false }], create(context, [{ onlyInlineLambdas }]) { - const services = util.getParserServices(context); + const services = getParserServices(context); const checker = services.program.getTypeChecker(); const classScopeStack: ClassScope[] = []; diff --git a/packages/eslint-plugin/src/rules/prefer-reduce-type-parameter.ts b/packages/eslint-plugin/src/rules/prefer-reduce-type-parameter.ts index 8c966eeea97d..e1f3ce4783c1 100644 --- a/packages/eslint-plugin/src/rules/prefer-reduce-type-parameter.ts +++ b/packages/eslint-plugin/src/rules/prefer-reduce-type-parameter.ts @@ -1,7 +1,12 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { + createRule, + getConstrainedTypeAtLocation, + getParserServices, + isTypeAssertion, +} from '../util'; type MemberExpressionWithCallExpressionParent = TSESTree.MemberExpression & { parent: TSESTree.CallExpression; @@ -24,7 +29,7 @@ const getMemberExpressionName = ( return null; }; -export default util.createRule({ +export default createRule({ name: 'prefer-reduce-type-parameter', meta: { type: 'problem', @@ -43,7 +48,7 @@ export default util.createRule({ }, defaultOptions: [], create(context) { - const services = util.getParserServices(context); + const services = getParserServices(context); const checker = services.program.getTypeChecker(); return { @@ -56,15 +61,12 @@ export default util.createRule({ const [, secondArg] = callee.parent.arguments; - if ( - callee.parent.arguments.length < 2 || - !util.isTypeAssertion(secondArg) - ) { + if (callee.parent.arguments.length < 2 || !isTypeAssertion(secondArg)) { return; } // Get the symbol of the `reduce` method. - const calleeObjType = util.getConstrainedTypeAtLocation( + const calleeObjType = getConstrainedTypeAtLocation( services, callee.object, ); diff --git a/packages/eslint-plugin/src/rules/prefer-ts-expect-error.ts b/packages/eslint-plugin/src/rules/prefer-ts-expect-error.ts index 8ef1c7ad9273..d388be9ec955 100644 --- a/packages/eslint-plugin/src/rules/prefer-ts-expect-error.ts +++ b/packages/eslint-plugin/src/rules/prefer-ts-expect-error.ts @@ -2,11 +2,11 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_TOKEN_TYPES } from '@typescript-eslint/utils'; import type { RuleFix, RuleFixer } from '@typescript-eslint/utils/ts-eslint'; -import * as util from '../util'; +import { createRule } from '../util'; type MessageIds = 'preferExpectErrorComment'; -export default util.createRule<[], MessageIds>({ +export default createRule<[], MessageIds>({ name: 'prefer-ts-expect-error', meta: { type: 'problem', diff --git a/packages/eslint-plugin/src/rules/promise-function-async.ts b/packages/eslint-plugin/src/rules/promise-function-async.ts index ba671d5929b0..334f8d008f4b 100644 --- a/packages/eslint-plugin/src/rules/promise-function-async.ts +++ b/packages/eslint-plugin/src/rules/promise-function-async.ts @@ -2,7 +2,13 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/utils'; import * as ts from 'typescript'; -import * as util from '../util'; +import { + containsAllTypesByName, + createRule, + getFunctionHeadLoc, + getParserServices, + isTypeFlagSet, +} from '../util'; type Options = [ { @@ -16,7 +22,7 @@ type Options = [ ]; type MessageIds = 'missingAsync'; -export default util.createRule({ +export default createRule({ name: 'promise-function-async', meta: { type: 'suggestion', @@ -90,7 +96,7 @@ export default util.createRule({ 'Promise', ...allowedPromiseNames!, ]); - const services = util.getParserServices(context); + const services = getParserServices(context); const checker = services.program.getTypeChecker(); const sourceCode = context.getSourceCode(); @@ -107,7 +113,7 @@ export default util.createRule({ const returnType = checker.getReturnTypeOfSignature(signatures[0]); if ( - !util.containsAllTypesByName( + !containsAllTypesByName( returnType, allowAny!, allAllowedPromiseNames, @@ -133,21 +139,19 @@ export default util.createRule({ return; } - if ( - util.isTypeFlagSet(returnType, ts.TypeFlags.Any | ts.TypeFlags.Unknown) - ) { + if (isTypeFlagSet(returnType, ts.TypeFlags.Any | ts.TypeFlags.Unknown)) { // Report without auto fixer because the return type is unknown return context.report({ messageId: 'missingAsync', node, - loc: util.getFunctionHeadLoc(node, sourceCode), + loc: getFunctionHeadLoc(node, sourceCode), }); } context.report({ messageId: 'missingAsync', node, - loc: util.getFunctionHeadLoc(node, sourceCode), + loc: getFunctionHeadLoc(node, sourceCode), fix: fixer => { if ( node.parent.type === AST_NODE_TYPES.MethodDefinition || diff --git a/packages/eslint-plugin/src/rules/quotes.ts b/packages/eslint-plugin/src/rules/quotes.ts index b5f2f7f57b03..74c41d6130d0 100644 --- a/packages/eslint-plugin/src/rules/quotes.ts +++ b/packages/eslint-plugin/src/rules/quotes.ts @@ -1,15 +1,19 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import type { + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +} from '../util'; +import { createRule } from '../util'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; const baseRule = getESLintCoreRule('quotes'); -export type Options = util.InferOptionsTypeFromRule; -export type MessageIds = util.InferMessageIdsTypeFromRule; +export type Options = InferOptionsTypeFromRule; +export type MessageIds = InferMessageIdsTypeFromRule; -export default util.createRule({ +export default createRule({ name: 'quotes', meta: { type: 'layout', diff --git a/packages/eslint-plugin/src/rules/require-array-sort-compare.ts b/packages/eslint-plugin/src/rules/require-array-sort-compare.ts index a3617894ee79..4097362bb247 100644 --- a/packages/eslint-plugin/src/rules/require-array-sort-compare.ts +++ b/packages/eslint-plugin/src/rules/require-array-sort-compare.ts @@ -1,6 +1,13 @@ import type { TSESTree } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { + createRule, + getConstrainedTypeAtLocation, + getParserServices, + getTypeArguments, + getTypeName, + isTypeArrayTypeOrUnionOfArrayTypes, +} from '../util'; export type Options = [ { @@ -9,7 +16,7 @@ export type Options = [ ]; export type MessageIds = 'requireCompare'; -export default util.createRule({ +export default createRule({ name: 'require-array-sort-compare', defaultOptions: [ { @@ -43,7 +50,7 @@ export default util.createRule({ }, create(context, [options]) { - const services = util.getParserServices(context); + const services = getParserServices(context); const checker = services.program.getTypeChecker(); /** @@ -54,10 +61,8 @@ export default util.createRule({ const type = services.getTypeAtLocation(node); if (checker.isArrayType(type) || checker.isTupleType(type)) { - const typeArgs = util.getTypeArguments(type, checker); - return typeArgs.every( - arg => util.getTypeName(checker, arg) === 'string', - ); + const typeArgs = getTypeArguments(type, checker); + return typeArgs.every(arg => getTypeName(checker, arg) === 'string'); } return false; } @@ -66,7 +71,7 @@ export default util.createRule({ "CallExpression[arguments.length=0] > MemberExpression[property.name='sort'][computed=false]"( callee: TSESTree.MemberExpression, ): void { - const calleeObjType = util.getConstrainedTypeAtLocation( + const calleeObjType = getConstrainedTypeAtLocation( services, callee.object, ); @@ -75,7 +80,7 @@ export default util.createRule({ return; } - if (util.isTypeArrayTypeOrUnionOfArrayTypes(calleeObjType, checker)) { + if (isTypeArrayTypeOrUnionOfArrayTypes(calleeObjType, checker)) { context.report({ node: callee.parent, messageId: 'requireCompare' }); } }, diff --git a/packages/eslint-plugin/src/rules/require-await.ts b/packages/eslint-plugin/src/rules/require-await.ts index de3624ecbf7d..86049b04e587 100644 --- a/packages/eslint-plugin/src/rules/require-await.ts +++ b/packages/eslint-plugin/src/rules/require-await.ts @@ -3,7 +3,16 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import type * as ts from 'typescript'; -import * as util from '../util'; +import { + createRule, + getFunctionNameWithKind, + getParserServices, + isArrowToken, + isOpeningParenToken, + nullThrows, + NullThrowsReasons, + upperCaseFirst, +} from '../util'; interface ScopeInfo { upper: ScopeInfo | null; @@ -17,7 +26,7 @@ type FunctionNode = | TSESTree.FunctionDeclaration | TSESTree.FunctionExpression; -export default util.createRule({ +export default createRule({ name: 'require-await', meta: { type: 'suggestion', @@ -34,7 +43,7 @@ export default util.createRule({ }, defaultOptions: [], create(context) { - const services = util.getParserServices(context); + const services = getParserServices(context); const checker = services.program.getTypeChecker(); const sourceCode = context.getSourceCode(); @@ -74,7 +83,7 @@ export default util.createRule({ loc: getFunctionHeadLoc(node, sourceCode), messageId: 'missingAwait', data: { - name: util.upperCaseFirst(util.getFunctionNameWithKind(node)), + name: upperCaseFirst(getFunctionNameWithKind(node)), }, }); } @@ -186,11 +195,11 @@ function getOpeningParenOfParams( node: FunctionNode, sourceCode: TSESLint.SourceCode, ): TSESTree.Token { - return util.nullThrows( + return nullThrows( node.id - ? sourceCode.getTokenAfter(node.id, util.isOpeningParenToken) - : sourceCode.getFirstToken(node, util.isOpeningParenToken), - util.NullThrowsReasons.MissingToken('(', node.type), + ? sourceCode.getTokenAfter(node.id, isOpeningParenToken) + : sourceCode.getFirstToken(node, isOpeningParenToken), + NullThrowsReasons.MissingToken('(', node.type), ); } @@ -202,17 +211,14 @@ function getFunctionHeadLoc( node: FunctionNode, sourceCode: TSESLint.SourceCode, ): TSESTree.SourceLocation { - const parent = util.nullThrows( - node.parent, - util.NullThrowsReasons.MissingParent, - ); + const parent = nullThrows(node.parent, NullThrowsReasons.MissingParent); let start = null; let end = null; if (node.type === AST_NODE_TYPES.ArrowFunctionExpression) { - const arrowToken = util.nullThrows( - sourceCode.getTokenBefore(node.body, util.isArrowToken), - util.NullThrowsReasons.MissingToken('=>', node.type), + const arrowToken = nullThrows( + sourceCode.getTokenBefore(node.body, isArrowToken), + NullThrowsReasons.MissingToken('=>', node.type), ); start = arrowToken.loc.start; diff --git a/packages/eslint-plugin/src/rules/restrict-plus-operands.ts b/packages/eslint-plugin/src/rules/restrict-plus-operands.ts index 6d2cc2222eaa..9e17fa486b52 100644 --- a/packages/eslint-plugin/src/rules/restrict-plus-operands.ts +++ b/packages/eslint-plugin/src/rules/restrict-plus-operands.ts @@ -2,7 +2,14 @@ import type { TSESTree } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../util'; +import { + createRule, + getConstrainedTypeAtLocation, + getParserServices, + getTypeName, + isTypeAnyType, + isTypeFlagSet, +} from '../util'; type Options = [ { @@ -17,7 +24,7 @@ type Options = [ type MessageIds = 'bigintAndNumber' | 'invalid' | 'mismatched'; -export default util.createRule({ +export default createRule({ name: 'restrict-plus-operands', meta: { type: 'problem', @@ -93,7 +100,7 @@ export default util.createRule({ }, ], ) { - const services = util.getParserServices(context); + const services = getParserServices(context); const typeChecker = services.program.getTypeChecker(); const stringLikes = [ @@ -111,7 +118,7 @@ export default util.createRule({ function getTypeConstrained(node: TSESTree.Node): ts.Type { return typeChecker.getBaseTypeOfLiteralType( - util.getConstrainedTypeAtLocation(services, node), + getConstrainedTypeAtLocation(services, node), ); } @@ -150,10 +157,7 @@ export default util.createRule({ (!allowBoolean && isTypeFlagSetInUnion(baseType, ts.TypeFlags.BooleanLike)) || (!allowNullish && - util.isTypeFlagSet( - baseType, - ts.TypeFlags.Null | ts.TypeFlags.Undefined, - )) + isTypeFlagSet(baseType, ts.TypeFlags.Null | ts.TypeFlags.Undefined)) ) { context.report({ data: { @@ -169,12 +173,12 @@ export default util.createRule({ // RegExps also contain ts.TypeFlags.Any & ts.TypeFlags.Object for (const subBaseType of tsutils.unionTypeParts(baseType)) { - const typeName = util.getTypeName(typeChecker, subBaseType); + const typeName = getTypeName(typeChecker, subBaseType); if ( typeName === 'RegExp' ? !allowRegExp || tsutils.isTypeFlagSet(otherType, ts.TypeFlags.NumberLike) - : (!allowAny && util.isTypeAnyType(subBaseType)) || + : (!allowAny && isTypeAnyType(subBaseType)) || isDeeplyObjectType(subBaseType) ) { context.report({ diff --git a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts index 5da963a8219e..63a0b171306a 100644 --- a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts +++ b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts @@ -2,7 +2,15 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as ts from 'typescript'; -import * as util from '../util'; +import { + createRule, + getConstrainedTypeAtLocation, + getParserServices, + getTypeName, + isTypeAnyType, + isTypeFlagSet, + isTypeNeverType, +} from '../util'; type Options = [ { @@ -17,7 +25,7 @@ type Options = [ type MessageId = 'invalidType'; -export default util.createRule({ +export default createRule({ name: 'restrict-template-expressions', meta: { type: 'problem', @@ -79,47 +87,44 @@ export default util.createRule({ }, ], create(context, [options]) { - const services = util.getParserServices(context); + const services = getParserServices(context); const checker = services.program.getTypeChecker(); function isUnderlyingTypePrimitive(type: ts.Type): boolean { - if (util.isTypeFlagSet(type, ts.TypeFlags.StringLike)) { + if (isTypeFlagSet(type, ts.TypeFlags.StringLike)) { return true; } if ( options.allowNumber && - util.isTypeFlagSet( - type, - ts.TypeFlags.NumberLike | ts.TypeFlags.BigIntLike, - ) + isTypeFlagSet(type, ts.TypeFlags.NumberLike | ts.TypeFlags.BigIntLike) ) { return true; } if ( options.allowBoolean && - util.isTypeFlagSet(type, ts.TypeFlags.BooleanLike) + isTypeFlagSet(type, ts.TypeFlags.BooleanLike) ) { return true; } - if (options.allowAny && util.isTypeAnyType(type)) { + if (options.allowAny && isTypeAnyType(type)) { return true; } - if (options.allowRegExp && util.getTypeName(checker, type) === 'RegExp') { + if (options.allowRegExp && getTypeName(checker, type) === 'RegExp') { return true; } if ( options.allowNullish && - util.isTypeFlagSet(type, ts.TypeFlags.Null | ts.TypeFlags.Undefined) + isTypeFlagSet(type, ts.TypeFlags.Null | ts.TypeFlags.Undefined) ) { return true; } - if (options.allowNever && util.isTypeNeverType(type)) { + if (options.allowNever && isTypeNeverType(type)) { return true; } @@ -134,7 +139,7 @@ export default util.createRule({ } for (const expression of node.expressions) { - const expressionType = util.getConstrainedTypeAtLocation( + const expressionType = getConstrainedTypeAtLocation( services, expression, ); diff --git a/packages/eslint-plugin/src/rules/return-await.ts b/packages/eslint-plugin/src/rules/return-await.ts index ed40fb967d95..df0810d41c05 100644 --- a/packages/eslint-plugin/src/rules/return-await.ts +++ b/packages/eslint-plugin/src/rules/return-await.ts @@ -3,7 +3,14 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../util'; +import { + createRule, + getParserServices, + isAwaitExpression, + isAwaitKeyword, + isTypeAnyType, + isTypeUnknownType, +} from '../util'; import { getOperatorPrecedence } from '../util/getOperatorPrecedence'; type FunctionNode = @@ -16,7 +23,7 @@ interface ScopeInfo { owningFunc: FunctionNode; } -export default util.createRule({ +export default createRule({ name: 'return-await', meta: { docs: { @@ -45,7 +52,7 @@ export default util.createRule({ defaultOptions: ['in-try-catch'], create(context, [option]) { - const services = util.getParserServices(context); + const services = getParserServices(context); const checker = services.program.getTypeChecker(); const sourceCode = context.getSourceCode(); @@ -126,11 +133,11 @@ export default util.createRule({ node: TSESTree.Expression, ): TSESLint.RuleFix | null { // Should always be an await node; but let's be safe. - /* istanbul ignore if */ if (!util.isAwaitExpression(node)) { + /* istanbul ignore if */ if (!isAwaitExpression(node)) { return null; } - const awaitToken = sourceCode.getFirstToken(node, util.isAwaitKeyword); + const awaitToken = sourceCode.getFirstToken(node, isAwaitKeyword); // Should always be the case; but let's be safe. /* istanbul ignore if */ if (!awaitToken) { return null; @@ -195,9 +202,7 @@ export default util.createRule({ if (isAwait && !isThenable) { // any/unknown could be thenable; do not auto-fix - const useAutoFix = !( - util.isTypeAnyType(type) || util.isTypeUnknownType(type) - ); + const useAutoFix = !(isTypeAnyType(type) || isTypeUnknownType(type)); const fix = (fixer: TSESLint.RuleFixer): TSESLint.RuleFix | null => removeAwait(fixer, node); diff --git a/packages/eslint-plugin/src/rules/semi.ts b/packages/eslint-plugin/src/rules/semi.ts index 1719bc247007..2129c27f9fb7 100644 --- a/packages/eslint-plugin/src/rules/semi.ts +++ b/packages/eslint-plugin/src/rules/semi.ts @@ -1,15 +1,19 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import type { + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +} from '../util'; +import { createRule } from '../util'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; const baseRule = getESLintCoreRule('semi'); -export type Options = util.InferOptionsTypeFromRule; -export type MessageIds = util.InferMessageIdsTypeFromRule; +export type Options = InferOptionsTypeFromRule; +export type MessageIds = InferMessageIdsTypeFromRule; -export default util.createRule({ +export default createRule({ name: 'semi', meta: { type: 'layout', diff --git a/packages/eslint-plugin/src/rules/sort-type-constituents.ts b/packages/eslint-plugin/src/rules/sort-type-constituents.ts index fd975d42073c..552599312e19 100644 --- a/packages/eslint-plugin/src/rules/sort-type-constituents.ts +++ b/packages/eslint-plugin/src/rules/sort-type-constituents.ts @@ -1,8 +1,7 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; -import { getEnumNames, typeNodeRequiresParentheses } from '../util'; +import { createRule, getEnumNames, typeNodeRequiresParentheses } from '../util'; enum Group { conditional = 'conditional', @@ -105,7 +104,7 @@ export type Options = [ ]; export type MessageIds = 'notSorted' | 'notSortedNamed' | 'suggestFix'; -export default util.createRule({ +export default createRule({ name: 'sort-type-constituents', meta: { type: 'suggestion', diff --git a/packages/eslint-plugin/src/rules/space-before-blocks.ts b/packages/eslint-plugin/src/rules/space-before-blocks.ts index 4f82bb785a13..902c47e5ce2e 100644 --- a/packages/eslint-plugin/src/rules/space-before-blocks.ts +++ b/packages/eslint-plugin/src/rules/space-before-blocks.ts @@ -1,14 +1,18 @@ import type { TSESTree } from '@typescript-eslint/utils'; -import * as util from '../util'; +import type { + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +} from '../util'; +import { createRule, isTokenOnSameLine } from '../util'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; const baseRule = getESLintCoreRule('space-before-blocks'); -export type Options = util.InferOptionsTypeFromRule; -export type MessageIds = util.InferMessageIdsTypeFromRule; +export type Options = InferOptionsTypeFromRule; +export type MessageIds = InferMessageIdsTypeFromRule; -export default util.createRule({ +export default createRule({ name: 'space-before-blocks', meta: { type: 'layout', @@ -44,7 +48,7 @@ export default util.createRule({ node: TSESTree.Token | TSESTree.TSInterfaceBody, ): void { const precedingToken = sourceCode.getTokenBefore(node); - if (precedingToken && util.isTokenOnSameLine(precedingToken, node)) { + if (precedingToken && isTokenOnSameLine(precedingToken, node)) { // eslint-disable-next-line deprecation/deprecation -- TODO - switch once our min ESLint version is 6.7.0 const hasSpace = sourceCode.isSpaceBetweenTokens( precedingToken, diff --git a/packages/eslint-plugin/src/rules/space-before-function-paren.ts b/packages/eslint-plugin/src/rules/space-before-function-paren.ts index e6015783a670..b7d5458b041e 100644 --- a/packages/eslint-plugin/src/rules/space-before-function-paren.ts +++ b/packages/eslint-plugin/src/rules/space-before-function-paren.ts @@ -1,7 +1,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule, isOpeningParenToken } from '../util'; type Option = 'always' | 'never'; type FuncOption = Option | 'ignore'; @@ -16,7 +16,7 @@ export type Options = [ ]; export type MessageIds = 'missing' | 'unexpected'; -export default util.createRule({ +export default createRule({ name: 'space-before-function-paren', meta: { type: 'layout', @@ -109,7 +109,7 @@ export default util.createRule({ // Always ignore non-async functions and arrow functions without parens, e.g. async foo => bar if ( node.async && - util.isOpeningParenToken(sourceCode.getFirstToken(node, { skip: 1 })!) + isOpeningParenToken(sourceCode.getFirstToken(node, { skip: 1 })!) ) { return overrideConfig.asyncArrow ?? baseConfig; } @@ -149,9 +149,10 @@ export default util.createRule({ leftToken = sourceCode.getLastToken(node.typeParameters)!; rightToken = sourceCode.getTokenAfter(leftToken)!; } else { - rightToken = sourceCode.getFirstToken(node, util.isOpeningParenToken)!; + rightToken = sourceCode.getFirstToken(node, isOpeningParenToken)!; leftToken = sourceCode.getTokenBefore(rightToken)!; } + // eslint-disable-next-line deprecation/deprecation -- TODO - switch once our min ESLint version is 6.7.0 const hasSpacing = sourceCode.isSpaceBetweenTokens(leftToken, rightToken); diff --git a/packages/eslint-plugin/src/rules/space-infix-ops.ts b/packages/eslint-plugin/src/rules/space-infix-ops.ts index c1df490436fd..53df0b4e39d5 100644 --- a/packages/eslint-plugin/src/rules/space-infix-ops.ts +++ b/packages/eslint-plugin/src/rules/space-infix-ops.ts @@ -1,16 +1,20 @@ import { AST_TOKEN_TYPES, TSESTree } from '@typescript-eslint/utils'; -import * as util from '../util'; +import type { + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +} from '../util'; +import { createRule, isNotOpeningParenToken } from '../util'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; const baseRule = getESLintCoreRule('space-infix-ops'); -export type Options = util.InferOptionsTypeFromRule; -export type MessageIds = util.InferMessageIdsTypeFromRule; +export type Options = InferOptionsTypeFromRule; +export type MessageIds = InferMessageIdsTypeFromRule; const UNIONS = ['|', '&']; -export default util.createRule({ +export default createRule({ name: 'space-infix-ops', meta: { type: 'layout', @@ -129,7 +133,7 @@ export default util.createRule({ types.forEach(type => { const skipFunctionParenthesis = type.type === TSESTree.AST_NODE_TYPES.TSFunctionType - ? util.isNotOpeningParenToken + ? isNotOpeningParenToken : 0; const operator = sourceCode.getTokenBefore( type, diff --git a/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts b/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts index 2eed8cdc1e82..db0d4474a14c 100644 --- a/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts +++ b/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts @@ -6,7 +6,13 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../util'; +import { + createRule, + getConstrainedTypeAtLocation, + getParserServices, + getWrappingFixer, + isTypeArrayTypeOrUnionOfArrayTypes, +} from '../util'; export type Options = [ { @@ -47,7 +53,7 @@ export type MessageId = | 'conditionFixDefaultZero' | 'noStrictNullCheck'; -export default util.createRule({ +export default createRule({ name: 'strict-boolean-expressions', meta: { type: 'suggestion', @@ -151,7 +157,7 @@ export default util.createRule({ }, ], create(context, [options]) { - const services = util.getParserServices(context); + const services = getParserServices(context); const checker = services.program.getTypeChecker(); const compilerOptions = services.program.getCompilerOptions(); const sourceCode = context.getSourceCode(); @@ -267,7 +273,7 @@ export default util.createRule({ * It analyzes the type of a node and checks if it is allowed in a boolean context. */ function checkNode(node: TSESTree.Node): void { - const type = util.getConstrainedTypeAtLocation(services, node); + const type = getConstrainedTypeAtLocation(services, node); const types = inspectVariantTypes(tsutils.unionTypeParts(type)); const is = (...wantedTypes: readonly VariantType[]): boolean => @@ -309,7 +315,7 @@ export default util.createRule({ suggest: [ { messageId: 'conditionFixDefaultFalse', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node, wrap: code => `${code} ?? false`, @@ -317,7 +323,7 @@ export default util.createRule({ }, { messageId: 'conditionFixCompareFalse', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node: node.parent, innerNode: node, @@ -334,7 +340,7 @@ export default util.createRule({ suggest: [ { messageId: 'conditionFixDefaultFalse', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node, wrap: code => `${code} ?? false`, @@ -342,7 +348,7 @@ export default util.createRule({ }, { messageId: 'conditionFixCompareTrue', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node, wrap: code => `${code} === true`, @@ -374,7 +380,7 @@ export default util.createRule({ suggest: [ { messageId: 'conditionFixCompareStringLength', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node: node.parent, innerNode: node, @@ -383,7 +389,7 @@ export default util.createRule({ }, { messageId: 'conditionFixCompareEmptyString', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node: node.parent, innerNode: node, @@ -392,7 +398,7 @@ export default util.createRule({ }, { messageId: 'conditionFixCastBoolean', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node: node.parent, innerNode: node, @@ -409,7 +415,7 @@ export default util.createRule({ suggest: [ { messageId: 'conditionFixCompareStringLength', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node, wrap: code => `${code}.length > 0`, @@ -417,7 +423,7 @@ export default util.createRule({ }, { messageId: 'conditionFixCompareEmptyString', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node, wrap: code => `${code} !== ""`, @@ -425,7 +431,7 @@ export default util.createRule({ }, { messageId: 'conditionFixCastBoolean', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node, wrap: code => `Boolean(${code})`, @@ -449,7 +455,7 @@ export default util.createRule({ suggest: [ { messageId: 'conditionFixCompareNullish', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node: node.parent, innerNode: node, @@ -458,7 +464,7 @@ export default util.createRule({ }, { messageId: 'conditionFixDefaultEmptyString', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node, wrap: code => `${code} ?? ""`, @@ -466,7 +472,7 @@ export default util.createRule({ }, { messageId: 'conditionFixCastBoolean', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node: node.parent, innerNode: node, @@ -483,7 +489,7 @@ export default util.createRule({ suggest: [ { messageId: 'conditionFixCompareNullish', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node, wrap: code => `${code} != null`, @@ -491,7 +497,7 @@ export default util.createRule({ }, { messageId: 'conditionFixDefaultEmptyString', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node, wrap: code => `${code} ?? ""`, @@ -499,7 +505,7 @@ export default util.createRule({ }, { messageId: 'conditionFixCastBoolean', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node, wrap: code => `Boolean(${code})`, @@ -521,7 +527,7 @@ export default util.createRule({ context.report({ node, messageId: 'conditionErrorNumber', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node: node.parent, innerNode: node, @@ -533,7 +539,7 @@ export default util.createRule({ context.report({ node, messageId: 'conditionErrorNumber', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node, wrap: code => `${code} > 0`, @@ -548,7 +554,7 @@ export default util.createRule({ suggest: [ { messageId: 'conditionFixCompareZero', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node: node.parent, innerNode: node, @@ -559,7 +565,7 @@ export default util.createRule({ { // TODO: don't suggest this for bigint because it can't be NaN messageId: 'conditionFixCompareNaN', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node: node.parent, innerNode: node, @@ -568,7 +574,7 @@ export default util.createRule({ }, { messageId: 'conditionFixCastBoolean', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node: node.parent, innerNode: node, @@ -585,7 +591,7 @@ export default util.createRule({ suggest: [ { messageId: 'conditionFixCompareZero', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node, wrap: code => `${code} !== 0`, @@ -593,7 +599,7 @@ export default util.createRule({ }, { messageId: 'conditionFixCompareNaN', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node, wrap: code => `!Number.isNaN(${code})`, @@ -601,7 +607,7 @@ export default util.createRule({ }, { messageId: 'conditionFixCastBoolean', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node, wrap: code => `Boolean(${code})`, @@ -625,7 +631,7 @@ export default util.createRule({ suggest: [ { messageId: 'conditionFixCompareNullish', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node: node.parent, innerNode: node, @@ -634,7 +640,7 @@ export default util.createRule({ }, { messageId: 'conditionFixDefaultZero', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node, wrap: code => `${code} ?? 0`, @@ -642,7 +648,7 @@ export default util.createRule({ }, { messageId: 'conditionFixCastBoolean', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node: node.parent, innerNode: node, @@ -659,7 +665,7 @@ export default util.createRule({ suggest: [ { messageId: 'conditionFixCompareNullish', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node, wrap: code => `${code} != null`, @@ -667,7 +673,7 @@ export default util.createRule({ }, { messageId: 'conditionFixDefaultZero', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node, wrap: code => `${code} ?? 0`, @@ -675,7 +681,7 @@ export default util.createRule({ }, { messageId: 'conditionFixCastBoolean', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node, wrap: code => `Boolean(${code})`, @@ -706,7 +712,7 @@ export default util.createRule({ suggest: [ { messageId: 'conditionFixCompareNullish', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node: node.parent, innerNode: node, @@ -723,7 +729,7 @@ export default util.createRule({ suggest: [ { messageId: 'conditionFixCompareNullish', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node, wrap: code => `${code} != null`, @@ -753,7 +759,7 @@ export default util.createRule({ context.report({ node, messageId: 'conditionErrorNullableEnum', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node: node.parent, innerNode: node, @@ -764,7 +770,7 @@ export default util.createRule({ context.report({ node, messageId: 'conditionErrorNullableEnum', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node, wrap: code => `${code} != null`, @@ -784,7 +790,7 @@ export default util.createRule({ suggest: [ { messageId: 'conditionFixCastBoolean', - fix: util.getWrappingFixer({ + fix: getWrappingFixer({ sourceCode, node, wrap: code => `Boolean(${code})`, @@ -905,7 +911,7 @@ export default util.createRule({ if ( types.some(type => - util.isTypeFlagSet( + tsutils.isTypeFlagSet( type, ts.TypeFlags.TypeParameter | ts.TypeFlags.Any | @@ -945,6 +951,6 @@ function isArrayLengthExpression( if (node.property.name !== 'length') { return false; } - const objectType = util.getConstrainedTypeAtLocation(services, node.object); - return util.isTypeArrayTypeOrUnionOfArrayTypes(objectType, typeChecker); + const objectType = getConstrainedTypeAtLocation(services, node.object); + return isTypeArrayTypeOrUnionOfArrayTypes(objectType, typeChecker); } diff --git a/packages/eslint-plugin/src/rules/triple-slash-reference.ts b/packages/eslint-plugin/src/rules/triple-slash-reference.ts index 10f85b6cc6e6..22f6b49da617 100644 --- a/packages/eslint-plugin/src/rules/triple-slash-reference.ts +++ b/packages/eslint-plugin/src/rules/triple-slash-reference.ts @@ -1,7 +1,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; type Options = [ { @@ -12,7 +12,7 @@ type Options = [ ]; type MessageIds = 'tripleSlashReference'; -export default util.createRule({ +export default createRule({ name: 'triple-slash-reference', meta: { type: 'suggestion', diff --git a/packages/eslint-plugin/src/rules/type-annotation-spacing.ts b/packages/eslint-plugin/src/rules/type-annotation-spacing.ts index 20db2832184e..f9ca288649e0 100644 --- a/packages/eslint-plugin/src/rules/type-annotation-spacing.ts +++ b/packages/eslint-plugin/src/rules/type-annotation-spacing.ts @@ -1,7 +1,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; -import * as util from '../util'; import { + createRule, isClassOrTypeElement, isFunction, isFunctionOrFunctionType, @@ -98,7 +98,7 @@ function getRules( return rules.colon; } -export default util.createRule({ +export default createRule({ name: 'type-annotation-spacing', meta: { type: 'layout', diff --git a/packages/eslint-plugin/src/rules/typedef.ts b/packages/eslint-plugin/src/rules/typedef.ts index 595081906afa..e84aaef8cb3d 100644 --- a/packages/eslint-plugin/src/rules/typedef.ts +++ b/packages/eslint-plugin/src/rules/typedef.ts @@ -1,7 +1,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import { createRule } from '../util'; const enum OptionKeys { ArrayDestructuring = 'arrayDestructuring', @@ -18,7 +18,7 @@ type Options = { [k in OptionKeys]?: boolean }; type MessageIds = 'expectedTypedef' | 'expectedTypedefNamed'; -export default util.createRule<[Options], MessageIds>({ +export default createRule<[Options], MessageIds>({ name: 'typedef', meta: { docs: { diff --git a/packages/eslint-plugin/src/rules/unbound-method.ts b/packages/eslint-plugin/src/rules/unbound-method.ts index ce2ec6ccd735..e1c2aed6a019 100644 --- a/packages/eslint-plugin/src/rules/unbound-method.ts +++ b/packages/eslint-plugin/src/rules/unbound-method.ts @@ -3,8 +3,12 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import * as util from '../util'; -import { getModifiers } from '../util'; +import { + createRule, + getModifiers, + getParserServices, + isIdentifier, +} from '../util'; //------------------------------------------------------------------------------ // Rule Definition @@ -124,7 +128,7 @@ const getMemberFullName = (node: TSESTree.MemberExpression): string => const BASE_MESSAGE = 'Avoid referencing unbound methods which may cause unintentional scoping of `this`.'; -export default util.createRule({ +export default createRule({ name: 'unbound-method', meta: { docs: { @@ -161,7 +165,7 @@ export default util.createRule({ }, ], create(context, [{ ignoreStatic }]) { - const services = util.getParserServices(context); + const services = getParserServices(context); const currentSourceFile = services.program.getSourceFile( context.getFilename(), ); @@ -226,7 +230,7 @@ export default util.createRule({ ) { if ( notImported && - util.isIdentifier(initNode) && + isIdentifier(initNode) && nativelyBoundMembers.includes( `${initNode.name}.${property.key.name}`, ) diff --git a/packages/eslint-plugin/src/rules/unified-signatures.ts b/packages/eslint-plugin/src/rules/unified-signatures.ts index 34fb04c295ec..950125e8686f 100644 --- a/packages/eslint-plugin/src/rules/unified-signatures.ts +++ b/packages/eslint-plugin/src/rules/unified-signatures.ts @@ -1,7 +1,8 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as util from '../util'; +import type { Equal } from '../util'; +import { arraysAreEqual, createRule } from '../util'; interface Failure { unify: Unify; @@ -61,7 +62,7 @@ type Options = [ }, ]; -export default util.createRule({ +export default createRule({ name: 'unified-signatures', meta: { docs: { @@ -229,7 +230,7 @@ export default util.createRule({ typesAreEqual(a.returnType, b.returnType) && // Must take the same type parameters. // If one uses a type parameter (from outside) and the other doesn't, they shouldn't be joined. - util.arraysAreEqual(aTypeParams, bTypeParams, typeParametersAreEqual) && + arraysAreEqual(aTypeParams, bTypeParams, typeParametersAreEqual) && signatureUsesTypeParameter(a, isTypeParameter) === signatureUsesTypeParameter(b, isTypeParameter) ); @@ -251,7 +252,7 @@ export default util.createRule({ // If remaining arrays are equal, the signatures differ by just one parameter type if ( - !util.arraysAreEqual( + !arraysAreEqual( types1.slice(index + 1), types2.slice(index + 1), parametersAreEqual, @@ -462,7 +463,7 @@ export default util.createRule({ function getIndexOfFirstDifference( a: readonly T[], b: readonly T[], - equal: util.Equal, + equal: Equal, ): number | undefined { for (let i = 0; i < a.length && i < b.length; i++) { if (!equal(a[i], b[i])) { diff --git a/packages/eslint-plugin/tests/areOptionsValid.test.ts b/packages/eslint-plugin/tests/areOptionsValid.test.ts index 6ec3fd4dfca4..ab234f2fe3a8 100644 --- a/packages/eslint-plugin/tests/areOptionsValid.test.ts +++ b/packages/eslint-plugin/tests/areOptionsValid.test.ts @@ -1,7 +1,7 @@ -import * as util from '../src/util'; +import { createRule } from '../src/util'; import { areOptionsValid } from './areOptionsValid'; -const exampleRule = util.createRule<['value-a' | 'value-b'], never>({ +const exampleRule = createRule<['value-a' | 'value-b'], never>({ name: 'my-example-rule', meta: { type: 'layout', diff --git a/packages/eslint-plugin/tests/util.test.ts b/packages/eslint-plugin/tests/util.test.ts index a2f742870779..4242128b0687 100644 --- a/packages/eslint-plugin/tests/util.test.ts +++ b/packages/eslint-plugin/tests/util.test.ts @@ -1,4 +1,4 @@ -import * as util from '../src/util'; +import { isDefinitionFile, upperCaseFirst } from '../src/util'; describe('isDefinitionFile', () => { describe('returns false for non-definition files', () => { @@ -22,7 +22,7 @@ describe('isDefinitionFile', () => { invalid.forEach(f => { it(f, () => { - expect(util.isDefinitionFile(f)).toBe(false); + expect(isDefinitionFile(f)).toBe(false); }); }); }); @@ -32,7 +32,7 @@ describe('isDefinitionFile', () => { valid.forEach(f => { it(f, () => { - expect(util.isDefinitionFile(f)).toBe(true); + expect(isDefinitionFile(f)).toBe(true); }); }); }); @@ -40,6 +40,6 @@ describe('isDefinitionFile', () => { describe('upperCaseFirst', () => { it('upper cases first', () => { - expect(util.upperCaseFirst('hello')).toBe('Hello'); + expect(upperCaseFirst('hello')).toBe('Hello'); }); }); diff --git a/packages/eslint-plugin/tests/util/getWrappedCode.test.ts b/packages/eslint-plugin/tests/util/getWrappedCode.test.ts index 516642c16b57..bc57bfdabf09 100644 --- a/packages/eslint-plugin/tests/util/getWrappedCode.test.ts +++ b/packages/eslint-plugin/tests/util/getWrappedCode.test.ts @@ -2,7 +2,11 @@ import { RuleTester } from '@typescript-eslint/rule-tester'; import type { TSESTree } from '@typescript-eslint/utils'; import * as ts from 'typescript'; -import * as util from '../../src/util'; +import { + createRule, + getOperatorPrecedence, + getParserServices, +} from '../../src/util'; import { getWrappedCode } from '../../src/util/getWrappedCode'; import { getFixturesRootDir } from '../RuleTester'; @@ -15,7 +19,7 @@ const ruleTester = new RuleTester({ }, }); -const removeFunctionRule = util.createRule({ +const removeFunctionRule = createRule({ name: 'remove-function', defaultOptions: [], meta: { @@ -33,7 +37,7 @@ const removeFunctionRule = util.createRule({ create(context) { const sourceCode = context.getSourceCode(); - const parserServices = util.getParserServices(context, true); + const parserServices = getParserServices(context, true); const report = (node: TSESTree.CallExpression): void => { context.report({ @@ -43,13 +47,13 @@ const removeFunctionRule = util.createRule({ const tsNode = parserServices.esTreeNodeToTSNodeMap.get(node); const tsArgumentNode = tsNode.arguments[0]; - const nodePrecedence = util.getOperatorPrecedence( + const nodePrecedence = getOperatorPrecedence( tsArgumentNode.kind, ts.isBinaryExpression(tsArgumentNode) ? tsArgumentNode.operatorToken.kind : ts.SyntaxKind.Unknown, ); - const parentPrecedence = util.getOperatorPrecedence( + const parentPrecedence = getOperatorPrecedence( tsNode.parent.kind, ts.isBinaryExpression(tsNode.parent) ? tsNode.parent.operatorToken.kind From c5334be9b09742ba3e283a34530088047a365dfc Mon Sep 17 00:00:00 2001 From: Edwin Kofler Date: Wed, 11 Oct 2023 04:35:35 -0700 Subject: [PATCH 09/16] docs: fix "Alternatively" typo (#7740) docs: Fix "Alternatively" typo --- docs/contributing/Local_Development.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/Local_Development.mdx b/docs/contributing/Local_Development.mdx index e4b9f6d83dc7..9b76bdb69b6b 100644 --- a/docs/contributing/Local_Development.mdx +++ b/docs/contributing/Local_Development.mdx @@ -40,7 +40,7 @@ You can also perform them locally. We use [Prettier](https://prettier.io) to auto-format code. A Git pre-commit hook should apply it to all committed changes. -ALternately, you can run `yarn format` in any package or in the root. +Alternately, you can run `yarn format` in any package or in the root. ### Linting From cff6e472996c6ccdd672be09d033d2e0a67d5687 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Wed, 11 Oct 2023 09:26:00 -0400 Subject: [PATCH 10/16] docs(eslint-plugin): deduplicate examples for no-explicit-any (#7715) --- .../docs/rules/no-explicit-any.md | 31 +------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/no-explicit-any.md b/packages/eslint-plugin/docs/rules/no-explicit-any.md index efec50113734..d3c5d7617425 100644 --- a/packages/eslint-plugin/docs/rules/no-explicit-any.md +++ b/packages/eslint-plugin/docs/rules/no-explicit-any.md @@ -98,7 +98,7 @@ function greet(param: Array): Array {} A boolean to specify if arrays from the rest operator are considered okay. `false` by default. -Examples of **incorrect** code for the `{ "ignoreRestArgs": false }` option: +The examples below are **incorrect** when `{ignoreRestArgs: false}`, but **correct** when `{ignoreRestArgs: true}`. ```ts /*eslint @typescript-eslint/no-explicit-any: ["error", { "ignoreRestArgs": false }]*/ @@ -127,35 +127,6 @@ interface Garply { } ``` -Examples of **correct** code for the `{ "ignoreRestArgs": true }` option: - -```ts -/*eslint @typescript-eslint/no-explicit-any: ["error", { "ignoreRestArgs": true }]*/ - -function foo1(...args: any[]): void {} -function foo2(...args: readonly any[]): void {} -function foo3(...args: Array): void {} -function foo4(...args: ReadonlyArray): void {} - -declare function bar(...args: any[]): void; - -const baz = (...args: any[]) => {}; -const qux = function (...args: any[]) {}; - -type Quux = (...args: any[]) => void; -type Quuz = new (...args: any[]) => void; - -interface Grault { - (...args: any[]): void; -} -interface Corge { - new (...args: any[]): void; -} -interface Garply { - f(...args: any[]): void; -} -``` - ## When Not To Use It If an unknown type or a library without typings is used From f81a2da13529e77d039c5b31b4313a6984ceb964 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Wed, 11 Oct 2023 09:27:31 -0400 Subject: [PATCH 11/16] fix(eslint-plugin): [no-unsafe-member-access] report on only the accessed property (#7717) --- .../src/rules/no-unsafe-member-access.ts | 2 +- .../rules/no-unsafe-member-access.test.ts | 67 +++++++++++++++++-- 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts b/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts index 45aefe49e534..2ec9a9d21a4f 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts @@ -89,7 +89,7 @@ export default createRule({ } context.report({ - node, + node: node.property, messageId, data: { property: node.computed ? `[${propertyName}]` : `.${propertyName}`, diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-member-access.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-member-access.test.ts index 8298cec6ceba..367ae0c6e3c2 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-member-access.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-member-access.test.ts @@ -81,6 +81,9 @@ function foo(x: any) { errors: [ { messageId: 'unsafeMemberExpression', + line: 3, + column: 5, + endColumn: 6, data: { property: '.a', }, @@ -96,6 +99,9 @@ function foo(x: any) { errors: [ { messageId: 'unsafeMemberExpression', + line: 3, + column: 5, + endColumn: 6, data: { property: '.a', }, @@ -111,6 +117,9 @@ function foo(x: { a: any }) { errors: [ { messageId: 'unsafeMemberExpression', + line: 3, + column: 7, + endColumn: 8, data: { property: '.b', }, @@ -126,6 +135,9 @@ function foo(x: any) { errors: [ { messageId: 'unsafeMemberExpression', + line: 3, + column: 5, + endColumn: 8, data: { property: "['a']", }, @@ -141,6 +153,9 @@ function foo(x: any) { errors: [ { messageId: 'unsafeMemberExpression', + line: 3, + column: 5, + endColumn: 8, data: { property: "['a']", }, @@ -156,6 +171,9 @@ function foo(x: { a: number }, y: any) { errors: [ { messageId: 'unsafeComputedMemberAccess', + line: 3, + column: 5, + endColumn: 6, data: { property: '[y]', }, @@ -171,6 +189,9 @@ function foo(x?: { a: number }, y: any) { errors: [ { messageId: 'unsafeComputedMemberAccess', + line: 3, + column: 7, + endColumn: 8, data: { property: '[y]', }, @@ -186,6 +207,9 @@ function foo(x: { a: number }, y: any) { errors: [ { messageId: 'unsafeComputedMemberAccess', + line: 3, + column: 6, + endColumn: 12, data: { property: '[y += 1]', }, @@ -201,6 +225,9 @@ function foo(x: { a: number }, y: any) { errors: [ { messageId: 'unsafeComputedMemberAccess', + line: 3, + column: 5, + endColumn: 13, data: { property: '[1 as any]', }, @@ -216,6 +243,9 @@ function foo(x: { a: number }, y: any) { errors: [ { messageId: 'unsafeComputedMemberAccess', + line: 3, + column: 5, + endColumn: 8, data: { property: '[y()]', }, @@ -231,6 +261,9 @@ function foo(x: string[], y: any) { errors: [ { messageId: 'unsafeComputedMemberAccess', + line: 3, + column: 5, + endColumn: 6, data: { property: '[y]', }, @@ -260,22 +293,48 @@ const methods = { { messageId: 'unsafeThisMemberExpression', line: 4, - column: 12, + column: 17, endColumn: 24, }, { messageId: 'unsafeThisMemberExpression', line: 8, - column: 12, - endColumn: 31, + column: 17, + endColumn: 30, }, { messageId: 'unsafeThisMemberExpression', line: 14, - column: 13, + column: 19, endColumn: 26, }, ], }, + { + code: ` +class C { + getObs$: any; + getPopularDepartments(): void { + this.getObs$.pipe().subscribe(res => { + console.log(res); + }); + } +} + `, + errors: [ + { + messageId: 'unsafeMemberExpression', + line: 5, + column: 18, + endColumn: 22, + }, + { + messageId: 'unsafeMemberExpression', + line: 5, + column: 25, + endColumn: 34, + }, + ], + }, ], }); From ac397f18176a9defd8c189b5b6b4e5d0b7582210 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Wed, 11 Oct 2023 09:29:04 -0400 Subject: [PATCH 12/16] fix(eslint-plugin): [no-useless-empty-export] exempt .d.ts (#7718) --- .../src/rules/no-useless-empty-export.ts | 28 +++++++------ .../rules/no-useless-empty-export.test.ts | 42 +++++++++++++++++++ 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-useless-empty-export.ts b/packages/eslint-plugin/src/rules/no-useless-empty-export.ts index 5d6b091e2abb..2fc04b3746af 100644 --- a/packages/eslint-plugin/src/rules/no-useless-empty-export.ts +++ b/packages/eslint-plugin/src/rules/no-useless-empty-export.ts @@ -40,6 +40,12 @@ export default createRule({ }, defaultOptions: [], create(context) { + // In a definition file, export {} is necessary to make the module properly + // encapsulated, even when there are other exports + // https://github.com/typescript-eslint/typescript-eslint/issues/4975 + if (util.isDefinitionFile(context.getFilename())) { + return {}; + } function checkNode( node: TSESTree.Program | TSESTree.TSModuleDeclaration, ): void { @@ -47,27 +53,25 @@ export default createRule({ return; } - let emptyExport: TSESTree.ExportNamedDeclaration | undefined; + const emptyExports: TSESTree.ExportNamedDeclaration[] = []; let foundOtherExport = false; for (const statement of node.body) { if (isEmptyExport(statement)) { - emptyExport = statement; - - if (foundOtherExport) { - break; - } + emptyExports.push(statement); } else if (exportOrImportNodeTypes.has(statement.type)) { foundOtherExport = true; } } - if (emptyExport && foundOtherExport) { - context.report({ - fix: fixer => fixer.remove(emptyExport!), - messageId: 'uselessExport', - node: emptyExport, - }); + if (foundOtherExport) { + for (const emptyExport of emptyExports) { + context.report({ + fix: fixer => fixer.remove(emptyExport), + messageId: 'uselessExport', + node: emptyExport, + }); + } } } diff --git a/packages/eslint-plugin/tests/rules/no-useless-empty-export.test.ts b/packages/eslint-plugin/tests/rules/no-useless-empty-export.test.ts index 6ed201033bb4..caef56622cbc 100644 --- a/packages/eslint-plugin/tests/rules/no-useless-empty-export.test.ts +++ b/packages/eslint-plugin/tests/rules/no-useless-empty-export.test.ts @@ -37,6 +37,35 @@ ruleTester.run('no-useless-empty-export', rule, { ` export {}; `, + // https://github.com/microsoft/TypeScript/issues/38592 + { + code: ` + export type A = 1; + export {}; + `, + filename: 'foo.d.ts', + }, + { + code: ` + export declare const a = 2; + export {}; + `, + filename: 'foo.d.ts', + }, + { + code: ` + import type { A } from '_'; + export {}; + `, + filename: 'foo.d.ts', + }, + { + code: ` + import { A } from '_'; + export {}; + `, + filename: 'foo.d.ts', + }, ], invalid: [ { @@ -120,6 +149,19 @@ export {}; output: ` import _ = require('_'); + `, + }, + { + code: ` +import _ = require('_'); +export {}; +export {}; + `, + errors: [error, error], + output: ` +import _ = require('_'); + + `, }, ], From e5ea1d05603e6212093de541e5da49f139571454 Mon Sep 17 00:00:00 2001 From: Mark de Dios <99303358+peanutenthusiast@users.noreply.github.com> Date: Wed, 11 Oct 2023 06:30:57 -0700 Subject: [PATCH 13/16] fix(eslint-plugin): [no-shadow] fix static class generics for class expressions (#7724) * Add test for factory generating class functionn with generic type * Rename isGenericOfClassDecl to isGenericOfClass, check for class expression in function * Apply eslint fixer on no shadow test class expression test case * Apply yarn lint-fix --- packages/eslint-plugin/src/rules/no-shadow.ts | 11 ++++++----- .../tests/rules/no-shadow/no-shadow.test.ts | 11 +++++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-shadow.ts b/packages/eslint-plugin/src/rules/no-shadow.ts index b26e8b4a957f..dbc86e930cde 100644 --- a/packages/eslint-plugin/src/rules/no-shadow.ts +++ b/packages/eslint-plugin/src/rules/no-shadow.ts @@ -199,7 +199,7 @@ export default createRule({ return methodDefinition.static; } - function isGenericOfClassDecl(variable: TSESLint.Scope.Variable): boolean { + function isGenericOfClass(variable: TSESLint.Scope.Variable): boolean { if (!('isTypeVariable' in variable)) { // this shouldn't happen... return false; @@ -224,16 +224,17 @@ export default createRule({ return false; } const classDecl = typeParameterDecl.parent; - return classDecl?.type === AST_NODE_TYPES.ClassDeclaration; + return ( + classDecl?.type === AST_NODE_TYPES.ClassDeclaration || + classDecl?.type === AST_NODE_TYPES.ClassExpression + ); } function isGenericOfAStaticMethodShadow( variable: TSESLint.Scope.Variable, shadowed: TSESLint.Scope.Variable, ): boolean { - return ( - isGenericOfStaticMethod(variable) && isGenericOfClassDecl(shadowed) - ); + return isGenericOfStaticMethod(variable) && isGenericOfClass(shadowed); } function isImportDeclaration( diff --git a/packages/eslint-plugin/tests/rules/no-shadow/no-shadow.test.ts b/packages/eslint-plugin/tests/rules/no-shadow/no-shadow.test.ts index ae00139d9821..277233d88d68 100644 --- a/packages/eslint-plugin/tests/rules/no-shadow/no-shadow.test.ts +++ b/packages/eslint-plugin/tests/rules/no-shadow/no-shadow.test.ts @@ -220,6 +220,17 @@ export class Wrapper { static create(wrapped: Wrapped) { return new Wrapper(wrapped); } +} + `, + ` +function makeA() { + return class A { + constructor(public value: T) {} + + static make(value: T) { + return new A(value); + } + }; } `, { From afdae3739c68469a488277eb7b7f56f679d6eb20 Mon Sep 17 00:00:00 2001 From: Ashriel Waghmare <89381263+rielAsh24@users.noreply.github.com> Date: Wed, 11 Oct 2023 19:05:20 +0530 Subject: [PATCH 14/16] fix(eslint-plugin): [consistent-type-imports] import assertion checks added (#7722) * Updated consistent-type-imports Added type assertion for json files * Import assertion checks added The linter checks for import assertions before suggesting fixes --- .../src/rules/consistent-type-imports.ts | 36 ++++++++++++------- .../rules/consistent-type-imports.test.ts | 10 ++++++ 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/packages/eslint-plugin/src/rules/consistent-type-imports.ts b/packages/eslint-plugin/src/rules/consistent-type-imports.ts index a99a09e7bc1c..57e15ea29174 100644 --- a/packages/eslint-plugin/src/rules/consistent-type-imports.ts +++ b/packages/eslint-plugin/src/rules/consistent-type-imports.ts @@ -271,17 +271,25 @@ export default createRule({ report.unusedSpecifiers.length === 0 && report.node.importKind !== 'type' ) { - context.report({ - node: report.node, - messageId: 'typeOverValue', - *fix(fixer) { - yield* fixToTypeImportDeclaration( - fixer, - report, - sourceImports, - ); - }, - }); + /** checks if import has type assertions + * ``` + * import * as type from 'mod' assert { type: 'json' }; + * ``` + * https://github.com/typescript-eslint/typescript-eslint/issues/7527 + */ + if (report.node.assertions.length === 0) { + context.report({ + node: report.node, + messageId: 'typeOverValue', + *fix(fixer) { + yield* fixToTypeImportDeclaration( + fixer, + report, + sourceImports, + ); + }, + }); + } } else { const isTypeImport = report.node.importKind === 'type'; @@ -622,7 +630,11 @@ export default createRule({ if (namespaceSpecifier && !defaultSpecifier) { // import * as types from 'foo' - yield* fixInsertTypeSpecifierForImportDeclaration(fixer, node, false); + + // checks for presence of import assertions + if (node.assertions.length === 0) { + yield* fixInsertTypeSpecifierForImportDeclaration(fixer, node, false); + } return; } else if (defaultSpecifier) { if ( diff --git a/packages/eslint-plugin/tests/rules/consistent-type-imports.test.ts b/packages/eslint-plugin/tests/rules/consistent-type-imports.test.ts index ae171e0d87e8..055f8473ee28 100644 --- a/packages/eslint-plugin/tests/rules/consistent-type-imports.test.ts +++ b/packages/eslint-plugin/tests/rules/consistent-type-imports.test.ts @@ -125,6 +125,16 @@ ruleTester.run('consistent-type-imports', rule, { `, options: [{ prefer: 'no-type-imports' }], }, + { + code: ` + import * as Type from 'foo' assert { type: 'json' }; + const a: typeof Type = Type; + `, + options: [{ prefer: 'no-type-imports' }], + dependencyConstraints: { + typescript: '4.5', + }, + }, ` import { type A } from 'foo'; type T = A; From 3c6379b7678bcb190ae70d211cb3930c942d17a0 Mon Sep 17 00:00:00 2001 From: Seiya <20365512+seiyab@users.noreply.github.com> Date: Wed, 11 Oct 2023 22:38:18 +0900 Subject: [PATCH 15/16] feat(eslint-plugin): add new extended rule `prefer-destructuring` (#7117) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * copy prefer-destructuring from ESLint * rewrite schema by hand * add enforceForTypeAnnotatedProperties option autofix is still wrong. * add tests * prevent fixing type-annotated declaration * add tests * move baseTests into end of file * refactor * consider numeric properties of non-itreable objects for VariableDeclarator * consider numeric properties of non-itreable objects for AssignmentExpression * fix a bug * fix a bug * add "openjsf" into the dictionary * add prefer-destructuring into all * add doc and minor tweak * fix typo * fix incorrect "correct" case * improve test coverage * improve test coverage * fix: bring in adjustments from main branch * Updated snapshot * Update packages/eslint-plugin/src/rules/prefer-destructuring.ts Co-authored-by: Josh Goldberg ✨ * rename a function * fix typo * reduce baseRule.create() calls * lazily run baseRule.create(noFixContext(context)) * lint * add test cases * add test cases * remove tests copied from base rule * add tests * add tests * declare variables * minor improvements - naming of options - using nullish coalescing assignment * improve type and coverage --------- Co-authored-by: Josh Goldberg --- .../docs/rules/prefer-destructuring.md | 91 ++ packages/eslint-plugin/src/configs/all.ts | 2 + packages/eslint-plugin/src/rules/index.ts | 2 + .../src/rules/prefer-destructuring.ts | 237 ++++ .../src/util/getESLintCoreRule.ts | 1 + .../tests/rules/prefer-destructuring.test.ts | 1064 +++++++++++++++++ .../prefer-destructuring.shot | 94 ++ .../eslint-plugin/typings/eslint-rules.d.ts | 27 + 8 files changed, 1518 insertions(+) create mode 100644 packages/eslint-plugin/docs/rules/prefer-destructuring.md create mode 100644 packages/eslint-plugin/src/rules/prefer-destructuring.ts create mode 100644 packages/eslint-plugin/tests/rules/prefer-destructuring.test.ts create mode 100644 packages/eslint-plugin/tests/schema-snapshots/prefer-destructuring.shot diff --git a/packages/eslint-plugin/docs/rules/prefer-destructuring.md b/packages/eslint-plugin/docs/rules/prefer-destructuring.md new file mode 100644 index 000000000000..5980b81dbae8 --- /dev/null +++ b/packages/eslint-plugin/docs/rules/prefer-destructuring.md @@ -0,0 +1,91 @@ +--- +description: 'Require destructuring from arrays and/or objects.' +--- + +> 🛑 This file is source code, not the primary documentation location! 🛑 +> +> See **https://typescript-eslint.io/rules/prefer-destructuring** for documentation. + +## Examples + +This rule extends the base [`eslint/prefer-destructuring`](https://eslint.org/docs/latest/rules/prefer-destructuring) rule. +It adds support for TypeScript's type annotations in variable declarations. + + + +### `eslint/prefer-destructuring` + +```ts +const x: string = obj.x; // This is incorrect and the auto fixer provides following untyped fix. +// const { x } = obj; +``` + +### `@typescript-eslint/prefer-destructuring` + +```ts +const x: string = obj.x; // This is correct by default. You can also forbid this by an option. +``` + + + +And it infers binding patterns more accurately thanks to the type checker. + + + +### ❌ Incorrect + +```ts +const x = ['a']; +const y = x[0]; +``` + +### ✅ Correct + +```ts +const x = { 0: 'a' }; +const y = x[0]; +``` + +It is correct when `enforceForRenamedProperties` is not true. +Valid destructuring syntax is renamed style like `{ 0: y } = x` rather than `[y] = x` because `x` is not iterable. + +## Options + +This rule adds the following options: + +```ts +type Options = [ + BasePreferDestructuringOptions[0], + BasePreferDestructuringOptions[1] & { + enforceForDeclarationWithTypeAnnotation?: boolean; + }, +]; + +const defaultOptions: Options = [ + basePreferDestructuringDefaultOptions[0], + { + ...basePreferDestructuringDefaultOptions[1], + enforceForDeclarationWithTypeAnnotation: false, + }, +]; +``` + +### `enforceForDeclarationWithTypeAnnotation` + +When set to `true`, type annotated variable declarations are enforced to use destructuring assignment. + +Examples with `{ enforceForDeclarationWithTypeAnnotation: true }`: + + + +### ❌ Incorrect + +```ts +const x: string = obj.x; +``` + +### ✅ Correct + +```ts +const { x }: { x: string } = obj; +``` diff --git a/packages/eslint-plugin/src/configs/all.ts b/packages/eslint-plugin/src/configs/all.ts index d0bd265b0996..bb3873bc3449 100644 --- a/packages/eslint-plugin/src/configs/all.ts +++ b/packages/eslint-plugin/src/configs/all.ts @@ -141,6 +141,8 @@ export = { '@typescript-eslint/parameter-properties': 'error', '@typescript-eslint/prefer-as-const': 'error', '@typescript-eslint/prefer-enum-initializers': 'error', + 'prefer-destructuring': 'off', + '@typescript-eslint/prefer-destructuring': 'error', '@typescript-eslint/prefer-for-of': 'error', '@typescript-eslint/prefer-function-type': 'error', '@typescript-eslint/prefer-includes': 'error', diff --git a/packages/eslint-plugin/src/rules/index.ts b/packages/eslint-plugin/src/rules/index.ts index 44aedd6198e1..0cc9c880759a 100644 --- a/packages/eslint-plugin/src/rules/index.ts +++ b/packages/eslint-plugin/src/rules/index.ts @@ -97,6 +97,7 @@ import objectCurlySpacing from './object-curly-spacing'; import paddingLineBetweenStatements from './padding-line-between-statements'; import parameterProperties from './parameter-properties'; import preferAsConst from './prefer-as-const'; +import preferDestructuring from './prefer-destructuring'; import preferEnumInitializers from './prefer-enum-initializers'; import preferForOf from './prefer-for-of'; import preferFunctionType from './prefer-function-type'; @@ -232,6 +233,7 @@ export default { 'padding-line-between-statements': paddingLineBetweenStatements, 'parameter-properties': parameterProperties, 'prefer-as-const': preferAsConst, + 'prefer-destructuring': preferDestructuring, 'prefer-enum-initializers': preferEnumInitializers, 'prefer-for-of': preferForOf, 'prefer-function-type': preferFunctionType, diff --git a/packages/eslint-plugin/src/rules/prefer-destructuring.ts b/packages/eslint-plugin/src/rules/prefer-destructuring.ts new file mode 100644 index 000000000000..41a4db152543 --- /dev/null +++ b/packages/eslint-plugin/src/rules/prefer-destructuring.ts @@ -0,0 +1,237 @@ +import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; +import { AST_NODE_TYPES } from '@typescript-eslint/utils'; +import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema'; +import * as tsutils from 'ts-api-utils'; +import type * as ts from 'typescript'; + +import type { + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +} from '../util'; +import { createRule, getParserServices, isTypeAnyType } from '../util'; +import { getESLintCoreRule } from '../util/getESLintCoreRule'; + +const baseRule = getESLintCoreRule('prefer-destructuring'); + +type BaseOptions = InferOptionsTypeFromRule; +type EnforcementOptions = BaseOptions[1] & { + enforceForDeclarationWithTypeAnnotation?: boolean; +}; +type Options = [BaseOptions[0], EnforcementOptions]; + +type MessageIds = InferMessageIdsTypeFromRule; + +const destructuringTypeConfig: JSONSchema4 = { + type: 'object', + properties: { + array: { + type: 'boolean', + }, + object: { + type: 'boolean', + }, + }, + additionalProperties: false, +}; + +const schema: readonly JSONSchema4[] = [ + { + oneOf: [ + { + type: 'object', + properties: { + VariableDeclarator: destructuringTypeConfig, + AssignmentExpression: destructuringTypeConfig, + }, + additionalProperties: false, + }, + destructuringTypeConfig, + ], + }, + { + type: 'object', + properties: { + enforceForRenamedProperties: { + type: 'boolean', + }, + enforceForDeclarationWithTypeAnnotation: { + type: 'boolean', + }, + }, + }, +]; + +export default createRule({ + name: 'prefer-destructuring', + meta: { + type: 'suggestion', + docs: { + description: 'Require destructuring from arrays and/or objects', + extendsBaseRule: true, + requiresTypeChecking: true, + }, + schema, + fixable: baseRule.meta.fixable, + hasSuggestions: baseRule.meta.hasSuggestions, + messages: baseRule.meta.messages, + }, + defaultOptions: [ + { + VariableDeclarator: { + array: true, + object: true, + }, + AssignmentExpression: { + array: true, + object: true, + }, + }, + {}, + ], + create(context, [enabledTypes, options]) { + const { + enforceForRenamedProperties = false, + enforceForDeclarationWithTypeAnnotation = false, + } = options; + const { program, esTreeNodeToTSNodeMap } = getParserServices(context); + const typeChecker = program.getTypeChecker(); + const baseRules = baseRule.create(context); + let baseRulesWithoutFixCache: typeof baseRules | null = null; + + return { + VariableDeclarator(node): void { + performCheck(node.id, node.init, node); + }, + AssignmentExpression(node): void { + if (node.operator !== '=') { + return; + } + performCheck(node.left, node.right, node); + }, + }; + + function performCheck( + leftNode: TSESTree.BindingName | TSESTree.Expression, + rightNode: TSESTree.Expression | null, + reportNode: TSESTree.VariableDeclarator | TSESTree.AssignmentExpression, + ): void { + const rules = + leftNode.type === AST_NODE_TYPES.Identifier && + leftNode.typeAnnotation === undefined + ? baseRules + : baseRulesWithoutFix(); + if ( + 'typeAnnotation' in leftNode && + leftNode.typeAnnotation !== undefined && + !enforceForDeclarationWithTypeAnnotation + ) { + return; + } + + if ( + rightNode != null && + isArrayLiteralIntegerIndexAccess(rightNode) && + rightNode.object.type !== AST_NODE_TYPES.Super + ) { + const tsObj = esTreeNodeToTSNodeMap.get(rightNode.object); + const objType = typeChecker.getTypeAtLocation(tsObj); + if (!isTypeAnyOrIterableType(objType, typeChecker)) { + if ( + !enforceForRenamedProperties || + !getNormalizedEnabledType(reportNode.type, 'object') + ) { + return; + } + context.report({ + node: reportNode, + messageId: 'preferDestructuring', + data: { type: 'object' }, + }); + return; + } + } + + if (reportNode.type === AST_NODE_TYPES.AssignmentExpression) { + rules.AssignmentExpression(reportNode); + } else { + rules.VariableDeclarator(reportNode); + } + } + + function getNormalizedEnabledType( + nodeType: + | AST_NODE_TYPES.VariableDeclarator + | AST_NODE_TYPES.AssignmentExpression, + destructuringType: 'array' | 'object', + ): boolean | undefined { + if ('object' in enabledTypes || 'array' in enabledTypes) { + return enabledTypes[destructuringType]; + } + return enabledTypes[nodeType as keyof typeof enabledTypes][ + destructuringType as keyof (typeof enabledTypes)[keyof typeof enabledTypes] + ]; + } + + function baseRulesWithoutFix(): ReturnType { + baseRulesWithoutFixCache ??= baseRule.create(noFixContext(context)); + return baseRulesWithoutFixCache; + } + }, +}); + +type Context = TSESLint.RuleContext; + +function noFixContext(context: Context): Context { + const customContext: { + report: Context['report']; + } = { + report: (descriptor): void => { + context.report({ + ...descriptor, + fix: undefined, + }); + }, + }; + + // we can't directly proxy `context` because its `report` property is non-configurable + // and non-writable. So we proxy `customContext` and redirect all + // property access to the original context except for `report` + return new Proxy(customContext as typeof context, { + get(target, path, receiver): unknown { + if (path !== 'report') { + return Reflect.get(context, path, receiver); + } + return Reflect.get(target, path, receiver); + }, + }); +} + +function isTypeAnyOrIterableType( + type: ts.Type, + typeChecker: ts.TypeChecker, +): boolean { + if (isTypeAnyType(type)) { + return true; + } + if (!type.isUnion()) { + const iterator = tsutils.getWellKnownSymbolPropertyOfType( + type, + 'iterator', + typeChecker, + ); + return iterator !== undefined; + } + return type.types.every(t => isTypeAnyOrIterableType(t, typeChecker)); +} + +function isArrayLiteralIntegerIndexAccess( + node: TSESTree.Expression, +): node is TSESTree.MemberExpression { + if (node.type !== AST_NODE_TYPES.MemberExpression) { + return false; + } + if (node.property.type !== AST_NODE_TYPES.Literal) { + return false; + } + return Number.isInteger(node.property.value); +} diff --git a/packages/eslint-plugin/src/util/getESLintCoreRule.ts b/packages/eslint-plugin/src/util/getESLintCoreRule.ts index 30de8347c0dd..6cfa0db393e9 100644 --- a/packages/eslint-plugin/src/util/getESLintCoreRule.ts +++ b/packages/eslint-plugin/src/util/getESLintCoreRule.ts @@ -34,6 +34,7 @@ interface RuleMap { 'no-restricted-globals': typeof import('eslint/lib/rules/no-restricted-globals'); 'object-curly-spacing': typeof import('eslint/lib/rules/object-curly-spacing'); 'prefer-const': typeof import('eslint/lib/rules/prefer-const'); + 'prefer-destructuring': typeof import('eslint/lib/rules/prefer-destructuring'); quotes: typeof import('eslint/lib/rules/quotes'); semi: typeof import('eslint/lib/rules/semi'); 'space-before-blocks': typeof import('eslint/lib/rules/space-before-blocks'); diff --git a/packages/eslint-plugin/tests/rules/prefer-destructuring.test.ts b/packages/eslint-plugin/tests/rules/prefer-destructuring.test.ts new file mode 100644 index 000000000000..812d317b18cb --- /dev/null +++ b/packages/eslint-plugin/tests/rules/prefer-destructuring.test.ts @@ -0,0 +1,1064 @@ +import { RuleTester } from '@typescript-eslint/rule-tester'; +import { AST_NODE_TYPES } from '@typescript-eslint/utils'; + +import rule from '../../src/rules/prefer-destructuring'; +import { getFixturesRootDir } from '../RuleTester'; + +const rootPath = getFixturesRootDir(); + +const ruleTester = new RuleTester({ + parser: '@typescript-eslint/parser', + parserOptions: { + sourceType: 'module', + tsconfigRootDir: rootPath, + project: './tsconfig.json', + }, +}); + +ruleTester.run('prefer-destructuring', rule, { + valid: [ + // type annotated + ` + declare const object: { foo: string }; + var foo: string = object.foo; + `, + ` + declare const array: number[]; + const bar: number = array[0]; + `, + // enforceForDeclarationWithTypeAnnotation: true + { + code: ` + declare const object: { foo: string }; + var { foo } = object; + `, + options: [ + { object: true }, + { enforceForDeclarationWithTypeAnnotation: true }, + ], + }, + { + code: ` + declare const object: { foo: string }; + var { foo }: { foo: number } = object; + `, + options: [ + { object: true }, + { enforceForDeclarationWithTypeAnnotation: true }, + ], + }, + { + code: ` + declare const array: number[]; + var [foo] = array; + `, + options: [ + { array: true }, + { enforceForDeclarationWithTypeAnnotation: true }, + ], + }, + { + code: ` + declare const array: number[]; + var [foo]: [foo: number] = array; + `, + options: [ + { object: true }, + { enforceForDeclarationWithTypeAnnotation: true }, + ], + }, + { + code: ` + declare const object: { bar: string }; + var foo: unknown = object.bar; + `, + options: [ + { object: true }, + { enforceForDeclarationWithTypeAnnotation: true }, + ], + }, + { + code: ` + declare const object: { foo: string }; + var { foo: bar } = object; + `, + options: [ + { object: true }, + { enforceForDeclarationWithTypeAnnotation: true }, + ], + }, + { + code: ` + declare const object: { foo: boolean }; + var { foo: bar }: { foo: boolean } = object; + `, + options: [ + { object: true }, + { enforceForDeclarationWithTypeAnnotation: true }, + ], + }, + { + code: ` + declare class Foo { + foo: string; + } + + class Bar extends Foo { + static foo() { + var foo: any = super.foo; + } + } + `, + options: [ + { object: true }, + { enforceForDeclarationWithTypeAnnotation: true }, + ], + }, + + // numeric property for iterable / non-iterable + ` + let x: { 0: unknown }; + let y = x[0]; + `, + ` + let x: { 0: unknown }; + y = x[0]; + `, + ` + let x: unknown; + let y = x[0]; + `, + ` + let x: unknown; + y = x[0]; + `, + ` + let x: { 0: unknown } | unknown[]; + let y = x[0]; + `, + ` + let x: { 0: unknown } | unknown[]; + y = x[0]; + `, + ` + let x: { 0: unknown } & (() => void); + let y = x[0]; + `, + ` + let x: { 0: unknown } & (() => void); + y = x[0]; + `, + ` + let x: Record; + let y = x[0]; + `, + ` + let x: Record; + y = x[0]; + `, + { + code: ` + let x: { 0: unknown }; + let { 0: y } = x; + `, + options: [ + { array: true, object: true }, + { enforceForRenamedProperties: true }, + ], + }, + { + code: ` + let x: { 0: unknown }; + ({ 0: y } = x); + `, + options: [ + { array: true, object: true }, + { enforceForRenamedProperties: true }, + ], + }, + { + code: ` + let x: { 0: unknown }; + let y = x[0]; + `, + options: [{ array: true }, { enforceForRenamedProperties: true }], + }, + { + code: ` + let x: { 0: unknown }; + y = x[0]; + `, + options: [{ array: true }, { enforceForRenamedProperties: true }], + }, + { + code: ` + let x: { 0: unknown }; + let y = x[0]; + `, + options: [ + { + VariableDeclarator: { array: true, object: false }, + AssignmentExpression: { array: true, object: true }, + }, + { enforceForRenamedProperties: true }, + ], + }, + { + code: ` + let x: { 0: unknown }; + y = x[0]; + `, + options: [ + { + VariableDeclarator: { array: true, object: true }, + AssignmentExpression: { array: true, object: false }, + }, + { enforceForRenamedProperties: true }, + ], + }, + { + code: ` + let x: Record; + let i: number = 0; + y = x[i]; + `, + options: [ + { object: false, array: true }, + { enforceForRenamedProperties: true }, + ], + }, + { + code: ` + let x: Record; + let i: 0 = 0; + y = x[i]; + `, + options: [ + { object: false, array: true }, + { enforceForRenamedProperties: true }, + ], + }, + { + code: ` + let x: Record; + let i: 0 | 1 | 2 = 0; + y = x[i]; + `, + options: [ + { object: false, array: true }, + { enforceForRenamedProperties: true }, + ], + }, + { + code: ` + let x: unknown[]; + let i: number = 0; + y = x[i]; + `, + options: [ + { object: false, array: true }, + { enforceForRenamedProperties: true }, + ], + }, + { + code: ` + let x: unknown[]; + let i: 0 = 0; + y = x[i]; + `, + options: [ + { object: false, array: true }, + { enforceForRenamedProperties: true }, + ], + }, + { + code: ` + let x: unknown[]; + let i: 0 | 1 | 2 = 0; + y = x[i]; + `, + options: [ + { object: false, array: true }, + { enforceForRenamedProperties: true }, + ], + }, + { + code: ` + let x: unknown[]; + let i: number = 0; + y = x[i]; + `, + options: [ + { object: true, array: true }, + { enforceForRenamedProperties: false }, + ], + }, + { + code: ` + let x: { 0: unknown }; + y += x[0]; + `, + options: [ + { object: true, array: true }, + { enforceForRenamedProperties: true }, + ], + }, + { + code: ` + class Bar { + public [0]: unknown; + } + class Foo extends Bar { + static foo() { + let y = super[0]; + } + } + `, + options: [ + { object: true, array: true }, + { enforceForRenamedProperties: true }, + ], + }, + { + code: ` + class Bar { + public [0]: unknown; + } + class Foo extends Bar { + static foo() { + y = super[0]; + } + } + `, + options: [ + { object: true, array: true }, + { enforceForRenamedProperties: true }, + ], + }, + + // already destructured + ` + let xs: unknown[] = [1]; + let [x] = xs; + `, + ` + const obj: { x: unknown } = { x: 1 }; + const { x } = obj; + `, + ` + var obj: { x: unknown } = { x: 1 }; + var { x: y } = obj; + `, + ` + let obj: { x: unknown } = { x: 1 }; + let key: 'x' = 'x'; + let { [key]: foo } = obj; + `, + ` + const obj: { x: unknown } = { x: 1 }; + let x: unknown; + ({ x } = obj); + `, + + // valid unless enforceForRenamedProperties is true + ` + let obj: { x: unknown } = { x: 1 }; + let y = obj.x; + `, + ` + var obj: { x: unknown } = { x: 1 }; + var y: unknown; + y = obj.x; + `, + ` + const obj: { x: unknown } = { x: 1 }; + const y = obj['x']; + `, + ` + let obj: Record = {}; + let key = 'abc'; + var y = obj[key]; + `, + + // shorthand operators shouldn't be reported; + ` + let obj: { x: number } = { x: 1 }; + let x = 10; + x += obj.x; + `, + ` + let obj: { x: boolean } = { x: false }; + let x = true; + x ||= obj.x; + `, + ` + const xs: number[] = [1]; + let x = 3; + x *= xs[0]; + `, + + // optional chaining shouldn't be reported + ` + let xs: unknown[] | undefined; + let x = xs?.[0]; + `, + ` + let obj: Record | undefined; + let x = obj?.x; + `, + + // private identifiers + ` + class C { + #foo: string; + + method() { + const foo: unknown = this.#foo; + } + } + `, + ` + class C { + #foo: string; + + method() { + let foo: unknown; + foo = this.#foo; + } + } + `, + { + code: ` + class C { + #foo: string; + + method() { + const bar: unknown = this.#foo; + } + } + `, + options: [ + { object: true, array: true }, + { enforceForDeclarationWithTypeAnnotation: true }, + ], + }, + { + code: ` + class C { + #foo: string; + + method(another: C) { + let bar: unknown; + bar: unknown = another.#foo; + } + } + `, + options: [ + { object: true, array: true }, + { enforceForDeclarationWithTypeAnnotation: true }, + ], + }, + { + code: ` + class C { + #foo: string; + + method() { + const foo: unknown = this.#foo; + } + } + `, + options: [ + { object: true, array: true }, + { enforceForDeclarationWithTypeAnnotation: true }, + ], + }, + ], + invalid: [ + // enforceForDeclarationWithTypeAnnotation: true + { + code: 'var foo: string = object.foo;', + options: [ + { object: true }, + { enforceForDeclarationWithTypeAnnotation: true }, + ], + output: null, + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, + { + code: 'var foo: string = array[0];', + options: [ + { array: true }, + { enforceForDeclarationWithTypeAnnotation: true }, + ], + output: null, + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'array' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, + { + code: 'var foo: unknown = object.bar;', + options: [ + { object: true }, + { + enforceForDeclarationWithTypeAnnotation: true, + enforceForRenamedProperties: true, + }, + ], + output: null, + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, + + // numeric property for iterable / non-iterable + { + code: ` + let x: { [Symbol.iterator]: unknown }; + let y = x[0]; + `, + output: null, + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'array' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, + { + code: ` + let x: { [Symbol.iterator]: unknown }; + y = x[0]; + `, + output: null, + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'array' }, + type: AST_NODE_TYPES.AssignmentExpression, + }, + ], + }, + { + code: ` + let x: [1, 2, 3]; + let y = x[0]; + `, + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'array' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, + { + code: ` + let x: [1, 2, 3]; + y = x[0]; + `, + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'array' }, + type: AST_NODE_TYPES.AssignmentExpression, + }, + ], + }, + { + code: ` + function* it() { + yield 1; + } + let y = it()[0]; + `, + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'array' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, + { + code: ` + function* it() { + yield 1; + } + y = it()[0]; + `, + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'array' }, + type: AST_NODE_TYPES.AssignmentExpression, + }, + ], + }, + { + code: ` + let x: any; + let y = x[0]; + `, + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'array' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, + { + code: ` + let x: any; + y = x[0]; + `, + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'array' }, + type: AST_NODE_TYPES.AssignmentExpression, + }, + ], + }, + { + code: ` + let x: string[] | { [Symbol.iterator]: unknown }; + let y = x[0]; + `, + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'array' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, + { + code: ` + let x: string[] | { [Symbol.iterator]: unknown }; + y = x[0]; + `, + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'array' }, + type: AST_NODE_TYPES.AssignmentExpression, + }, + ], + }, + { + code: ` + let x: object & unknown[]; + let y = x[0]; + `, + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'array' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, + { + code: ` + let x: object & unknown[]; + y = x[0]; + `, + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'array' }, + type: AST_NODE_TYPES.AssignmentExpression, + }, + ], + }, + { + code: ` + let x: { 0: string }; + let y = x[0]; + `, + options: [{ object: true }, { enforceForRenamedProperties: true }], + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, + { + code: ` + let x: { 0: string }; + y = x[0]; + `, + options: [{ object: true }, { enforceForRenamedProperties: true }], + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.AssignmentExpression, + }, + ], + }, + { + code: ` + let x: { 0: string }; + let y = x[0]; + `, + options: [ + { + VariableDeclarator: { object: true, array: false }, + AssignmentExpression: { object: false, array: false }, + }, + { enforceForRenamedProperties: true }, + ], + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, + { + code: ` + let x: { 0: string }; + y = x[0]; + `, + options: [ + { + VariableDeclarator: { object: false, array: false }, + AssignmentExpression: { object: true, array: false }, + }, + { enforceForRenamedProperties: true }, + ], + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.AssignmentExpression, + }, + ], + }, + { + code: ` + let x: Record; + let i: number = 0; + y = x[i]; + `, + options: [ + { object: true, array: true }, + { enforceForRenamedProperties: true }, + ], + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.AssignmentExpression, + }, + ], + }, + { + code: ` + let x: Record; + let i: 0 = 0; + y = x[i]; + `, + options: [ + { object: true, array: true }, + { enforceForRenamedProperties: true }, + ], + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.AssignmentExpression, + }, + ], + }, + { + code: ` + let x: Record; + let i: 0 | 1 | 2 = 0; + y = x[i]; + `, + options: [ + { object: true, array: true }, + { enforceForRenamedProperties: true }, + ], + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.AssignmentExpression, + }, + ], + }, + { + code: ` + let x: unknown[]; + let i: number = 0; + y = x[i]; + `, + options: [ + { object: true, array: true }, + { enforceForRenamedProperties: true }, + ], + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.AssignmentExpression, + }, + ], + }, + { + code: ` + let x: unknown[]; + let i: 0 = 0; + y = x[i]; + `, + options: [ + { object: true, array: true }, + { enforceForRenamedProperties: true }, + ], + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.AssignmentExpression, + }, + ], + }, + { + code: ` + let x: unknown[]; + let i: 0 | 1 | 2 = 0; + y = x[i]; + `, + options: [ + { object: true, array: true }, + { enforceForRenamedProperties: true }, + ], + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.AssignmentExpression, + }, + ], + }, + { + code: ` + let x: { 0: unknown } | unknown[]; + let y = x[0]; + `, + options: [{ object: true }, { enforceForRenamedProperties: true }], + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, + { + code: ` + let x: { 0: unknown } | unknown[]; + y = x[0]; + `, + options: [{ object: true }, { enforceForRenamedProperties: true }], + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.AssignmentExpression, + }, + ], + }, + + // auto fixes + { + code: ` + let obj = { foo: 'bar' }; + const foo = obj.foo; + `, + output: ` + let obj = { foo: 'bar' }; + const {foo} = obj; + `, + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, + { + code: ` + let obj = { foo: 'bar' }; + var x: null = null; + const foo = (x, obj).foo; + `, + output: ` + let obj = { foo: 'bar' }; + var x: null = null; + const {foo} = (x, obj); + `, + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, + { + code: 'const call = (() => null).call;', + output: 'const {call} = () => null;', + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, + { + code: ` + const obj = { foo: 'bar' }; + let a: any; + var foo = (a = obj).foo; + `, + output: ` + const obj = { foo: 'bar' }; + let a: any; + var {foo} = a = obj; + `, + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, + { + code: ` + const obj = { asdf: { qwer: null } }; + const qwer = obj.asdf.qwer; + `, + output: ` + const obj = { asdf: { qwer: null } }; + const {qwer} = obj.asdf; + `, + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, + { + code: ` + const obj = { foo: 100 }; + const /* comment */ foo = obj.foo; + `, + output: ` + const obj = { foo: 100 }; + const /* comment */ {foo} = obj; + `, + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, + + // enforceForRenamedProperties: true + { + code: ` + let obj = { foo: 'bar' }; + const x = obj.foo; + `, + output: null, + options: [{ object: true }, { enforceForRenamedProperties: true }], + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, + { + code: ` + let obj = { foo: 'bar' }; + let x: unknown; + x = obj.foo; + `, + output: null, + options: [{ object: true }, { enforceForRenamedProperties: true }], + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.AssignmentExpression, + }, + ], + }, + { + code: ` + let obj: Record; + let key = 'abc'; + const x = obj[key]; + `, + output: null, + options: [{ object: true }, { enforceForRenamedProperties: true }], + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, + { + code: ` + let obj: Record; + let key = 'abc'; + let x: unknown; + x = obj[key]; + `, + output: null, + options: [{ object: true }, { enforceForRenamedProperties: true }], + errors: [ + { + messageId: 'preferDestructuring', + data: { type: 'object' }, + type: AST_NODE_TYPES.AssignmentExpression, + }, + ], + }, + ], +}); diff --git a/packages/eslint-plugin/tests/schema-snapshots/prefer-destructuring.shot b/packages/eslint-plugin/tests/schema-snapshots/prefer-destructuring.shot new file mode 100644 index 000000000000..ca0e2597bf59 --- /dev/null +++ b/packages/eslint-plugin/tests/schema-snapshots/prefer-destructuring.shot @@ -0,0 +1,94 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Rule schemas should be convertible to TS types for documentation purposes prefer-destructuring 1`] = ` +" +# SCHEMA: + +[ + { + "oneOf": [ + { + "additionalProperties": false, + "properties": { + "AssignmentExpression": { + "additionalProperties": false, + "properties": { + "array": { + "type": "boolean" + }, + "object": { + "type": "boolean" + } + }, + "type": "object" + }, + "VariableDeclarator": { + "additionalProperties": false, + "properties": { + "array": { + "type": "boolean" + }, + "object": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "array": { + "type": "boolean" + }, + "object": { + "type": "boolean" + } + }, + "type": "object" + } + ] + }, + { + "properties": { + "enforceForDeclarationWithTypeAnnotation": { + "type": "boolean" + }, + "enforceForRenamedProperties": { + "type": "boolean" + } + }, + "type": "object" + } +] + + +# TYPES: + +type Options = [ + ( + | { + AssignmentExpression?: { + array?: boolean; + object?: boolean; + }; + VariableDeclarator?: { + array?: boolean; + object?: boolean; + }; + } + | { + array?: boolean; + object?: boolean; + } + ), + { + enforceForDeclarationWithTypeAnnotation?: boolean; + enforceForRenamedProperties?: boolean; + [k: string]: unknown; + }, +]; +" +`; diff --git a/packages/eslint-plugin/typings/eslint-rules.d.ts b/packages/eslint-plugin/typings/eslint-rules.d.ts index 295dd4d757c5..dea1fcd69972 100644 --- a/packages/eslint-plugin/typings/eslint-rules.d.ts +++ b/packages/eslint-plugin/typings/eslint-rules.d.ts @@ -966,6 +966,33 @@ declare module 'eslint/lib/rules/prefer-const' { export = rule; } +declare module 'eslint/lib/rules/prefer-destructuring' { + import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; + + interface DestructuringTypeConfig { + object?: boolean; + array?: boolean; + } + type Option0 = + | DestructuringTypeConfig + | { + VariableDeclarator?: DestructuringTypeConfig; + AssignmentExpression?: DestructuringTypeConfig; + }; + interface Option1 { + enforceForRenamedProperties?: boolean; + } + const rule: TSESLint.RuleModule< + 'preferDestructuring', + [Option0, Option1?], + { + VariableDeclarator(node: TSESTree.VariableDeclarator): void; + AssignmentExpression(node: TSESTree.AssignmentExpression): void; + } + >; + export = rule; +} + declare module 'eslint/lib/rules/object-curly-spacing' { import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; From 3d58813ac9ccd758e440b8e8ba55fef9b88f6058 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Sun, 15 Oct 2023 10:28:15 -0400 Subject: [PATCH 16/16] build: fix introduced post-merge build break with no-useless-empty-export --- packages/eslint-plugin/src/rules/no-useless-empty-export.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-useless-empty-export.ts b/packages/eslint-plugin/src/rules/no-useless-empty-export.ts index 2fc04b3746af..524e0fc9c082 100644 --- a/packages/eslint-plugin/src/rules/no-useless-empty-export.ts +++ b/packages/eslint-plugin/src/rules/no-useless-empty-export.ts @@ -1,7 +1,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import { createRule } from '../util'; +import { createRule, isDefinitionFile } from '../util'; function isEmptyExport( node: TSESTree.Node, @@ -43,7 +43,7 @@ export default createRule({ // In a definition file, export {} is necessary to make the module properly // encapsulated, even when there are other exports // https://github.com/typescript-eslint/typescript-eslint/issues/4975 - if (util.isDefinitionFile(context.getFilename())) { + if (isDefinitionFile(context.getFilename())) { return {}; } function checkNode(