Skip to content

WIP Integrate used tsutils functions #5689

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 26 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
bdde634
WIP Integrate used tsutils functions
varwasabi Sep 25, 2022
ffb2dd1
Add `isJsxExpression`
varwasabi Sep 25, 2022
1342253
Add `isNewExpression`
varwasabi Sep 25, 2022
84b2283
Add `isPropertyDeclaration`
varwasabi Sep 25, 2022
daf96d3
Add `isPropertyAssignment`
varwasabi Sep 25, 2022
03f3d00
Add `isUnionOrIntersectionType`
varwasabi Sep 25, 2022
371b6b1
Add `isValidPropertyAccess`
varwasabi Sep 25, 2022
b74a090
Add `isParameterDeclaration`
varwasabi Sep 25, 2022
066efc0
Add `isObjectType`
varwasabi Sep 25, 2022
844cb10
Add `isObjectFlagSet`
varwasabi Sep 25, 2022
4bd0bd0
Add `isModifierFlagSet`
varwasabi Sep 25, 2022
64ea998
Add `isVariableDeclaration`
varwasabi Sep 25, 2022
2090ade
Add `isStrictCompilerOptionEnabled`
varwasabi Sep 25, 2022
2f11a14
Add `isSymbolFlagSet`
varwasabi Sep 25, 2022
bc8f8cc
Add `isThenableType`
varwasabi Sep 25, 2022
fe48d85
Add `getWellKnownSymbolPropertyOfType`
varwasabi Sep 25, 2022
cffe5d3
Add `isCompilerOptionEnabled`
varwasabi Sep 25, 2022
cb5f139
Remove various usages of tsutils
varwasabi Sep 25, 2022
b6f1705
Add `isExpression`
varwasabi Sep 25, 2022
e11c028
Remove tsutils import from `CUSTOM_RULES.md`
varwasabi Sep 25, 2022
e324b3f
Add `isLiteralType`
varwasabi Sep 25, 2022
5661313
Add `isFalsyType`
varwasabi Sep 25, 2022
81cdc88
Add `getCallSignaturesOfType`
varwasabi Sep 25, 2022
8457217
Add `isFunctionScopeBoundary`
varwasabi Sep 25, 2022
eb35908
Use original isTypeFlagSet
varwasabi Sep 25, 2022
4f1cbd7
Merge branch 'main' into integrate-tsutils
varwasabi Sep 28, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/development/CUSTOM_RULES.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,9 @@ By mapping from ESTree nodes to TypeScript nodes and retrieving the TypeScript p
This rule bans for-of looping over an enum by using the type-checker via typescript-eslint and TypeScript APIs:

```ts
import { isTypeFlagSet } from '@typescript-eslint/type-utils';
import { ESLintUtils } from '@typescript-eslint/utils';
import * as ts from 'typescript';
import * as tsutils from 'tsutils';

export const rule = createRule({
create(context) {
Expand All @@ -241,7 +241,7 @@ export const rule = createRule({
const nodeType = checker.getTypeAtLocation(originalNode);

// 3. Check the TS node type using the TypeScript APIs
if (tsutils.isTypeFlagSet(nodeType, ts.TypeFlags.EnumLike)) {
if (isTypeFlagSet(nodeType, ts.TypeFlags.EnumLike)) {
context.report({
messageId: 'loopOverEnum',
node: node.right,
Expand Down
4 changes: 2 additions & 2 deletions packages/eslint-plugin/src/rules/await-thenable.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as tsutils from 'tsutils';
import { isThenableType } from '@typescript-eslint/type-utils';

import * as util from '../util';

Expand Down Expand Up @@ -30,7 +30,7 @@ export default util.createRule({
if (
!util.isTypeAnyType(type) &&
!util.isTypeUnknownType(type) &&
!tsutils.isThenableType(checker, originalNode.expression, type)
!isThenableType(checker, originalNode.expression, type)
) {
context.report({
messageId: 'await',
Expand Down
5 changes: 2 additions & 3 deletions packages/eslint-plugin/src/rules/dot-notation.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { isCompilerOptionEnabled } from '@typescript-eslint/type-utils';
import type { TSESTree } from '@typescript-eslint/utils';
import * as tsutils from 'tsutils';
import * as ts from 'typescript';

import type {
Expand Down Expand Up @@ -77,9 +77,8 @@ export default createRule<Options, MessageIds>({
options.allowProtectedClassPropertyAccess;
const allowIndexSignaturePropertyAccess =
(options.allowIndexSignaturePropertyAccess ?? false) ||
tsutils.isCompilerOptionEnabled(
isCompilerOptionEnabled(
program.getCompilerOptions(),
// @ts-expect-error - TS is refining the type to never for some reason
'noPropertyAccessFromIndexSignature',
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { isTypeFlagSet } from '@typescript-eslint/type-utils';
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import * as tsutils from 'tsutils';
import * as ts from 'typescript';

import * as util from '../util';
Expand Down Expand Up @@ -84,7 +84,7 @@ export default util.createRule<Options, MessageId>({
const checker = parserServices.program.getTypeChecker();
const tsNode = parserServices.esTreeNodeToTSNodeMap.get(node);
const type = util.getConstrainedTypeAtLocation(checker, tsNode);
if (!tsutils.isTypeFlagSet(type, ts.TypeFlags.VoidLike)) {
if (!isTypeFlagSet(type, ts.TypeFlags.VoidLike)) {
// not a void expression
return;
}
Expand Down
5 changes: 2 additions & 3 deletions packages/eslint-plugin/src/rules/no-dynamic-delete.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { isValidPropertyAccess } from '@typescript-eslint/type-utils';
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import * as tsutils from 'tsutils';

import * as util from '../util';

Expand Down Expand Up @@ -96,7 +96,6 @@ function isNecessaryDynamicAccess(property: TSESTree.Expression): boolean {
}

return (
typeof property.value === 'string' &&
!tsutils.isValidPropertyAccess(property.value)
typeof property.value === 'string' && !isValidPropertyAccess(property.value)
);
}
8 changes: 4 additions & 4 deletions packages/eslint-plugin/src/rules/no-floating-promises.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { unionTypeParts } from '@typescript-eslint/type-utils';
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import * as tsutils from 'tsutils';
import type * as ts from 'typescript';

import * as util from '../util';
Expand Down Expand Up @@ -183,7 +183,7 @@ export default util.createRule<Options, MessageId>({
// https://github.com/ajafff/tsutils/blob/49d0d31050b44b81e918eae4fbaf1dfe7b7286af/util/type.ts#L95-L125
function isPromiseLike(checker: ts.TypeChecker, node: ts.Node): boolean {
const type = checker.getTypeAtLocation(node);
for (const ty of tsutils.unionTypeParts(checker.getApparentType(type))) {
for (const ty of unionTypeParts(checker.getApparentType(type))) {
const then = ty.getProperty('then');
if (then === undefined) {
continue;
Expand All @@ -209,7 +209,7 @@ function hasMatchingSignature(
type: ts.Type,
matcher: (signature: ts.Signature) => boolean,
): boolean {
for (const t of tsutils.unionTypeParts(type)) {
for (const t of unionTypeParts(type)) {
if (t.getCallSignatures().some(matcher)) {
return true;
}
Expand All @@ -226,7 +226,7 @@ function isFunctionParam(
const type: ts.Type | undefined = checker.getApparentType(
checker.getTypeOfSymbolAtLocation(param, node),
);
for (const t of tsutils.unionTypeParts(type)) {
for (const t of unionTypeParts(type)) {
if (t.getCallSignatures().length !== 0) {
return true;
}
Expand Down
7 changes: 2 additions & 5 deletions packages/eslint-plugin/src/rules/no-implied-eval.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { isSymbolFlagSet } from '@typescript-eslint/type-utils';
import type { TSESTree } from '@typescript-eslint/utils';
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import * as tsutils from 'tsutils';
import * as ts from 'typescript';

import * as util from '../util';
Expand Down Expand Up @@ -71,10 +71,7 @@ export default util.createRule({

if (
symbol &&
tsutils.isSymbolFlagSet(
symbol,
ts.SymbolFlags.Function | ts.SymbolFlags.Method,
)
isSymbolFlagSet(symbol, ts.SymbolFlags.Function | ts.SymbolFlags.Method)
) {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { unionTypeParts } from '@typescript-eslint/type-utils';
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
import { ESLintUtils } from '@typescript-eslint/utils';
import * as tsutils from 'tsutils';
import * as ts from 'typescript';

import * as util from '../util';
Expand Down Expand Up @@ -64,7 +64,7 @@ export default util.createRule<
node.argument,
);
const argType = checker.getTypeAtLocation(argTsNode);
const unionParts = tsutils.unionTypeParts(argType);
const unionParts = unionTypeParts(argType);
if (
unionParts.every(
part => part.flags & (ts.TypeFlags.Void | ts.TypeFlags.Undefined),
Expand Down
31 changes: 18 additions & 13 deletions packages/eslint-plugin/src/rules/no-misused-promises.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import {
isCallExpression,
isThenableType,
isTypeFlagSet,
unionTypeParts,
} from '@typescript-eslint/type-utils';
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import * as tsutils from 'tsutils';
import * as ts from 'typescript';

import * as util from '../util';
Expand Down Expand Up @@ -410,8 +415,8 @@ export default util.createRule<Options, MessageId>({
function isSometimesThenable(checker: ts.TypeChecker, node: ts.Node): boolean {
const type = checker.getTypeAtLocation(node);

for (const subType of tsutils.unionTypeParts(checker.getApparentType(type))) {
if (tsutils.isThenableType(checker, node, subType)) {
for (const subType of unionTypeParts(checker.getApparentType(type))) {
if (isThenableType(checker, node, subType)) {
return true;
}
}
Expand All @@ -426,7 +431,7 @@ function isSometimesThenable(checker: ts.TypeChecker, node: ts.Node): boolean {
function isAlwaysThenable(checker: ts.TypeChecker, node: ts.Node): boolean {
const type = checker.getTypeAtLocation(node);

for (const subType of tsutils.unionTypeParts(checker.getApparentType(type))) {
for (const subType of unionTypeParts(checker.getApparentType(type))) {
const thenProp = subType.getProperty('then');

// If one of the alternates has no then property, it is not thenable in all
Expand All @@ -440,7 +445,7 @@ function isAlwaysThenable(checker: ts.TypeChecker, node: ts.Node): boolean {
// be of the right form to consider it thenable.
const thenType = checker.getTypeOfSymbolAtLocation(thenProp, node);
let hasThenableSignature = false;
for (const subType of tsutils.unionTypeParts(thenType)) {
for (const subType of unionTypeParts(thenType)) {
for (const signature of subType.getCallSignatures()) {
if (
signature.parameters.length !== 0 &&
Expand Down Expand Up @@ -478,7 +483,7 @@ function isFunctionParam(
const type: ts.Type | undefined = checker.getApparentType(
checker.getTypeOfSymbolAtLocation(param, node),
);
for (const subType of tsutils.unionTypeParts(type)) {
for (const subType of unionTypeParts(type)) {
if (subType.getCallSignatures().length !== 0) {
return true;
}
Expand All @@ -500,9 +505,9 @@ function voidFunctionParams(
// We can't use checker.getResolvedSignature because it prefers an early '() => void' over a later '() => Promise<void>'
// See https://github.com/microsoft/TypeScript/issues/48077

for (const subType of tsutils.unionTypeParts(type)) {
for (const subType of unionTypeParts(type)) {
// Standard function calls and `new` have two different types of signatures
const signatures = ts.isCallExpression(node)
const signatures = isCallExpression(node)
? subType.getCallSignatures()
: subType.getConstructSignatures();
for (const signature of signatures) {
Expand Down Expand Up @@ -540,7 +545,7 @@ function anySignatureIsThenableType(
): boolean {
for (const signature of type.getCallSignatures()) {
const returnType = signature.getReturnType();
if (tsutils.isThenableType(checker, node, returnType)) {
if (isThenableType(checker, node, returnType)) {
return true;
}
}
Expand All @@ -556,7 +561,7 @@ function isThenableReturningFunctionType(
node: ts.Node,
type: ts.Type,
): boolean {
for (const subType of tsutils.unionTypeParts(type)) {
for (const subType of unionTypeParts(type)) {
if (anySignatureIsThenableType(checker, node, subType)) {
return true;
}
Expand All @@ -575,17 +580,17 @@ function isVoidReturningFunctionType(
): boolean {
let hadVoidReturn = false;

for (const subType of tsutils.unionTypeParts(type)) {
for (const subType of unionTypeParts(type)) {
for (const signature of subType.getCallSignatures()) {
const returnType = signature.getReturnType();

// If a certain positional argument accepts both thenable and void returns,
// a promise-returning function is valid
if (tsutils.isThenableType(checker, node, returnType)) {
if (isThenableType(checker, node, returnType)) {
return false;
}

hadVoidReturn ||= tsutils.isTypeFlagSet(returnType, ts.TypeFlags.Void);
hadVoidReturn ||= isTypeFlagSet(returnType, ts.TypeFlags.Void);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import {
isBooleanLiteralType,
unionTypeParts,
} from '@typescript-eslint/type-utils';
import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils';
import * as tsutils from 'tsutils';
import * as ts from 'typescript';

import * as util from '../util';
Expand Down Expand Up @@ -106,11 +109,11 @@ function describeLiteralType(type: ts.Type): string {
return `${type.value.negative ? '-' : ''}${type.value.base10Value}n`;
}

if (tsutils.isBooleanLiteralType(type, true)) {
if (isBooleanLiteralType(type, true)) {
return 'true';
}

if (tsutils.isBooleanLiteralType(type, false)) {
if (isBooleanLiteralType(type, false)) {
return 'false';
}

Expand Down Expand Up @@ -167,10 +170,10 @@ function isNodeInsideReturnType(node: TSESTree.TSUnionType): boolean {
function unionTypePartsUnlessBoolean(type: ts.Type): ts.Type[] {
return type.isUnion() &&
type.types.length === 2 &&
tsutils.isBooleanLiteralType(type.types[0], false) &&
tsutils.isBooleanLiteralType(type.types[1], true)
isBooleanLiteralType(type.types[0], false) &&
isBooleanLiteralType(type.types[1], true)
? [type]
: tsutils.unionTypeParts(type);
: unionTypeParts(type);
}

export default util.createRule({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { TSESTree } from '@typescript-eslint/utils';
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import * as tsutils from 'tsutils';
import { isTypeFlagSet } from 'tsutils';
import * as ts from 'typescript';

import * as util from '../util';
Expand Down Expand Up @@ -113,7 +113,7 @@ export default util.createRule<Options, MessageIds>({
}

function isBooleanType(expressionType: ts.Type): boolean {
return tsutils.isTypeFlagSet(
return isTypeFlagSet(
expressionType,
ts.TypeFlags.Boolean | ts.TypeFlags.BooleanLiteral,
);
Expand All @@ -134,10 +134,7 @@ export default util.createRule<Options, MessageIds>({

const nonNullishTypes = types.filter(
type =>
!tsutils.isTypeFlagSet(
type,
ts.TypeFlags.Undefined | ts.TypeFlags.Null,
),
!isTypeFlagSet(type, ts.TypeFlags.Undefined | ts.TypeFlags.Null),
);

const hasNonNullishType = nonNullishTypes.length > 0;
Expand Down
6 changes: 3 additions & 3 deletions packages/eslint-plugin/src/rules/no-unnecessary-condition.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import type { TSESTree } from '@typescript-eslint/utils';
import { AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/utils';
import {
getCallSignaturesOfType,
isBooleanLiteralType,
isFalsyType,
isLiteralType,
isStrictCompilerOptionEnabled,
unionTypeParts,
} from 'tsutils';
} from '@typescript-eslint/type-utils';
import type { TSESTree } from '@typescript-eslint/utils';
import { AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/utils';
import * as ts from 'typescript';

import {
Expand Down
4 changes: 2 additions & 2 deletions packages/eslint-plugin/src/rules/no-unnecessary-qualifier.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { isSymbolFlagSet } from '@typescript-eslint/type-utils';
import type { TSESTree } from '@typescript-eslint/utils';
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import * as tsutils from 'tsutils';
import * as ts from 'typescript';

import * as util from '../util';
Expand Down Expand Up @@ -35,7 +35,7 @@ export default util.createRule({
symbol: ts.Symbol,
checker: ts.TypeChecker,
): ts.Symbol | null {
return tsutils.isSymbolFlagSet(symbol, ts.SymbolFlags.Alias)
return isSymbolFlagSet(symbol, ts.SymbolFlags.Alias)
? checker.getAliasedSymbol(symbol)
: null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import {
isCallExpression,
isSymbolFlagSet,
} from '@typescript-eslint/type-utils';
import type { TSESTree } from '@typescript-eslint/utils';
import * as tsutils from 'tsutils';
import * as ts from 'typescript';

import * as util from '../util';
Expand Down Expand Up @@ -129,7 +132,7 @@ function getTypeParametersFromNode(
return getTypeParametersFromType(node.typeName, checker);
}

if (ts.isCallExpression(node) || ts.isNewExpression(node)) {
if (isCallExpression(node) || ts.isNewExpression(node)) {
return getTypeParametersFromCall(node, checker);
}

Expand Down Expand Up @@ -180,7 +183,7 @@ function getAliasedSymbol(
symbol: ts.Symbol,
checker: ts.TypeChecker,
): ts.Symbol {
return tsutils.isSymbolFlagSet(symbol, ts.SymbolFlags.Alias)
return isSymbolFlagSet(symbol, ts.SymbolFlags.Alias)
? checker.getAliasedSymbol(symbol)
: symbol;
}
Loading