20
21
// @ts-expect-error untyped module
22
import CodePathAnalyzer from '../code-path-analysis/code-path-analyzer';
23
+import { getAdditionalEffectHooksFromSettings } from '../shared/Utils';
24
25
/**
26
* Catch all identifiers that begin with "use" followed by an uppercase Latin
148
return node;
149
}
150
150
-function isEffectIdentifier(node: Node): boolean {
151
- return node.type === 'Identifier' && (node.name === 'useEffect' || node.name === 'useLayoutEffect' || node.name === 'useInsertionEffect');
151
+function isEffectIdentifier(node: Node, additionalHooks?: RegExp): boolean {
152
+ const isBuiltInEffect =
153
+ node.type === 'Identifier' &&
154
+ (node.name === 'useEffect' ||
155
+ node.name === 'useLayoutEffect' ||
156
+ node.name === 'useInsertionEffect');
157
+
158
+ if (isBuiltInEffect) {
159
+ return true;
160
+ }
161
+
162
+ // Check if this matches additional hooks configured by the user
163
+ if (additionalHooks && node.type === 'Identifier') {
164
+ return additionalHooks.test(node.name);
165
+ }
166
+
167
+ return false;
168
}
169
function isUseEffectEventIdentifier(node: Node): boolean {
170
if (__EXPERIMENTAL__) {
185
recommended: true,
186
url: 'https://react.dev/reference/rules/rules-of-hooks',
187
},
188
+ schema: [
189
+ {
190
+ type: 'object',
191
+ additionalProperties: false,
192
+ properties: {
193
+ additionalHooks: {
194
+ type: 'string',
195
+ },
196
+ },
197
+ },
198
+ ],
199
},
200
create(context: Rule.RuleContext) {
201
+ const settings = context.settings || {};
202
+
203
+ const additionalEffectHooks = getAdditionalEffectHooksFromSettings(settings);
204
+
205
let lastEffect: CallExpression | null = null;
206
const codePathReactHooksMapStack: Array<
207
Map<Rule.CodePathSegment, Array<Node>>
757
// Check all `useEffect` and `React.useEffect`, `useEffectEvent`, and `React.useEffectEvent`
758
const nodeWithoutNamespace = getNodeWithoutReactNamespace(node.callee);
759
if (
729
- (isEffectIdentifier(nodeWithoutNamespace) ||
760
+ (isEffectIdentifier(nodeWithoutNamespace, additionalEffectHooks) ||
761
isUseEffectEventIdentifier(nodeWithoutNamespace)) &&
762
node.arguments.length > 0
763
) {