Skip to content
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

fix: replace tsutils with ts-api-tools #6428

Merged
merged 5 commits into from Feb 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion .cspell.json
Expand Up @@ -114,7 +114,6 @@
"triaging",
"tsconfigs",
"tseslint",
"tsutils",
"tsvfs",
"typedef",
"typedefs",
Expand Down
4 changes: 2 additions & 2 deletions docs/Custom_Rules.mdx
Expand Up @@ -230,8 +230,8 @@ This rule bans for-of looping over an enum by using the TypeScript type checker

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

export const rule = createRule({
create(context) {
Expand All @@ -244,7 +244,7 @@ export const rule = createRule({
const type = services.getTypeAtLocation(node);

// 3. Check the TS type using the TypeScript APIs
if (tsutils.isTypeFlagSet(nodeType, ts.TypeFlags.EnumLike)) {
if (tools.isTypeFlagSet(nodeType, ts.TypeFlags.EnumLike)) {
context.report({
messageId: 'loopOverEnum',
node: node.right,
Expand Down
1 change: 1 addition & 0 deletions jest.config.base.js
Expand Up @@ -11,6 +11,7 @@ module.exports = {
'tsx',
'mts',
'mtsx',
'cjs',
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ts-api-tools formats its output files as .js with ES modules. But it also includes an additional set of .cjs files for CJS users. This allows Jest to consider .cjs files (which it didn't before) - and look at them before .js files.

'js',
'jsx',
'mjs',
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin/package.json
Expand Up @@ -53,7 +53,7 @@
"natural-compare-lite": "^1.4.0",
"regexpp": "^3.2.0",
"semver": "^7.3.7",
"tsutils": "^3.21.0"
"ts-api-tools": "^0.0.15"
},
"devDependencies": {
"@types/debug": "*",
Expand Down
4 changes: 2 additions & 2 deletions packages/eslint-plugin/src/rules/await-thenable.ts
@@ -1,4 +1,4 @@
import * as tsutils from 'tsutils';
import * as tools from 'ts-api-tools';

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

Expand Down Expand Up @@ -31,7 +31,7 @@ export default util.createRule({

const originalNode = services.esTreeNodeToTSNodeMap.get(node);

if (!tsutils.isThenableType(checker, originalNode.expression, type)) {
if (!tools.isThenableType(checker, originalNode.expression, type)) {
context.report({
messageId: 'await',
node,
Expand Down
4 changes: 2 additions & 2 deletions packages/eslint-plugin/src/rules/dot-notation.ts
@@ -1,5 +1,5 @@
import type { TSESTree } from '@typescript-eslint/utils';
import * as tsutils from 'tsutils';
import * as tools from 'ts-api-tools';
import * as ts from 'typescript';

import type {
Expand Down Expand Up @@ -75,7 +75,7 @@ export default createRule<Options, MessageIds>({
options.allowProtectedClassPropertyAccess;
const allowIndexSignaturePropertyAccess =
(options.allowIndexSignaturePropertyAccess ?? false) ||
tsutils.isCompilerOptionEnabled(
tools.isCompilerOptionEnabled(
services.program.getCompilerOptions(),
// @ts-expect-error - TS is refining the type to never for some reason
'noPropertyAccessFromIndexSignature',
Expand Down
@@ -1,6 +1,6 @@
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import * as tsutils from 'tsutils';
import * as tools from 'ts-api-tools';
import * as ts from 'typescript';

import * as util from '../util';
Expand Down Expand Up @@ -82,7 +82,7 @@ export default util.createRule<Options, MessageId>({
): void {
const services = util.getParserServices(context);
const type = util.getConstrainedTypeAtLocation(services, node);
if (!tsutils.isTypeFlagSet(type, ts.TypeFlags.VoidLike)) {
if (!tools.isTypeFlagSet(type, ts.TypeFlags.VoidLike)) {
// not a void expression
return;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/eslint-plugin/src/rules/no-dynamic-delete.ts
@@ -1,6 +1,6 @@
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import * as tsutils from 'tsutils';
import * as tools from 'ts-api-tools';

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

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

return (
typeof property.value === 'string' &&
!tsutils.isValidPropertyAccess(property.value)
!tools.isValidPropertyAccess(property.value)
);
}
10 changes: 5 additions & 5 deletions packages/eslint-plugin/src/rules/no-floating-promises.ts
@@ -1,6 +1,6 @@
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import * as tsutils from 'tsutils';
import * as tools from 'ts-api-tools';
import * as ts from 'typescript';

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

function isHigherPrecedenceThanUnary(node: ts.Node): boolean {
const operator = tsutils.isBinaryExpression(node)
const operator = ts.isBinaryExpression(node)
? node.operatorToken.kind
: ts.SyntaxKind.Unknown;
const nodePrecedence = util.getOperatorPrecedence(node.kind, operator);
Expand Down Expand Up @@ -240,7 +240,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 tools.unionTypeParts(checker.getApparentType(type))) {
const then = ty.getProperty('then');
if (then === undefined) {
continue;
Expand All @@ -266,7 +266,7 @@ function hasMatchingSignature(
type: ts.Type,
matcher: (signature: ts.Signature) => boolean,
): boolean {
for (const t of tsutils.unionTypeParts(type)) {
for (const t of tools.unionTypeParts(type)) {
if (t.getCallSignatures().some(matcher)) {
return true;
}
Expand All @@ -283,7 +283,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 tools.unionTypeParts(type)) {
if (t.getCallSignatures().length !== 0) {
return true;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/eslint-plugin/src/rules/no-implied-eval.ts
@@ -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 * as tools from 'ts-api-tools';
import * as ts from 'typescript';

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

if (
symbol &&
tsutils.isSymbolFlagSet(
tools.isSymbolFlagSet(
symbol,
ts.SymbolFlags.Function | ts.SymbolFlags.Method,
)
Expand Down
@@ -1,6 +1,6 @@
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
import { ESLintUtils } from '@typescript-eslint/utils';
import * as tsutils from 'tsutils';
import * as tools from 'ts-api-tools';
import * as ts from 'typescript';

import * as util from '../util';
Expand Down Expand Up @@ -61,7 +61,7 @@ export default util.createRule<
};

const argType = services.getTypeAtLocation(node.argument);
const unionParts = tsutils.unionTypeParts(argType);
const unionParts = tools.unionTypeParts(argType);
if (
unionParts.every(
part => part.flags & (ts.TypeFlags.Void | ts.TypeFlags.Undefined),
Expand Down
24 changes: 12 additions & 12 deletions packages/eslint-plugin/src/rules/no-misused-promises.ts
@@ -1,6 +1,6 @@
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import * as tsutils from 'tsutils';
import * as tools from 'ts-api-tools';
import * as ts from 'typescript';

import * as util from '../util';
Expand Down Expand Up @@ -410,8 +410,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 tools.unionTypeParts(checker.getApparentType(type))) {
if (tools.isThenableType(checker, node, subType)) {
return true;
}
}
Expand All @@ -426,7 +426,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 tools.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 +440,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 tools.unionTypeParts(thenType)) {
for (const signature of subType.getCallSignatures()) {
if (
signature.parameters.length !== 0 &&
Expand Down Expand Up @@ -478,7 +478,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 tools.unionTypeParts(type)) {
if (subType.getCallSignatures().length !== 0) {
return true;
}
Expand Down Expand Up @@ -527,7 +527,7 @@ function voidFunctionArguments(
// 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 tools.unionTypeParts(type)) {
// Standard function calls and `new` have two different types of signatures
const signatures = ts.isCallExpression(node)
? subType.getCallSignatures()
Expand Down Expand Up @@ -610,7 +610,7 @@ function anySignatureIsThenableType(
): boolean {
for (const signature of type.getCallSignatures()) {
const returnType = signature.getReturnType();
if (tsutils.isThenableType(checker, node, returnType)) {
if (tools.isThenableType(checker, node, returnType)) {
return true;
}
}
Expand All @@ -626,7 +626,7 @@ function isThenableReturningFunctionType(
node: ts.Node,
type: ts.Type,
): boolean {
for (const subType of tsutils.unionTypeParts(type)) {
for (const subType of tools.unionTypeParts(type)) {
if (anySignatureIsThenableType(checker, node, subType)) {
return true;
}
Expand All @@ -645,17 +645,17 @@ function isVoidReturningFunctionType(
): boolean {
let hadVoidReturn = false;

for (const subType of tsutils.unionTypeParts(type)) {
for (const subType of tools.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 (tools.isThenableType(checker, node, returnType)) {
return false;
}

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

Expand Down
@@ -1,5 +1,5 @@
import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils';
import * as tsutils from 'tsutils';
import * as tools from 'ts-api-tools';
import * as ts from 'typescript';

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

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

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

Expand Down Expand Up @@ -166,10 +166,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)
tools.isBooleanLiteralType(type.types[0], false) &&
tools.isBooleanLiteralType(type.types[1], true)
? [type]
: tsutils.unionTypeParts(type);
: tools.unionTypeParts(type);
}

export default util.createRule({
Expand Down
@@ -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 * as tools from 'ts-api-tools';
import * as ts from 'typescript';

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

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

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