From d004c95ec16f96cb0b14b5cab09c7cabfa2ba71d Mon Sep 17 00:00:00 2001 From: arka1002 Date: Mon, 22 Jan 2024 15:01:13 +0530 Subject: [PATCH 1/3] chore(type-utils): reuse newly added "is builtin symbol like" logic fixes: #8234 --- .../eslint-plugin/src/rules/no-implied-eval.ts | 18 ++++-------------- packages/type-utils/src/builtinSymbolLikes.ts | 12 ++++++++++++ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-implied-eval.ts b/packages/eslint-plugin/src/rules/no-implied-eval.ts index 8c6d9bc74338..e3ba27068043 100644 --- a/packages/eslint-plugin/src/rules/no-implied-eval.ts +++ b/packages/eslint-plugin/src/rules/no-implied-eval.ts @@ -1,6 +1,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import { getScope } from '@typescript-eslint/utils/eslint-utils'; +import { isFunctionLike } from '@typescript-eslint/type-utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; @@ -80,13 +81,7 @@ export default createRule({ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison if (symbol && symbol.escapedName === FUNCTION_CONSTRUCTOR) { - const declarations = symbol.getDeclarations() ?? []; - for (const declaration of declarations) { - const sourceFile = declaration.getSourceFile(); - if (services.program.isSourceFileDefaultLibrary(sourceFile)) { - return true; - } - } + return isFunctionLike(services.program, type); } const signatures = checker.getSignaturesOfType( @@ -143,13 +138,8 @@ export default createRule({ const type = services.getTypeAtLocation(node.callee); const symbol = type.getSymbol(); if (symbol) { - const declarations = symbol.getDeclarations() ?? []; - for (const declaration of declarations) { - const sourceFile = declaration.getSourceFile(); - if (services.program.isSourceFileDefaultLibrary(sourceFile)) { - context.report({ node, messageId: 'noFunctionConstructor' }); - return; - } + if (isFunctionLike(services.program, type)) { + context.report({ node, messageId: 'noFunctionConstructor' }); } } else { context.report({ node, messageId: 'noFunctionConstructor' }); diff --git a/packages/type-utils/src/builtinSymbolLikes.ts b/packages/type-utils/src/builtinSymbolLikes.ts index 3443a0d0382e..4f494165225b 100644 --- a/packages/type-utils/src/builtinSymbolLikes.ts +++ b/packages/type-utils/src/builtinSymbolLikes.ts @@ -69,6 +69,18 @@ export function isReadonlyTypeLike( ); }); } +/** + * let F = new Function("foo"); + * ^ FunctionLike + * let I = (callback: Function) => {} + * ^ FunctionLike + */ +export function isFunctionLike(program: ts.Program, type: ts.Type): boolean { + return ( + isBuiltinSymbolLike(program, type, 'Function') || + isBuiltinSymbolLike(program, type, 'FunctionConstructor') + ); +} export function isBuiltinTypeAliasLike( program: ts.Program, type: ts.Type, From 59adffb76daaac664d32104e18f9fff9e2aaacdd Mon Sep 17 00:00:00 2001 From: arka1002 Date: Mon, 22 Jan 2024 16:45:51 +0530 Subject: [PATCH 2/3] chore: lint errors --- packages/eslint-plugin/src/rules/no-implied-eval.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/src/rules/no-implied-eval.ts b/packages/eslint-plugin/src/rules/no-implied-eval.ts index e3ba27068043..e7155fc05788 100644 --- a/packages/eslint-plugin/src/rules/no-implied-eval.ts +++ b/packages/eslint-plugin/src/rules/no-implied-eval.ts @@ -1,7 +1,7 @@ +import { isFunctionLike } from '@typescript-eslint/type-utils'; import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import { getScope } from '@typescript-eslint/utils/eslint-utils'; -import { isFunctionLike } from '@typescript-eslint/type-utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; From 7c96190cc5046edd5b1eac8d32de625dd0b9f540 Mon Sep 17 00:00:00 2001 From: arka1002 Date: Mon, 22 Jan 2024 19:43:15 +0530 Subject: [PATCH 3/3] chore: address reviews --- packages/eslint-plugin/src/rules/no-implied-eval.ts | 10 ++++------ packages/type-utils/src/builtinSymbolLikes.ts | 6 +++--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-implied-eval.ts b/packages/eslint-plugin/src/rules/no-implied-eval.ts index e7155fc05788..273cfd4d734c 100644 --- a/packages/eslint-plugin/src/rules/no-implied-eval.ts +++ b/packages/eslint-plugin/src/rules/no-implied-eval.ts @@ -1,11 +1,10 @@ -import { isFunctionLike } from '@typescript-eslint/type-utils'; import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import { getScope } from '@typescript-eslint/utils/eslint-utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import { createRule, getParserServices } from '../util'; +import { createRule, getParserServices, isFunctionSimilar } from '../util'; const FUNCTION_CONSTRUCTOR = 'Function'; const GLOBAL_CANDIDATES = new Set(['global', 'window', 'globalThis']); @@ -79,9 +78,8 @@ export default createRule({ return true; } - // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison - if (symbol && symbol.escapedName === FUNCTION_CONSTRUCTOR) { - return isFunctionLike(services.program, type); + if (isFunctionSimilar(services.program, type)) { + return true; } const signatures = checker.getSignaturesOfType( @@ -138,7 +136,7 @@ export default createRule({ const type = services.getTypeAtLocation(node.callee); const symbol = type.getSymbol(); if (symbol) { - if (isFunctionLike(services.program, type)) { + if (isFunctionSimilar(services.program, type)) { context.report({ node, messageId: 'noFunctionConstructor' }); } } else { diff --git a/packages/type-utils/src/builtinSymbolLikes.ts b/packages/type-utils/src/builtinSymbolLikes.ts index 4f494165225b..0a5cfa47a608 100644 --- a/packages/type-utils/src/builtinSymbolLikes.ts +++ b/packages/type-utils/src/builtinSymbolLikes.ts @@ -71,11 +71,11 @@ export function isReadonlyTypeLike( } /** * let F = new Function("foo"); - * ^ FunctionLike + * ^ FunctionSimilar * let I = (callback: Function) => {} - * ^ FunctionLike + * ^ FunctionSimilar */ -export function isFunctionLike(program: ts.Program, type: ts.Type): boolean { +export function isFunctionSimilar(program: ts.Program, type: ts.Type): boolean { return ( isBuiltinSymbolLike(program, type, 'Function') || isBuiltinSymbolLike(program, type, 'FunctionConstructor')