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

feat(utils): add ESLint CodePath selector types #7551

Merged
merged 15 commits into from Nov 13, 2023
46 changes: 43 additions & 3 deletions packages/eslint-plugin/typings/eslint-rules.d.ts
bradzacher marked this conversation as resolved.
Show resolved Hide resolved
Expand Up @@ -817,17 +817,57 @@ declare module 'eslint/lib/rules/no-invalid-this' {
],
{
// for ESLint < v8.7.0

Program?: (node: TSESTree.Program) => void;
'Program:exit'?: (node: TSESTree.Program) => void;

FunctionDeclaration?: (node: TSESTree.FunctionDeclaration) => void;
'FunctionDeclaration:exit'?: (node: TSESTree.FunctionDeclaration) => void;

FunctionExpression?: (node: TSESTree.FunctionExpression) => void;
'FunctionExpression:exit'?: (node: TSESTree.FunctionExpression) => void;

// for ESLint >= v8.7.0
// We don't use it and we don't have the CodePath types, so comment out it.
// onCodePathStart?: (codePath: unknown, node: TSESTree.Node) => void
// onCodePathEnd?: (codePath: unknown, node: TSESTree.Node) => void

// The code path functions below are intentionally commented out because
// they cause unresolvable compiler errors:
// https://github.com/typescript-eslint/typescript-eslint/issues/6993

/*
onCodePathStart?: (
codePath: TSESLint.CodePath,
node: TSESTree.Node,
) => void;
*/

/*
onCodePathEnd?: (
codePath: TSESLint.CodePath,
node: TSESTree.Node,
) => void;
*/

/*
onCodePathSegmentStart?: (
segment: TSESLint.CodePathSegment,
node: TSESTree.Node,
) => void;
*/

/*
onCodePathSegmentEnd?: (
segment: TSESLint.CodePathSegment,
node: TSESTree.Node,
) => void;
*/

/*
onCodePathSegmentLoop?: (
fromSegment: TSESLint.CodePathSegment,
toSegment: TSESLint.CodePathSegment,
node: TSESTree.Node,
) => void;
*/

// Common
ThisExpression(node: TSESTree.ThisExpression): void;
Expand Down
98 changes: 98 additions & 0 deletions packages/utils/src/ts-eslint/Rule.ts
Expand Up @@ -284,6 +284,101 @@ interface RuleContext<
report(descriptor: ReportDescriptor<TMessageIds>): void;
}

/**
* Part of the code path analysis feature of ESLint:
* https://eslint.org/docs/latest/extend/code-path-analysis
*
* These are used in the `onCodePath*` methods. (Note that the `node` parameter
* of these methods is intentionally omitted.)
*
* @see https://github.com/typescript-eslint/typescript-eslint/issues/6993
*/
interface CodePath {
/**
* A unique string. Respective rules can use `id` to save additional
* information for each code path.
*/
id: string;

initialSegment: CodePathSegment;

/** The final segments which includes both returned and thrown. */
finalSegments: CodePathSegment[];

/** The final segments which includes only returned. */
returnedSegments: CodePathSegment[];

/** The final segments which includes only thrown. */
thrownSegments: CodePathSegment[];

/**
* Segments of the current traversal position.
*
* @deprecated
*/
currentSegments: CodePathSegment[];

/** The code path of the upper function/global scope. */
upper: CodePath | null;

/** Code paths of functions this code path contains. */
childCodePaths: CodePath[];
}

/**
* Part of the code path analysis feature of ESLint:
* https://eslint.org/docs/latest/extend/code-path-analysis
*
* These are used in the `onCodePath*` methods. (Note that the `node` parameter
* of these methods is intentionally omitted.)
*
* @see https://github.com/typescript-eslint/typescript-eslint/issues/6993
*/
interface CodePathSegment {
/**
* A unique string. Respective rules can use `id` to save additional
* information for each segment.
*/
id: string;

/**
* The next segments. If forking, there are two or more. If final, there is
* nothing.
*/
nextSegments: CodePathSegment[];

/**
* The previous segments. If merging, there are two or more. If initial, there
* is nothing.
*/
prevSegments: CodePathSegment[];

/**
* A flag which shows whether it is reachable. This becomes `false` when
* preceded by `return`, `throw`, `break`, or `continue`.
*/
reachable: boolean;
}

/**
* Part of the code path analysis feature of ESLint:
* https://eslint.org/docs/latest/extend/code-path-analysis
*
* This type is unused in the `typescript-eslint` codebase since putting it on
* the `nodeSelector` for `RuleListener` would break the existing definition.
* However, it is exported here for the purposes of manual type-assertion.
*
* @see https://github.com/typescript-eslint/typescript-eslint/issues/6993
*/
type CodePathFunction =
| ((
fromSegment: CodePathSegment,
toSegment: CodePathSegment,
node: TSESTree.Node,
) => void)
| ((codePath: CodePath, node: TSESTree.Node) => void)
| ((segment: CodePathSegment, node: TSESTree.Node) => void);

// This isn't the correct signature, but it makes it easier to do custom unions within reusable listeners
// never will break someone's code unless they specifically type the function argument
type RuleFunction<T extends TSESTree.NodeOrTokenData = never> = (
Expand Down Expand Up @@ -494,6 +589,9 @@ type AnyRuleCreateFunction = RuleCreateFunction<string, readonly unknown[]>;
export {
AnyRuleCreateFunction,
AnyRuleModule,
CodePath,
CodePathFunction,
CodePathSegment,
ReportDescriptor,
ReportDescriptorMessageData,
ReportFixFunction,
Expand Down