| 
1 |  | -import {  | 
2 |  | -	DefinitionType,  | 
3 |  | -	type ScopeVariable,  | 
4 |  | -} from '@typescript-eslint/scope-manager';  | 
5 | 1 | import { TSESTree, ASTUtils } from '@typescript-eslint/utils';  | 
6 | 2 | 
 
  | 
7 | 3 | import { createTestingLibraryRule } from '../create-testing-library-rule';  | 
8 | 4 | import {  | 
9 | 5 | 	getDeepestIdentifierNode,  | 
10 |  | -	getPropertyIdentifierNode,  | 
11 |  | -	isCallExpression,  | 
 | 6 | +	isLiteral,  | 
12 | 7 | 	isMemberExpression,  | 
13 | 8 | } from '../node-utils';  | 
14 | 9 | import {  | 
 | 10 | +	ALL_QUERIES_COMBINATIONS,  | 
15 | 11 | 	ALL_RETURNING_NODES,  | 
16 | 12 | 	EVENT_HANDLER_METHODS,  | 
17 |  | -	getScope,  | 
18 | 13 | 	resolveToTestingLibraryFn,  | 
19 | 14 | } from '../utils';  | 
20 | 15 | 
 
  | 
@@ -60,8 +55,6 @@ export default createTestingLibraryRule<Options, MessageIds>({  | 
60 | 55 | 	],  | 
61 | 56 | 
 
  | 
62 | 57 | 	create(context, [{ allowContainerFirstChild = false }], helpers) {  | 
63 |  | -		const userEventInstanceNames = new Set<string>();  | 
64 |  | - | 
65 | 58 | 		function showErrorForNodeAccess(node: TSESTree.MemberExpression) {  | 
66 | 59 | 			// This rule is so aggressive that can cause tons of false positives outside test files when Aggressive Reporting  | 
67 | 60 | 			// is enabled. Because of that, this rule will skip this mechanism and report only if some Testing Library package  | 
@@ -99,94 +92,44 @@ export default createTestingLibraryRule<Options, MessageIds>({  | 
99 | 92 | 			}  | 
100 | 93 | 		}  | 
101 | 94 | 
 
  | 
102 |  | -		function detectTestingLibraryFn(  | 
103 |  | -			node: TSESTree.CallExpression,  | 
104 |  | -			variable: ScopeVariable | null  | 
 | 95 | +		function getProperty(  | 
 | 96 | +			node: TSESTree.PrivateIdentifier | TSESTree.Expression  | 
105 | 97 | 		) {  | 
106 |  | -			if (variable && variable.defs.length > 0) {  | 
107 |  | -				const def = variable.defs[0];  | 
108 |  | -				if (  | 
109 |  | -					def.type === DefinitionType.Variable &&  | 
110 |  | -					isCallExpression(def.node.init)  | 
111 |  | -				) {  | 
112 |  | -					return resolveToTestingLibraryFn(def.node.init, context);  | 
113 |  | -				}  | 
 | 98 | +			if (isLiteral(node)) {  | 
 | 99 | +				return node;  | 
114 | 100 | 			}  | 
115 | 101 | 
 
  | 
116 |  | -			return resolveToTestingLibraryFn(node, context);  | 
 | 102 | +			return getDeepestIdentifierNode(node);  | 
117 | 103 | 		}  | 
118 | 104 | 
 
  | 
119 | 105 | 		return {  | 
120 | 106 | 			CallExpression(node: TSESTree.CallExpression) {  | 
121 |  | -				const property = getDeepestIdentifierNode(node);  | 
122 |  | -				const identifier = getPropertyIdentifierNode(node);  | 
123 |  | - | 
124 |  | -				const isEventHandlerMethod = EVENT_HANDLER_METHODS.some(  | 
125 |  | -					(method) => method === property?.name  | 
126 |  | -				);  | 
127 |  | -				const hasUserEventInstanceName = userEventInstanceNames.has(  | 
128 |  | -					identifier?.name ?? ''  | 
129 |  | -				);  | 
130 |  | - | 
131 |  | -				const variable = identifier  | 
132 |  | -					? ASTUtils.findVariable(getScope(context, node), identifier)  | 
133 |  | -					: null;  | 
134 |  | -				const testingLibraryFn = detectTestingLibraryFn(node, variable);  | 
 | 107 | +				if (!isMemberExpression(node.callee)) return;  | 
135 | 108 | 
 
  | 
 | 109 | +				const { callee } = node;  | 
136 | 110 | 				if (  | 
137 |  | -					!testingLibraryFn &&  | 
138 |  | -					isEventHandlerMethod &&  | 
139 |  | -					!hasUserEventInstanceName  | 
 | 111 | +					!EVENT_HANDLER_METHODS.some(  | 
 | 112 | +						(method) => method === ASTUtils.getPropertyName(callee)  | 
 | 113 | +					)  | 
140 | 114 | 				) {  | 
141 |  | -					context.report({  | 
142 |  | -						node,  | 
143 |  | -						loc: property?.loc.start,  | 
144 |  | -						messageId: 'noNodeAccess',  | 
145 |  | -					});  | 
146 |  | -				}  | 
147 |  | -			},  | 
148 |  | -			VariableDeclarator(node: TSESTree.VariableDeclarator) {  | 
149 |  | -				const { init, id } = node;  | 
150 |  | - | 
151 |  | -				if (!isCallExpression(init)) {  | 
152 | 115 | 					return;  | 
153 | 116 | 				}  | 
 | 117 | +				const identifier = getDeepestIdentifierNode(callee.object);  | 
154 | 118 | 
 
  | 
155 | 119 | 				if (  | 
156 |  | -					!isMemberExpression(init.callee) ||  | 
157 |  | -					!ASTUtils.isIdentifier(init.callee.object)  | 
 | 120 | +					!identifier ||  | 
 | 121 | +					!ALL_QUERIES_COMBINATIONS.includes(identifier.name)  | 
158 | 122 | 				) {  | 
159 | 123 | 					return;  | 
160 | 124 | 				}  | 
161 | 125 | 
 
  | 
162 |  | -				const testingLibraryFn = resolveToTestingLibraryFn(init, context);  | 
163 |  | -				if (  | 
164 |  | -					init.callee.object.name === testingLibraryFn?.local &&  | 
165 |  | -					ASTUtils.isIdentifier(init.callee.property) &&  | 
166 |  | -					init.callee.property.name === 'setup' &&  | 
167 |  | -					ASTUtils.isIdentifier(id)  | 
168 |  | -				) {  | 
169 |  | -					userEventInstanceNames.add(id.name);  | 
170 |  | -				}  | 
171 |  | -			},  | 
172 |  | -			AssignmentExpression(node: TSESTree.AssignmentExpression) {  | 
173 |  | -				if (  | 
174 |  | -					ASTUtils.isIdentifier(node.left) &&  | 
175 |  | -					isCallExpression(node.right) &&  | 
176 |  | -					isMemberExpression(node.right.callee) &&  | 
177 |  | -					ASTUtils.isIdentifier(node.right.callee.object)  | 
178 |  | -				) {  | 
179 |  | -					const testingLibraryFn = resolveToTestingLibraryFn(  | 
180 |  | -						node.right,  | 
181 |  | -						context  | 
182 |  | -					);  | 
183 |  | -					if (  | 
184 |  | -						node.right.callee.object.name === testingLibraryFn?.local &&  | 
185 |  | -						ASTUtils.isIdentifier(node.right.callee.property) &&  | 
186 |  | -						node.right.callee.property.name === 'setup'  | 
187 |  | -					) {  | 
188 |  | -						userEventInstanceNames.add(node.left.name);  | 
189 |  | -					}  | 
 | 126 | +				if (resolveToTestingLibraryFn(node, context)) {  | 
 | 127 | +					const property = getProperty(callee.property);  | 
 | 128 | +					context.report({  | 
 | 129 | +						node,  | 
 | 130 | +						loc: property?.loc.start,  | 
 | 131 | +						messageId: 'noNodeAccess',  | 
 | 132 | +					});  | 
190 | 133 | 				}  | 
191 | 134 | 			},  | 
192 | 135 | 			'ExpressionStatement MemberExpression': showErrorForNodeAccess,  | 
 | 
0 commit comments