@@ -61,27 +61,38 @@ const rule = {
6161 enableDangerousAutofixThisMayCauseInfiniteLoops : {
6262 type : 'boolean' ,
6363 } ,
64+ experimental_autoDependenciesHooks : {
65+ type : 'array' ,
66+ items : {
67+ type : 'string' ,
68+ } ,
69+ } ,
6470 } ,
6571 } ,
6672 ] ,
6773 } ,
6874 create ( context : Rule . RuleContext ) {
75+ const rawOptions = context . options && context . options [ 0 ] ;
76+
6977 // Parse the `additionalHooks` regex.
7078 const additionalHooks =
71- context . options &&
72- context . options [ 0 ] &&
73- context . options [ 0 ] . additionalHooks
74- ? new RegExp ( context . options [ 0 ] . additionalHooks )
79+ rawOptions && rawOptions . additionalHooks
80+ ? new RegExp ( rawOptions . additionalHooks )
7581 : undefined ;
7682
7783 const enableDangerousAutofixThisMayCauseInfiniteLoops : boolean =
78- ( context . options &&
79- context . options [ 0 ] &&
80- context . options [ 0 ] . enableDangerousAutofixThisMayCauseInfiniteLoops ) ||
84+ ( rawOptions &&
85+ rawOptions . enableDangerousAutofixThisMayCauseInfiniteLoops ) ||
8186 false ;
8287
88+ const experimental_autoDependenciesHooks : ReadonlyArray < string > =
89+ rawOptions && Array . isArray ( rawOptions . experimental_autoDependenciesHooks )
90+ ? rawOptions . experimental_autoDependenciesHooks
91+ : [ ] ;
92+
8393 const options = {
8494 additionalHooks,
95+ experimental_autoDependenciesHooks,
8596 enableDangerousAutofixThisMayCauseInfiniteLoops,
8697 } ;
8798
@@ -162,6 +173,7 @@ const rule = {
162173 reactiveHook : Node ,
163174 reactiveHookName : string ,
164175 isEffect : boolean ,
176+ isAutoDepsHook : boolean ,
165177 ) : void {
166178 if ( isEffect && node . async ) {
167179 reportProblem ( {
@@ -649,6 +661,9 @@ const rule = {
649661 }
650662
651663 if ( ! declaredDependenciesNode ) {
664+ if ( isAutoDepsHook ) {
665+ return ;
666+ }
652667 // Check if there are any top-level setState() calls.
653668 // Those tend to lead to infinite loops.
654669 let setStateInsideEffectWithoutDeps : string | null = null ;
@@ -711,6 +726,13 @@ const rule = {
711726 }
712727 return ;
713728 }
729+ if (
730+ isAutoDepsHook &&
731+ declaredDependenciesNode . type === 'Literal' &&
732+ declaredDependenciesNode . value === null
733+ ) {
734+ return ;
735+ }
714736
715737 const declaredDependencies : Array < DeclaredDependency > = [ ] ;
716738 const externalDependencies = new Set < string > ( ) ;
@@ -1318,10 +1340,19 @@ const rule = {
13181340 return ;
13191341 }
13201342
1343+ const isAutoDepsHook =
1344+ options . experimental_autoDependenciesHooks . includes ( reactiveHookName ) ;
1345+
13211346 // Check the declared dependencies for this reactive hook. If there is no
13221347 // second argument then the reactive callback will re-run on every render.
13231348 // So no need to check for dependency inclusion.
1324- if ( ! declaredDependenciesNode && ! isEffect ) {
1349+ if (
1350+ ( ! declaredDependenciesNode ||
1351+ ( isAutoDepsHook &&
1352+ declaredDependenciesNode . type === 'Literal' &&
1353+ declaredDependenciesNode . value === null ) ) &&
1354+ ! isEffect
1355+ ) {
13251356 // These are only used for optimization.
13261357 if (
13271358 reactiveHookName === 'useMemo' ||
@@ -1355,11 +1386,17 @@ const rule = {
13551386 reactiveHook ,
13561387 reactiveHookName ,
13571388 isEffect ,
1389+ isAutoDepsHook ,
13581390 ) ;
13591391 return ; // Handled
13601392 case 'Identifier' :
1361- if ( ! declaredDependenciesNode ) {
1362- // No deps, no problems.
1393+ if (
1394+ ! declaredDependenciesNode ||
1395+ ( isAutoDepsHook &&
1396+ declaredDependenciesNode . type === 'Literal' &&
1397+ declaredDependenciesNode . value === null )
1398+ ) {
1399+ // Always runs, no problems.
13631400 return ; // Handled
13641401 }
13651402 // The function passed as a callback is not written inline.
@@ -1408,6 +1445,7 @@ const rule = {
14081445 reactiveHook ,
14091446 reactiveHookName ,
14101447 isEffect ,
1448+ isAutoDepsHook ,
14111449 ) ;
14121450 return ; // Handled
14131451 case 'VariableDeclarator' :
@@ -1427,6 +1465,7 @@ const rule = {
14271465 reactiveHook ,
14281466 reactiveHookName ,
14291467 isEffect ,
1468+ isAutoDepsHook ,
14301469 ) ;
14311470 return ; // Handled
14321471 }
0 commit comments