From 8dbcee04de7795f7e04ac79c88d5e816fe3d27af Mon Sep 17 00:00:00 2001 From: Gareth Jones Date: Fri, 18 Oct 2024 11:30:21 +1300 Subject: [PATCH] fix: replace use of deprecated methods (#925) --- lib/node-utils/index.ts | 6 +- lib/rules/consistent-data-testid.ts | 4 +- lib/rules/no-debugging-utils.ts | 4 +- lib/rules/no-manual-cleanup.ts | 3 +- lib/rules/no-promise-in-fire-event.ts | 3 +- lib/rules/prefer-find-by.ts | 29 ++++++---- lib/utils/compat.ts | 80 +++++++++++++++++++++++++++ lib/utils/index.ts | 1 + 8 files changed, 110 insertions(+), 20 deletions(-) create mode 100644 lib/utils/compat.ts diff --git a/lib/node-utils/index.ts b/lib/node-utils/index.ts index 0f748c5c..9e9e9b04 100644 --- a/lib/node-utils/index.ts +++ b/lib/node-utils/index.ts @@ -6,6 +6,8 @@ import { TSESTree, } from '@typescript-eslint/utils'; +import { getDeclaredVariables, getScope } from '../utils'; + import { isArrayExpression, isArrowFunctionExpression, @@ -287,7 +289,7 @@ export function getVariableReferences( ): TSESLint.Scope.Reference[] { if (ASTUtils.isVariableDeclarator(node)) { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - return context.getDeclaredVariables(node)[0]?.references?.slice(1) ?? []; + return getDeclaredVariables(context, node)[0]?.references?.slice(1) ?? []; } return []; @@ -305,7 +307,7 @@ export function getInnermostFunctionScope( asyncQueryNode: TSESTree.Identifier ): InnermostFunctionScope | null { const innermostScope = ASTUtils.getInnermostScope( - context.getScope(), + getScope(context, asyncQueryNode), asyncQueryNode ); diff --git a/lib/rules/consistent-data-testid.ts b/lib/rules/consistent-data-testid.ts index 2536706e..f8b7ff6e 100644 --- a/lib/rules/consistent-data-testid.ts +++ b/lib/rules/consistent-data-testid.ts @@ -1,5 +1,6 @@ import { createTestingLibraryRule } from '../create-testing-library-rule'; import { isJSXAttribute, isLiteral } from '../node-utils'; +import { getFilename } from '../utils'; export const RULE_NAME = 'consistent-data-testid'; export type MessageIds = @@ -77,11 +78,10 @@ export default createTestingLibraryRule({ }, create: (context, [options]) => { - const { getFilename } = context; const { testIdPattern, testIdAttribute: attr, customMessage } = options; function getFileNameData() { - const splitPath = getFilename().split('/'); + const splitPath = getFilename(context).split('/'); const fileNameWithExtension = splitPath.pop() ?? ''; if ( fileNameWithExtension.includes('[') || diff --git a/lib/rules/no-debugging-utils.ts b/lib/rules/no-debugging-utils.ts index d9ed3040..3978fbde 100644 --- a/lib/rules/no-debugging-utils.ts +++ b/lib/rules/no-debugging-utils.ts @@ -11,7 +11,7 @@ import { isObjectPattern, isProperty, } from '../node-utils'; -import { DEBUG_UTILS } from '../utils'; +import { DEBUG_UTILS, getDeclaredVariables } from '../utils'; type DebugUtilsToCheckForConfig = Record<(typeof DEBUG_UTILS)[number], boolean>; type DebugUtilsToCheckFor = Partial; @@ -175,7 +175,7 @@ export default createTestingLibraryRule({ const isVariableFromBuiltInConsole = builtInConsoleNodes.some( (variableDeclarator) => { - const variables = context.getDeclaredVariables(variableDeclarator); + const variables = getDeclaredVariables(context, variableDeclarator); return variables.some( ({ name }) => name === callExpressionIdentifier.name && diff --git a/lib/rules/no-manual-cleanup.ts b/lib/rules/no-manual-cleanup.ts index 9074d669..ee65ee71 100644 --- a/lib/rules/no-manual-cleanup.ts +++ b/lib/rules/no-manual-cleanup.ts @@ -12,6 +12,7 @@ import { isObjectPattern, isProperty, } from '../node-utils'; +import { getDeclaredVariables } from '../utils'; export const RULE_NAME = 'no-manual-cleanup'; export type MessageIds = 'noManualCleanup'; @@ -65,7 +66,7 @@ export default createTestingLibraryRule({ if (isImportDeclaration(moduleNode)) { // case: import utils from 'testing-library-module' if (isImportDefaultSpecifier(moduleNode.specifiers[0])) { - const { references } = context.getDeclaredVariables(moduleNode)[0]; + const { references } = getDeclaredVariables(context, moduleNode)[0]; reportImportReferences(references); } diff --git a/lib/rules/no-promise-in-fire-event.ts b/lib/rules/no-promise-in-fire-event.ts index c3c7eb4d..f10bfc77 100644 --- a/lib/rules/no-promise-in-fire-event.ts +++ b/lib/rules/no-promise-in-fire-event.ts @@ -8,6 +8,7 @@ import { isNewExpression, isPromiseIdentifier, } from '../node-utils'; +import { getScope } from '../utils'; export const RULE_NAME = 'no-promise-in-fire-event'; export type MessageIds = 'noPromiseInFireEvent'; @@ -76,7 +77,7 @@ export default createTestingLibraryRule({ if (ASTUtils.isIdentifier(node)) { const nodeVariable = ASTUtils.findVariable( - context.getScope(), + getScope(context, node), node.name ); if (!nodeVariable) { diff --git a/lib/rules/prefer-find-by.ts b/lib/rules/prefer-find-by.ts index f9d951e0..7e48993b 100644 --- a/lib/rules/prefer-find-by.ts +++ b/lib/rules/prefer-find-by.ts @@ -9,6 +9,7 @@ import { isObjectPattern, isProperty, } from '../node-utils'; +import { getScope, getSourceCode } from '../utils'; export const RULE_NAME = 'prefer-find-by'; export type MessageIds = 'preferFindBy'; @@ -69,7 +70,7 @@ export default createTestingLibraryRule({ defaultOptions: [], create(context, _, helpers) { - const sourceCode = context.getSourceCode(); + const sourceCode = getSourceCode(context); /** * Reports the invalid usage of wait* plus getBy/QueryBy methods and automatically fixes the scenario @@ -118,7 +119,7 @@ export default createTestingLibraryRule({ isCallExpression(node.body.callee.object.arguments[0]) && ASTUtils.isIdentifier(node.body.callee.object.arguments[0].callee) ) { - return node.body.callee.object.arguments[0].callee.name; + return node.body.callee.object.arguments[0].callee; } if (!ASTUtils.isIdentifier(node.body.callee.property)) { @@ -134,7 +135,7 @@ export default createTestingLibraryRule({ node.body.callee.object.arguments[0].callee.property ) ) { - return node.body.callee.object.arguments[0].callee.property.name; + return node.body.callee.object.arguments[0].callee.property; } // expect(screen.getByText).not shape @@ -149,7 +150,7 @@ export default createTestingLibraryRule({ node.body.callee.object.object.arguments[0].callee.property ) ) { - return node.body.callee.object.object.arguments[0].callee.property.name; + return node.body.callee.object.object.arguments[0].callee.property; } // expect(getByText).not shape @@ -161,10 +162,10 @@ export default createTestingLibraryRule({ node.body.callee.object.object.arguments[0].callee ) ) { - return node.body.callee.object.object.arguments[0].callee.name; + return node.body.callee.object.object.arguments[0].callee; } - return node.body.callee.property.name; + return node.body.callee.property; } function getWrongQueryName(node: TSESTree.ArrowFunctionExpression) { @@ -177,7 +178,7 @@ export default createTestingLibraryRule({ ASTUtils.isIdentifier(node.body.callee) && helpers.isSyncQuery(node.body.callee) ) { - return node.body.callee.name; + return node.body.callee; } return getWrongQueryNameInAssertion(node); @@ -353,12 +354,14 @@ export default createTestingLibraryRule({ } // shape of () => screen.getByText - const fullQueryMethod = getWrongQueryName(argument); + const fullQueryMethodNode = getWrongQueryName(argument); - if (!fullQueryMethod) { + if (!fullQueryMethodNode) { return; } + const fullQueryMethod = fullQueryMethodNode.name; + // if there is a second argument to AwaitExpression, it is the options const waitOptions = node.arguments[1]; let waitOptionsSourceCode = ''; @@ -400,12 +403,14 @@ export default createTestingLibraryRule({ } // shape of () => getByText - const fullQueryMethod = getWrongQueryName(argument); + const fullQueryMethodNode = getWrongQueryName(argument); - if (!fullQueryMethod) { + if (!fullQueryMethodNode) { return; } + const fullQueryMethod = fullQueryMethodNode.name; + const queryMethod = fullQueryMethod.split('By')[1]; const queryVariant = getFindByQueryVariant(fullQueryMethod); const callArguments = getQueryArguments(argument.body); @@ -434,7 +439,7 @@ export default createTestingLibraryRule({ // this adds the findBy* declaration - adding it to the list of destructured variables { findBy* } = render() const definition = findRenderDefinitionDeclaration( - context.getScope(), + getScope(context, fullQueryMethodNode), fullQueryMethod ); // I think it should always find it, otherwise code should not be valid (it'd be using undeclared variables) diff --git a/lib/utils/compat.ts b/lib/utils/compat.ts new file mode 100644 index 00000000..2216dd8d --- /dev/null +++ b/lib/utils/compat.ts @@ -0,0 +1,80 @@ +import { type TSESLint, type TSESTree } from '@typescript-eslint/utils'; + +declare module '@typescript-eslint/utils/dist/ts-eslint/Rule' { + export interface RuleContext< + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TMessageIds extends string, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TOptions extends readonly unknown[], + > { + /** + * The filename associated with the source. + */ + filename: string; + + /** + * A SourceCode object that you can use to work with the source that + * was passed to ESLint. + */ + sourceCode: Readonly; + } +} + +declare module '@typescript-eslint/utils/dist/ts-eslint/SourceCode' { + export interface SourceCode { + /** + * Returns the scope of the given node. + * This information can be used track references to variables. + * @since 8.37.0 + */ + getScope(node: TSESTree.Node): TSESLint.Scope.Scope; + /** + * Returns an array of the ancestors of the given node, starting at + * the root of the AST and continuing through the direct parent of the current node. + * This array does not include the currently-traversed node itself. + * @since 8.38.0 + */ + getAncestors(node: TSESTree.Node): TSESTree.Node[]; + /** + * Returns a list of variables declared by the given node. + * This information can be used to track references to variables. + * @since 8.38.0 + */ + getDeclaredVariables( + node: TSESTree.Node + ): readonly TSESLint.Scope.Variable[]; + } +} + +/* istanbul ignore next */ +export const getFilename = ( + context: TSESLint.RuleContext +) => { + return context.filename ?? context.getFilename(); +}; + +/* istanbul ignore next */ +export const getSourceCode = ( + context: TSESLint.RuleContext +) => { + return context.sourceCode ?? context.getSourceCode(); +}; + +/* istanbul ignore next */ +export const getScope = ( + context: TSESLint.RuleContext, + node: TSESTree.Node +) => { + return getSourceCode(context).getScope?.(node) ?? context.getScope(); +}; + +/* istanbul ignore next */ +export const getDeclaredVariables = ( + context: TSESLint.RuleContext, + node: TSESTree.Node +) => { + return ( + getSourceCode(context).getDeclaredVariables?.(node) ?? + context.getDeclaredVariables(node) + ); +}; diff --git a/lib/utils/index.ts b/lib/utils/index.ts index b0ed31f7..cb0e8e03 100644 --- a/lib/utils/index.ts +++ b/lib/utils/index.ts @@ -1,3 +1,4 @@ +export * from './compat'; export * from './file-import'; export * from './types';