From 2d08593fcd1bcedb07d5c9f4ca477fd9959dda95 Mon Sep 17 00:00:00 2001 From: dbarabashh Date: Fri, 8 Aug 2025 14:33:24 +0100 Subject: [PATCH 1/3] fix: exclude Program from DefinitionBase node types --- packages/scope-manager/src/definition/DefinitionBase.ts | 7 ++++++- .../src/definition/ImplicitGlobalVariableDefinition.ts | 4 +++- packages/scope-manager/src/referencer/Reference.ts | 3 ++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/scope-manager/src/definition/DefinitionBase.ts b/packages/scope-manager/src/definition/DefinitionBase.ts index de4260ea888d..b6e20b0e025b 100644 --- a/packages/scope-manager/src/definition/DefinitionBase.ts +++ b/packages/scope-manager/src/definition/DefinitionBase.ts @@ -5,10 +5,15 @@ import type { DefinitionType } from './DefinitionType'; import { createIdGenerator } from '../ID'; const generator = createIdGenerator(); +/** + * Helper type to exclude Program from valid definition nodes + * Program is the root node and doesn't have a parent property + */ +export type NodeWithParent = Exclude; export abstract class DefinitionBase< Type extends DefinitionType, - Node extends TSESTree.Node, + Node extends NodeWithParent, Parent extends TSESTree.Node | null, Name extends TSESTree.Node, > { diff --git a/packages/scope-manager/src/definition/ImplicitGlobalVariableDefinition.ts b/packages/scope-manager/src/definition/ImplicitGlobalVariableDefinition.ts index fa36527502c4..9023d2949c28 100644 --- a/packages/scope-manager/src/definition/ImplicitGlobalVariableDefinition.ts +++ b/packages/scope-manager/src/definition/ImplicitGlobalVariableDefinition.ts @@ -1,11 +1,13 @@ import type { TSESTree } from '@typescript-eslint/types'; +import type { NodeWithParent } from './DefinitionBase'; + import { DefinitionBase } from './DefinitionBase'; import { DefinitionType } from './DefinitionType'; export class ImplicitGlobalVariableDefinition extends DefinitionBase< DefinitionType.ImplicitGlobalVariable, - TSESTree.Node, + NodeWithParent, null, TSESTree.BindingName > { diff --git a/packages/scope-manager/src/referencer/Reference.ts b/packages/scope-manager/src/referencer/Reference.ts index 6487f8ff36e4..4eca3a057cae 100644 --- a/packages/scope-manager/src/referencer/Reference.ts +++ b/packages/scope-manager/src/referencer/Reference.ts @@ -1,5 +1,6 @@ import type { TSESTree } from '@typescript-eslint/types'; +import type { NodeWithParent } from '../definition/DefinitionBase'; import type { Scope } from '../scope'; import type { Variable } from '../variable'; @@ -12,7 +13,7 @@ export enum ReferenceFlag { } export interface ReferenceImplicitGlobal { - node: TSESTree.Node; + node: NodeWithParent; pattern: TSESTree.BindingName; ref?: Reference; } From 5dd757ae38cca0c632a37ee92fbb267d38a58eab Mon Sep 17 00:00:00 2001 From: dbarabashh Date: Sat, 9 Aug 2025 23:47:07 +0100 Subject: [PATCH 2/3] fix eslint --- .../eslint-plugin/src/util/collectUnusedVariables.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/eslint-plugin/src/util/collectUnusedVariables.ts b/packages/eslint-plugin/src/util/collectUnusedVariables.ts index 983eb1472c14..3e7172e2ca45 100644 --- a/packages/eslint-plugin/src/util/collectUnusedVariables.ts +++ b/packages/eslint-plugin/src/util/collectUnusedVariables.ts @@ -438,8 +438,8 @@ function isMergableExported(variable: ScopeVariable): boolean { if ( (MERGABLE_TYPES.has(def.node.type) && - def.node.parent?.type === AST_NODE_TYPES.ExportNamedDeclaration) || - def.node.parent?.type === AST_NODE_TYPES.ExportDefaultDeclaration + def.node.parent.type === AST_NODE_TYPES.ExportNamedDeclaration) || + def.node.parent.type === AST_NODE_TYPES.ExportDefaultDeclaration ) { return true; } @@ -458,14 +458,12 @@ function isExported(variable: ScopeVariable): boolean { let node = definition.node; if (node.type === AST_NODE_TYPES.VariableDeclarator) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - node = node.parent!; + node = node.parent; } else if (definition.type === TSESLint.Scope.DefinitionType.Parameter) { return false; } - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - return node.parent!.type.startsWith('Export'); + return node.parent.type.startsWith('Export'); }); } From 382a14930e575a93618528630f34d14a97bd5b37 Mon Sep 17 00:00:00 2001 From: dbarabashh Date: Thu, 28 Aug 2025 20:58:28 +0100 Subject: [PATCH 3/3] Add NodeWithParent type --- .../src/rules/no-confusing-void-expression.ts | 17 +++++++++-------- .../src/definition/DefinitionBase.ts | 7 +------ .../ImplicitGlobalVariableDefinition.ts | 4 +--- .../scope-manager/src/referencer/Reference.ts | 3 +-- packages/types/src/ts-estree.ts | 1 + packages/utils/src/ts-estree.ts | 2 +- 6 files changed, 14 insertions(+), 20 deletions(-) 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 1efacdaf5ae1..9534acef8ee2 100644 --- a/packages/eslint-plugin/src/rules/no-confusing-void-expression.ts +++ b/packages/eslint-plugin/src/rules/no-confusing-void-expression.ts @@ -1,4 +1,8 @@ -import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; +import type { + NodeWithParent, + TSESLint, + TSESTree, +} from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; @@ -300,8 +304,8 @@ export default createRule({ * @param node The void expression node to check. * @returns Invalid ancestor node if it was found. `null` otherwise. */ - function findInvalidAncestor(node: TSESTree.Node): InvalidAncestor | null { - const parent = nullThrows(node.parent, NullThrowsReasons.MissingParent); + function findInvalidAncestor(node: NodeWithParent): InvalidAncestor | null { + const parent = node.parent; if ( parent.type === AST_NODE_TYPES.SequenceExpression && node !== parent.expressions[parent.expressions.length - 1] @@ -365,17 +369,14 @@ export default 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 = nullThrows(node.parent, NullThrowsReasons.MissingParent); + const block = node.parent; 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 = nullThrows( - block.parent, - NullThrowsReasons.MissingParent, - ); + const blockParent = block.parent; if ( ![ AST_NODE_TYPES.ArrowFunctionExpression, diff --git a/packages/scope-manager/src/definition/DefinitionBase.ts b/packages/scope-manager/src/definition/DefinitionBase.ts index b6e20b0e025b..87b9cfb0eea4 100644 --- a/packages/scope-manager/src/definition/DefinitionBase.ts +++ b/packages/scope-manager/src/definition/DefinitionBase.ts @@ -1,15 +1,10 @@ -import type { TSESTree } from '@typescript-eslint/types'; +import type { NodeWithParent, TSESTree } from '@typescript-eslint/types'; import type { DefinitionType } from './DefinitionType'; import { createIdGenerator } from '../ID'; const generator = createIdGenerator(); -/** - * Helper type to exclude Program from valid definition nodes - * Program is the root node and doesn't have a parent property - */ -export type NodeWithParent = Exclude; export abstract class DefinitionBase< Type extends DefinitionType, diff --git a/packages/scope-manager/src/definition/ImplicitGlobalVariableDefinition.ts b/packages/scope-manager/src/definition/ImplicitGlobalVariableDefinition.ts index 9023d2949c28..23bc4dedfd30 100644 --- a/packages/scope-manager/src/definition/ImplicitGlobalVariableDefinition.ts +++ b/packages/scope-manager/src/definition/ImplicitGlobalVariableDefinition.ts @@ -1,6 +1,4 @@ -import type { TSESTree } from '@typescript-eslint/types'; - -import type { NodeWithParent } from './DefinitionBase'; +import type { NodeWithParent, TSESTree } from '@typescript-eslint/types'; import { DefinitionBase } from './DefinitionBase'; import { DefinitionType } from './DefinitionType'; diff --git a/packages/scope-manager/src/referencer/Reference.ts b/packages/scope-manager/src/referencer/Reference.ts index 4eca3a057cae..f5d1d3549d9e 100644 --- a/packages/scope-manager/src/referencer/Reference.ts +++ b/packages/scope-manager/src/referencer/Reference.ts @@ -1,6 +1,5 @@ -import type { TSESTree } from '@typescript-eslint/types'; +import type { NodeWithParent, TSESTree } from '@typescript-eslint/types'; -import type { NodeWithParent } from '../definition/DefinitionBase'; import type { Scope } from '../scope'; import type { Variable } from '../variable'; diff --git a/packages/types/src/ts-estree.ts b/packages/types/src/ts-estree.ts index b1a5928a5d2b..dc9902f60538 100644 --- a/packages/types/src/ts-estree.ts +++ b/packages/types/src/ts-estree.ts @@ -254,3 +254,4 @@ declare module './generated/ast-spec' { } export * as TSESTree from './generated/ast-spec'; +export type NodeWithParent = Exclude; diff --git a/packages/utils/src/ts-estree.ts b/packages/utils/src/ts-estree.ts index 6c61253a1f05..41cb2bf119b9 100644 --- a/packages/utils/src/ts-estree.ts +++ b/packages/utils/src/ts-estree.ts @@ -1,11 +1,11 @@ // for convenience's sake - export the types directly from here so consumers // don't need to reference/install both packages in their code - export { AST_NODE_TYPES, AST_TOKEN_TYPES, TSESTree, } from '@typescript-eslint/types'; +export type { NodeWithParent } from '@typescript-eslint/types'; export type { ParserServices,