| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458 | /** * @license React * eslint-plugin-react-hooks.development.js * * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */'use strict';if (process.env.NODE_ENV !== "production") {  (function() {'use strict';function _unsupportedIterableToArray(o, minLen) {  if (!o) return;  if (typeof o === "string") return _arrayLikeToArray(o, minLen);  var n = Object.prototype.toString.call(o).slice(8, -1);  if (n === "Object" && o.constructor) n = o.constructor.name;  if (n === "Map" || n === "Set") return Array.from(o);  if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);}function _arrayLikeToArray(arr, len) {  if (len == null || len > arr.length) len = arr.length;  for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];  return arr2;}function _createForOfIteratorHelper(o, allowArrayLike) {  var it;  if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {    if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {      if (it) o = it;      var i = 0;      var F = function () {};      return {        s: F,        n: function () {          if (i >= o.length) return {            done: true          };          return {            done: false,            value: o[i++]          };        },        e: function (e) {          throw e;        },        f: F      };    }    throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");  }  var normalCompletion = true,      didErr = false,      err;  return {    s: function () {      it = o[Symbol.iterator]();    },    n: function () {      var step = it.next();      normalCompletion = step.done;      return step;    },    e: function (e) {      didErr = true;      err = e;    },    f: function () {      try {        if (!normalCompletion && it.return != null) it.return();      } finally {        if (didErr) throw err;      }    }  };}/* global BigInt */function isHookName(s) {  return /^use[A-Z0-9].*$/.test(s);}/** * We consider hooks to be a hook name identifier or a member expression * containing a hook name. */function isHook(node) {  if (node.type === 'Identifier') {    return isHookName(node.name);  } else if (node.type === 'MemberExpression' && !node.computed && isHook(node.property)) {    var obj = node.object;    var isPascalCaseNameSpace = /^[A-Z].*/;    return obj.type === 'Identifier' && isPascalCaseNameSpace.test(obj.name);  } else {    return false;  }}/** * Checks if the node is a React component name. React component names must * always start with a non-lowercase letter. So `MyComponent` or `_MyComponent` * are valid component names for instance. */function isComponentName(node) {  if (node.type === 'Identifier') {    return !/^[a-z]/.test(node.name);  } else {    return false;  }}function isReactFunction(node, functionName) {  return node.name === functionName || node.type === 'MemberExpression' && node.object.name === 'React' && node.property.name === functionName;}/** * Checks if the node is a callback argument of forwardRef. This render function * should follow the rules of hooks. */function isForwardRefCallback(node) {  return !!(node.parent && node.parent.callee && isReactFunction(node.parent.callee, 'forwardRef'));}/** * Checks if the node is a callback argument of React.memo. This anonymous * functional component should follow the rules of hooks. */function isMemoCallback(node) {  return !!(node.parent && node.parent.callee && isReactFunction(node.parent.callee, 'memo'));}function isInsideComponentOrHook(node) {  while (node) {    var functionName = getFunctionName(node);    if (functionName) {      if (isComponentName(functionName) || isHook(functionName)) {        return true;      }    }    if (isForwardRefCallback(node) || isMemoCallback(node)) {      return true;    }    node = node.parent;  }  return false;}var RulesOfHooks = {  meta: {    type: 'problem',    docs: {      description: 'enforces the Rules of Hooks',      recommended: true,      url: 'https://reactjs.org/docs/hooks-rules.html'    }  },  create: function (context) {    var codePathReactHooksMapStack = [];    var codePathSegmentStack = [];    return {      // Maintain code segment path stack as we traverse.      onCodePathSegmentStart: function (segment) {        return codePathSegmentStack.push(segment);      },      onCodePathSegmentEnd: function () {        return codePathSegmentStack.pop();      },      // Maintain code path stack as we traverse.      onCodePathStart: function () {        return codePathReactHooksMapStack.push(new Map());      },      // Process our code path.      //      // Everything is ok if all React Hooks are both reachable from the initial      // segment and reachable from every final segment.      onCodePathEnd: function (codePath, codePathNode) {        var reactHooksMap = codePathReactHooksMapStack.pop();        if (reactHooksMap.size === 0) {          return;        } // All of the segments which are cyclic are recorded in this set.        var cyclic = new Set();        /**         * Count the number of code paths from the start of the function to this         * segment. For example:         *         * ```js         * function MyComponent() {         *   if (condition) {         *     // Segment 1         *   } else {         *     // Segment 2         *   }         *   // Segment 3         * }         * ```         *         * Segments 1 and 2 have one path to the beginning of `MyComponent` and         * segment 3 has two paths to the beginning of `MyComponent` since we         * could have either taken the path of segment 1 or segment 2.         *         * Populates `cyclic` with cyclic segments.         */        function countPathsFromStart(segment, pathHistory) {          var cache = countPathsFromStart.cache;          var paths = cache.get(segment.id);          var pathList = new Set(pathHistory); // If `pathList` includes the current segment then we've found a cycle!          // We need to fill `cyclic` with all segments inside cycle          if (pathList.has(segment.id)) {            var pathArray = [].concat(pathList);            var cyclicSegments = pathArray.slice(pathArray.indexOf(segment.id) + 1);            var _iterator = _createForOfIteratorHelper(cyclicSegments),                _step;            try {              for (_iterator.s(); !(_step = _iterator.n()).done;) {                var cyclicSegment = _step.value;                cyclic.add(cyclicSegment);              }            } catch (err) {              _iterator.e(err);            } finally {              _iterator.f();            }            return BigInt('0');          } // add the current segment to pathList          pathList.add(segment.id); // We have a cached `paths`. Return it.          if (paths !== undefined) {            return paths;          }          if (codePath.thrownSegments.includes(segment)) {            paths = BigInt('0');          } else if (segment.prevSegments.length === 0) {            paths = BigInt('1');          } else {            paths = BigInt('0');            var _iterator2 = _createForOfIteratorHelper(segment.prevSegments),                _step2;            try {              for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {                var prevSegment = _step2.value;                paths += countPathsFromStart(prevSegment, pathList);              }            } catch (err) {              _iterator2.e(err);            } finally {              _iterator2.f();            }          } // If our segment is reachable then there should be at least one path          // to it from the start of our code path.          if (segment.reachable && paths === BigInt('0')) {            cache.delete(segment.id);          } else {            cache.set(segment.id, paths);          }          return paths;        }        /**         * Count the number of code paths from this segment to the end of the         * function. For example:         *         * ```js         * function MyComponent() {         *   // Segment 1         *   if (condition) {         *     // Segment 2         *   } else {         *     // Segment 3         *   }         * }         * ```         *         * Segments 2 and 3 have one path to the end of `MyComponent` and         * segment 1 has two paths to the end of `MyComponent` since we could         * either take the path of segment 1 or segment 2.         *         * Populates `cyclic` with cyclic segments.         */        function countPathsToEnd(segment, pathHistory) {          var cache = countPathsToEnd.cache;          var paths = cache.get(segment.id);          var pathList = new Set(pathHistory); // If `pathList` includes the current segment then we've found a cycle!          // We need to fill `cyclic` with all segments inside cycle          if (pathList.has(segment.id)) {            var pathArray = Array.from(pathList);            var cyclicSegments = pathArray.slice(pathArray.indexOf(segment.id) + 1);            var _iterator3 = _createForOfIteratorHelper(cyclicSegments),                _step3;            try {              for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {                var cyclicSegment = _step3.value;                cyclic.add(cyclicSegment);              }            } catch (err) {              _iterator3.e(err);            } finally {              _iterator3.f();            }            return BigInt('0');          } // add the current segment to pathList          pathList.add(segment.id); // We have a cached `paths`. Return it.          if (paths !== undefined) {            return paths;          }          if (codePath.thrownSegments.includes(segment)) {            paths = BigInt('0');          } else if (segment.nextSegments.length === 0) {            paths = BigInt('1');          } else {            paths = BigInt('0');            var _iterator4 = _createForOfIteratorHelper(segment.nextSegments),                _step4;            try {              for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {                var nextSegment = _step4.value;                paths += countPathsToEnd(nextSegment, pathList);              }            } catch (err) {              _iterator4.e(err);            } finally {              _iterator4.f();            }          }          cache.set(segment.id, paths);          return paths;        }        /**         * Gets the shortest path length to the start of a code path.         * For example:         *         * ```js         * function MyComponent() {         *   if (condition) {         *     // Segment 1         *   }         *   // Segment 2         * }         * ```         *         * There is only one path from segment 1 to the code path start. Its         * length is one so that is the shortest path.         *         * There are two paths from segment 2 to the code path start. One         * through segment 1 with a length of two and another directly to the         * start with a length of one. The shortest path has a length of one         * so we would return that.         */        function shortestPathLengthToStart(segment) {          var cache = shortestPathLengthToStart.cache;          var length = cache.get(segment.id); // If `length` is null then we found a cycle! Return infinity since          // the shortest path is definitely not the one where we looped.          if (length === null) {            return Infinity;          } // We have a cached `length`. Return it.          if (length !== undefined) {            return length;          } // Compute `length` and cache it. Guarding against cycles.          cache.set(segment.id, null);          if (segment.prevSegments.length === 0) {            length = 1;          } else {            length = Infinity;            var _iterator5 = _createForOfIteratorHelper(segment.prevSegments),                _step5;            try {              for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {                var prevSegment = _step5.value;                var prevLength = shortestPathLengthToStart(prevSegment);                if (prevLength < length) {                  length = prevLength;                }              }            } catch (err) {              _iterator5.e(err);            } finally {              _iterator5.f();            }            length += 1;          }          cache.set(segment.id, length);          return length;        }        countPathsFromStart.cache = new Map();        countPathsToEnd.cache = new Map();        shortestPathLengthToStart.cache = new Map(); // Count all code paths to the end of our component/hook. Also primes        // the `countPathsToEnd` cache.        var allPathsFromStartToEnd = countPathsToEnd(codePath.initialSegment); // Gets the function name for our code path. If the function name is        // `undefined` then we know either that we have an anonymous function        // expression or our code path is not in a function. In both cases we        // will want to error since neither are React function components or        // hook functions - unless it is an anonymous function argument to        // forwardRef or memo.        var codePathFunctionName = getFunctionName(codePathNode); // This is a valid code path for React hooks if we are directly in a React        // function component or we are in a hook function.        var isSomewhereInsideComponentOrHook = isInsideComponentOrHook(codePathNode);        var isDirectlyInsideComponentOrHook = codePathFunctionName ? isComponentName(codePathFunctionName) || isHook(codePathFunctionName) : isForwardRefCallback(codePathNode) || isMemoCallback(codePathNode); // Compute the earliest finalizer level using information from the        // cache. We expect all reachable final segments to have a cache entry        // after calling `visitSegment()`.        var shortestFinalPathLength = Infinity;        var _iterator6 = _createForOfIteratorHelper(codePath.finalSegments),            _step6;        try {          for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {            var finalSegment = _step6.value;            if (!finalSegment.reachable) {              continue;            }            var length = shortestPathLengthToStart(finalSegment);            if (length < shortestFinalPathLength) {              shortestFinalPathLength = length;            }          } // Make sure all React Hooks pass our lint invariants. Log warnings          // if not.        } catch (err) {          _iterator6.e(err);        } finally {          _iterator6.f();        }        var _iterator7 = _createForOfIteratorHelper(reactHooksMap),            _step7;        try {          for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {            var _step7$value = _step7.value,                segment = _step7$value[0],                reactHooks = _step7$value[1];            // NOTE: We could report here that the hook is not reachable, but            // that would be redundant with more general "no unreachable"            // lint rules.            if (!segment.reachable) {              continue;            } // If there are any final segments with a shorter path to start then            // we possibly have an early return.            //            // If our segment is a final segment itself then siblings could            // possibly be early returns.            var possiblyHasEarlyReturn = segment.nextSegments.length === 0 ? shortestFinalPathLength <= shortestPathLengthToStart(segment) : shortestFinalPathLength < shortestPathLengthToStart(segment); // Count all the paths from the start of our code path to the end of            // our code path that go _through_ this segment. The critical piece            // of this is _through_. If we just call `countPathsToEnd(segment)`            // then we neglect that we may have gone through multiple paths to get            // to this point! Consider:            //            // ```js            // function MyComponent() {            //   if (a) {            //     // Segment 1            //   } else {            //     // Segment 2            //   }            //   // Segment 3            //   if (b) {            //     // Segment 4            //   } else {            //     // Segment 5            //   }            // }            // ```            //            // In this component we have four code paths:            //            // 1. `a = true; b = true`            // 2. `a = true; b = false`            // 3. `a = false; b = true`            // 4. `a = false; b = false`            //            // From segment 3 there are two code paths to the end through segment            // 4 and segment 5. However, we took two paths to get here through            // segment 1 and segment 2.            //            // If we multiply the paths from start (two) by the paths to end (two)            // for segment 3 we get four. Which is our desired count.            var pathsFromStartToEnd = countPathsFromStart(segment) * countPathsToEnd(segment); // Is this hook a part of a cyclic segment?            var cycled = cyclic.has(segment.id);            var _iterator8 = _createForOfIteratorHelper(reactHooks),                _step8;            try {              for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {                var hook = _step8.value;                // Report an error if a hook may be called more then once.                if (cycled) {                  context.report({                    node: hook,                    message: "React Hook \"" + context.getSource(hook) + "\" may be executed " + 'more than once. Possibly because it is called in a loop. ' + 'React Hooks must be called in the exact same order in ' + 'every component render.'                  });                } // If this is not a valid code path for React hooks then we need to                // log a warning for every hook in this code path.                //                // Pick a special message depending on the scope this hook was                // called in.                if (isDirectlyInsideComponentOrHook) {                  // Report an error if a hook does not reach all finalizing code                  // path segments.                  //                  // Special case when we think there might be an early return.                  if (!cycled && pathsFromStartToEnd !== allPathsFromStartToEnd) {                    var message = "React Hook \"" + context.getSource(hook) + "\" is called " + 'conditionally. React Hooks must be called in the exact ' + 'same order in every component render.' + (possiblyHasEarlyReturn ? ' Did you accidentally call a React Hook after an' + ' early return?' : '');                    context.report({                      node: hook,                      message: message                    });                  }                } else if (codePathNode.parent && (codePathNode.parent.type === 'MethodDefinition' || codePathNode.parent.type === 'ClassProperty') && codePathNode.parent.value === codePathNode) {                  // Custom message for hooks inside a class                  var _message = "React Hook \"" + context.getSource(hook) + "\" cannot be called " + 'in a class component. React Hooks must be called in a ' + 'React function component or a custom React Hook function.';                  context.report({                    node: hook,                    message: _message                  });                } else if (codePathFunctionName) {                  // Custom message if we found an invalid function name.                  var _message2 = "React Hook \"" + context.getSource(hook) + "\" is called in " + ("function \"" + context.getSource(codePathFunctionName) + "\" ") + 'that is neither a React function component nor a custom ' + 'React Hook function.' + ' React component names must start with an uppercase letter.' + ' React Hook names must start with the word "use".';                  context.report({                    node: hook,                    message: _message2                  });                } else if (codePathNode.type === 'Program') {                  // These are dangerous if you have inline requires enabled.                  var _message3 = "React Hook \"" + context.getSource(hook) + "\" cannot be called " + 'at the top level. React Hooks must be called in a ' + 'React function component or a custom React Hook function.';                  context.report({                    node: hook,                    message: _message3                  });                } else {                  // Assume in all other cases the user called a hook in some                  // random function callback. This should usually be true for                  // anonymous function expressions. Hopefully this is clarifying                  // enough in the common case that the incorrect message in                  // uncommon cases doesn't matter.                  if (isSomewhereInsideComponentOrHook) {                    var _message4 = "React Hook \"" + context.getSource(hook) + "\" cannot be called " + 'inside a callback. React Hooks must be called in a ' + 'React function component or a custom React Hook function.';                    context.report({                      node: hook,                      message: _message4                    });                  }                }              }            } catch (err) {              _iterator8.e(err);            } finally {              _iterator8.f();            }          }        } catch (err) {          _iterator7.e(err);        } finally {          _iterator7.f();        }      },      // Missed opportunity...We could visit all `Identifier`s instead of all      // `CallExpression`s and check that _every use_ of a hook name is valid.      // But that gets complicated and enters type-system territory, so we're      // only being strict about hook calls for now.      CallExpression: function (node) {        if (isHook(node.callee)) {          // Add the hook node to a map keyed by the code path segment. We will          // do full code path analysis at the end of our code path.          var reactHooksMap = last(codePathReactHooksMapStack);          var codePathSegment = last(codePathSegmentStack);          var reactHooks = reactHooksMap.get(codePathSegment);          if (!reactHooks) {            reactHooks = [];            reactHooksMap.set(codePathSegment, reactHooks);          }          reactHooks.push(node.callee);        }      }    };  }};/** * Gets the static name of a function AST node. For function declarations it is * easy. For anonymous function expressions it is much harder. If you search for * `IsAnonymousFunctionDefinition()` in the ECMAScript spec you'll find places * where JS gives anonymous function expressions names. We roughly detect the * same AST nodes with some exceptions to better fit our use case. */function getFunctionName(node) {  if (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression' && node.id) {    // function useHook() {}    // const whatever = function useHook() {};    //    // Function declaration or function expression names win over any    // assignment statements or other renames.    return node.id;  } else if (node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') {    if (node.parent.type === 'VariableDeclarator' && node.parent.init === node) {      // const useHook = () => {};      return node.parent.id;    } else if (node.parent.type === 'AssignmentExpression' && node.parent.right === node && node.parent.operator === '=') {      // useHook = () => {};      return node.parent.left;    } else if (node.parent.type === 'Property' && node.parent.value === node && !node.parent.computed) {      // {useHook: () => {}}      // {useHook() {}}      return node.parent.key; // NOTE: We could also support `ClassProperty` and `MethodDefinition`      // here to be pedantic. However, hooks in a class are an anti-pattern. So      // we don't allow it to error early.      //      // class {useHook = () => {}}      // class {useHook() {}}    } else if (node.parent.type === 'AssignmentPattern' && node.parent.right === node && !node.parent.computed) {      // const {useHook = () => {}} = {};      // ({useHook = () => {}} = {});      //      // Kinda clowny, but we'd said we'd follow spec convention for      // `IsAnonymousFunctionDefinition()` usage.      return node.parent.left;    } else {      return undefined;    }  } else {    return undefined;  }}/** * Convenience function for peeking the last item in a stack. */function last(array) {  return array[array.length - 1];}/* eslint-disable no-for-of-loops/no-for-of-loops */var ExhaustiveDeps = {  meta: {    type: 'suggestion',    docs: {      description: 'verifies the list of dependencies for Hooks like useEffect and similar',      recommended: true,      url: 'https://github.com/facebook/react/issues/14920'    },    fixable: 'code',    hasSuggestions: true,    schema: [{      type: 'object',      additionalProperties: false,      enableDangerousAutofixThisMayCauseInfiniteLoops: false,      properties: {        additionalHooks: {          type: 'string'        },        enableDangerousAutofixThisMayCauseInfiniteLoops: {          type: 'boolean'        }      }    }]  },  create: function (context) {    // Parse the `additionalHooks` regex.    var additionalHooks = context.options && context.options[0] && context.options[0].additionalHooks ? new RegExp(context.options[0].additionalHooks) : undefined;    var enableDangerousAutofixThisMayCauseInfiniteLoops = context.options && context.options[0] && context.options[0].enableDangerousAutofixThisMayCauseInfiniteLoops || false;    var options = {      additionalHooks: additionalHooks,      enableDangerousAutofixThisMayCauseInfiniteLoops: enableDangerousAutofixThisMayCauseInfiniteLoops    };    function reportProblem(problem) {      if (enableDangerousAutofixThisMayCauseInfiniteLoops) {        // Used to enable legacy behavior. Dangerous.        // Keep this as an option until major IDEs upgrade (including VSCode FB ESLint extension).        if (Array.isArray(problem.suggest) && problem.suggest.length > 0) {          problem.fix = problem.suggest[0].fix;        }      }      context.report(problem);    }    var scopeManager = context.getSourceCode().scopeManager; // Should be shared between visitors.    var setStateCallSites = new WeakMap();    var stateVariables = new WeakSet();    var stableKnownValueCache = new WeakMap();    var functionWithoutCapturedValueCache = new WeakMap();    function memoizeWithWeakMap(fn, map) {      return function (arg) {        if (map.has(arg)) {          // to verify cache hits:          // console.log(arg.name)          return map.get(arg);        }        var result = fn(arg);        map.set(arg, result);        return result;      };    }    /**     * Visitor for both function expressions and arrow function expressions.     */    function visitFunctionWithDependencies(node, declaredDependenciesNode, reactiveHook, reactiveHookName, isEffect) {      if (isEffect && node.async) {        reportProblem({          node: node,          message: "Effect callbacks are synchronous to prevent race conditions. " + "Put the async function inside:\n\n" + 'useEffect(() => {\n' + '  async function fetchData() {\n' + '    // You can await here\n' + '    const response = await MyAPI.getData(someId);\n' + '    // ...\n' + '  }\n' + '  fetchData();\n' + "}, [someId]); // Or [] if effect doesn't need props or state\n\n" + 'Learn more about data fetching with Hooks: https://reactjs.org/link/hooks-data-fetching'        });      } // Get the current scope.      var scope = scopeManager.acquire(node); // Find all our "pure scopes". On every re-render of a component these      // pure scopes may have changes to the variables declared within. So all      // variables used in our reactive hook callback but declared in a pure      // scope need to be listed as dependencies of our reactive hook callback.      //      // According to the rules of React you can't read a mutable value in pure      // scope. We can't enforce this in a lint so we trust that all variables      // declared outside of pure scope are indeed frozen.      var pureScopes = new Set();      var componentScope = null;      {        var currentScope = scope.upper;        while (currentScope) {          pureScopes.add(currentScope);          if (currentScope.type === 'function') {            break;          }          currentScope = currentScope.upper;        } // If there is no parent function scope then there are no pure scopes.        // The ones we've collected so far are incorrect. So don't continue with        // the lint.        if (!currentScope) {          return;        }        componentScope = currentScope;      }      var isArray = Array.isArray; // Next we'll define a few helpers that helps us      // tell if some values don't have to be declared as deps.      // Some are known to be stable based on Hook calls.      // const [state, setState] = useState() / React.useState()      //               ^^^ true for this reference      // const [state, dispatch] = useReducer() / React.useReducer()      //               ^^^ true for this reference      // const ref = useRef()      //       ^^^ true for this reference      // False for everything else.      function isStableKnownHookValue(resolved) {        if (!isArray(resolved.defs)) {          return false;        }        var def = resolved.defs[0];        if (def == null) {          return false;        } // Look for `let stuff = ...`        if (def.node.type !== 'VariableDeclarator') {          return false;        }        var init = def.node.init;        if (init == null) {          return false;        }        while (init.type === 'TSAsExpression') {          init = init.expression;        } // Detect primitive constants        // const foo = 42        var declaration = def.node.parent;        if (declaration == null) {          // This might happen if variable is declared after the callback.          // In that case ESLint won't set up .parent refs.          // So we'll set them up manually.          fastFindReferenceWithParent(componentScope.block, def.node.id);          declaration = def.node.parent;          if (declaration == null) {            return false;          }        }        if (declaration.kind === 'const' && init.type === 'Literal' && (typeof init.value === 'string' || typeof init.value === 'number' || init.value === null)) {          // Definitely stable          return true;        } // Detect known Hook calls        // const [_, setState] = useState()        if (init.type !== 'CallExpression') {          return false;        }        var callee = init.callee; // Step into `= React.something` initializer.        if (callee.type === 'MemberExpression' && callee.object.name === 'React' && callee.property != null && !callee.computed) {          callee = callee.property;        }        if (callee.type !== 'Identifier') {          return false;        }        var id = def.node.id;        var _callee = callee,            name = _callee.name;        if (name === 'useRef' && id.type === 'Identifier') {          // useRef() return value is stable.          return true;        } else if (name === 'useState' || name === 'useReducer') {          // Only consider second value in initializing tuple stable.          if (id.type === 'ArrayPattern' && id.elements.length === 2 && isArray(resolved.identifiers)) {            // Is second tuple value the same reference we're checking?            if (id.elements[1] === resolved.identifiers[0]) {              if (name === 'useState') {                var references = resolved.references;                var writeCount = 0;                for (var i = 0; i < references.length; i++) {                  if (references[i].isWrite()) {                    writeCount++;                  }                  if (writeCount > 1) {                    return false;                  }                  setStateCallSites.set(references[i].identifier, id.elements[0]);                }              } // Setter is stable.              return true;            } else if (id.elements[0] === resolved.identifiers[0]) {              if (name === 'useState') {                var _references = resolved.references;                for (var _i = 0; _i < _references.length; _i++) {                  stateVariables.add(_references[_i].identifier);                }              } // State variable itself is dynamic.              return false;            }          }        } else if (name === 'useTransition') {          // Only consider second value in initializing tuple stable.          if (id.type === 'ArrayPattern' && id.elements.length === 2 && Array.isArray(resolved.identifiers)) {            // Is second tuple value the same reference we're checking?            if (id.elements[1] === resolved.identifiers[0]) {              // Setter is stable.              return true;            }          }        } // By default assume it's dynamic.        return false;      } // Some are just functions that don't reference anything dynamic.      function isFunctionWithoutCapturedValues(resolved) {        if (!isArray(resolved.defs)) {          return false;        }        var def = resolved.defs[0];        if (def == null) {          return false;        }        if (def.node == null || def.node.id == null) {          return false;        } // Search the direct component subscopes for        // top-level function definitions matching this reference.        var fnNode = def.node;        var childScopes = componentScope.childScopes;        var fnScope = null;        var i;        for (i = 0; i < childScopes.length; i++) {          var childScope = childScopes[i];          var childScopeBlock = childScope.block;          if ( // function handleChange() {}          fnNode.type === 'FunctionDeclaration' && childScopeBlock === fnNode || // const handleChange = () => {}          // const handleChange = function() {}          fnNode.type === 'VariableDeclarator' && childScopeBlock.parent === fnNode) {            // Found it!            fnScope = childScope;            break;          }        }        if (fnScope == null) {          return false;        } // Does this function capture any values        // that are in pure scopes (aka render)?        for (i = 0; i < fnScope.through.length; i++) {          var ref = fnScope.through[i];          if (ref.resolved == null) {            continue;          }          if (pureScopes.has(ref.resolved.scope) && // Stable values are fine though,          // although we won't check functions deeper.          !memoizedIsStableKnownHookValue(ref.resolved)) {            return false;          }        } // If we got here, this function doesn't capture anything        // from render--or everything it captures is known stable.        return true;      } // Remember such values. Avoid re-running extra checks on them.      var memoizedIsStableKnownHookValue = memoizeWithWeakMap(isStableKnownHookValue, stableKnownValueCache);      var memoizedIsFunctionWithoutCapturedValues = memoizeWithWeakMap(isFunctionWithoutCapturedValues, functionWithoutCapturedValueCache); // These are usually mistaken. Collect them.      var currentRefsInEffectCleanup = new Map(); // Is this reference inside a cleanup function for this effect node?      // We can check by traversing scopes upwards  from the reference, and checking      // if the last "return () => " we encounter is located directly inside the effect.      function isInsideEffectCleanup(reference) {        var curScope = reference.from;        var isInReturnedFunction = false;        while (curScope.block !== node) {          if (curScope.type === 'function') {            isInReturnedFunction = curScope.block.parent != null && curScope.block.parent.type === 'ReturnStatement';          }          curScope = curScope.upper;        }        return isInReturnedFunction;      } // Get dependencies from all our resolved references in pure scopes.      // Key is dependency string, value is whether it's stable.      var dependencies = new Map();      var optionalChains = new Map();      gatherDependenciesRecursively(scope);      function gatherDependenciesRecursively(currentScope) {        var _iterator = _createForOfIteratorHelper(currentScope.references),            _step;        try {          for (_iterator.s(); !(_step = _iterator.n()).done;) {            var reference = _step.value;            // If this reference is not resolved or it is not declared in a pure            // scope then we don't care about this reference.            if (!reference.resolved) {              continue;            }            if (!pureScopes.has(reference.resolved.scope)) {              continue;            } // Narrow the scope of a dependency if it is, say, a member expression.            // Then normalize the narrowed dependency.            var referenceNode = fastFindReferenceWithParent(node, reference.identifier);            var dependencyNode = getDependency(referenceNode);            var dependency = analyzePropertyChain(dependencyNode, optionalChains); // Accessing ref.current inside effect cleanup is bad.            if ( // We're in an effect...            isEffect && // ... and this look like accessing .current...            dependencyNode.type === 'Identifier' && (dependencyNode.parent.type === 'MemberExpression' || dependencyNode.parent.type === 'OptionalMemberExpression') && !dependencyNode.parent.computed && dependencyNode.parent.property.type === 'Identifier' && dependencyNode.parent.property.name === 'current' && // ...in a cleanup function or below...            isInsideEffectCleanup(reference)) {              currentRefsInEffectCleanup.set(dependency, {                reference: reference,                dependencyNode: dependencyNode              });            }            if (dependencyNode.parent.type === 'TSTypeQuery' || dependencyNode.parent.type === 'TSTypeReference') {              continue;            }            var def = reference.resolved.defs[0];            if (def == null) {              continue;            } // Ignore references to the function itself as it's not defined yet.            if (def.node != null && def.node.init === node.parent) {              continue;            } // Ignore Flow type parameters            if (def.type === 'TypeParameter') {              continue;            } // Add the dependency to a map so we can make sure it is referenced            // again in our dependencies array. Remember whether it's stable.            if (!dependencies.has(dependency)) {              var resolved = reference.resolved;              var isStable = memoizedIsStableKnownHookValue(resolved) || memoizedIsFunctionWithoutCapturedValues(resolved);              dependencies.set(dependency, {                isStable: isStable,                references: [reference]              });            } else {              dependencies.get(dependency).references.push(reference);            }          }        } catch (err) {          _iterator.e(err);        } finally {          _iterator.f();        }        var _iterator2 = _createForOfIteratorHelper(currentScope.childScopes),            _step2;        try {          for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {            var childScope = _step2.value;            gatherDependenciesRecursively(childScope);          }        } catch (err) {          _iterator2.e(err);        } finally {          _iterator2.f();        }      } // Warn about accessing .current in cleanup effects.      currentRefsInEffectCleanup.forEach(function (_ref, dependency) {        var reference = _ref.reference,            dependencyNode = _ref.dependencyNode;        var references = reference.resolved.references; // Is React managing this ref or us?        // Let's see if we can find a .current assignment.        var foundCurrentAssignment = false;        for (var i = 0; i < references.length; i++) {          var identifier = references[i].identifier;          var parent = identifier.parent;          if (parent != null && // ref.current          // Note: no need to handle OptionalMemberExpression because it can't be LHS.          parent.type === 'MemberExpression' && !parent.computed && parent.property.type === 'Identifier' && parent.property.name === 'current' && // ref.current = <something>          parent.parent.type === 'AssignmentExpression' && parent.parent.left === parent) {            foundCurrentAssignment = true;            break;          }        } // We only want to warn about React-managed refs.        if (foundCurrentAssignment) {          return;        }        reportProblem({          node: dependencyNode.parent.property,          message: "The ref value '" + dependency + ".current' will likely have " + "changed by the time this effect cleanup function runs. If " + "this ref points to a node rendered by React, copy " + ("'" + dependency + ".current' to a variable inside the effect, and ") + "use that variable in the cleanup function."        });      }); // Warn about assigning to variables in the outer scope.      // Those are usually bugs.      var staleAssignments = new Set();      function reportStaleAssignment(writeExpr, key) {        if (staleAssignments.has(key)) {          return;        }        staleAssignments.add(key);        reportProblem({          node: writeExpr,          message: "Assignments to the '" + key + "' variable from inside React Hook " + (context.getSource(reactiveHook) + " will be lost after each ") + "render. To preserve the value over time, store it in a useRef " + "Hook and keep the mutable value in the '.current' property. " + "Otherwise, you can move this variable directly inside " + (context.getSource(reactiveHook) + ".")        });      } // Remember which deps are stable and report bad usage first.      var stableDependencies = new Set();      dependencies.forEach(function (_ref2, key) {        var isStable = _ref2.isStable,            references = _ref2.references;        if (isStable) {          stableDependencies.add(key);        }        references.forEach(function (reference) {          if (reference.writeExpr) {            reportStaleAssignment(reference.writeExpr, key);          }        });      });      if (staleAssignments.size > 0) {        // The intent isn't clear so we'll wait until you fix those first.        return;      }      if (!declaredDependenciesNode) {        // Check if there are any top-level setState() calls.        // Those tend to lead to infinite loops.        var setStateInsideEffectWithoutDeps = null;        dependencies.forEach(function (_ref3, key) {          var isStable = _ref3.isStable,              references = _ref3.references;          if (setStateInsideEffectWithoutDeps) {            return;          }          references.forEach(function (reference) {            if (setStateInsideEffectWithoutDeps) {              return;            }            var id = reference.identifier;            var isSetState = setStateCallSites.has(id);            if (!isSetState) {              return;            }            var fnScope = reference.from;            while (fnScope.type !== 'function') {              fnScope = fnScope.upper;            }            var isDirectlyInsideEffect = fnScope.block === node;            if (isDirectlyInsideEffect) {              // TODO: we could potentially ignore early returns.              setStateInsideEffectWithoutDeps = key;            }          });        });        if (setStateInsideEffectWithoutDeps) {          var _collectRecommendatio = collectRecommendations({            dependencies: dependencies,            declaredDependencies: [],            stableDependencies: stableDependencies,            externalDependencies: new Set(),            isEffect: true          }),              _suggestedDependencies = _collectRecommendatio.suggestedDependencies;          reportProblem({            node: reactiveHook,            message: "React Hook " + reactiveHookName + " contains a call to '" + setStateInsideEffectWithoutDeps + "'. " + "Without a list of dependencies, this can lead to an infinite chain of updates. " + "To fix this, pass [" + _suggestedDependencies.join(', ') + ("] as a second argument to the " + reactiveHookName + " Hook."),            suggest: [{              desc: "Add dependencies array: [" + _suggestedDependencies.join(', ') + "]",              fix: function (fixer) {                return fixer.insertTextAfter(node, ", [" + _suggestedDependencies.join(', ') + "]");              }            }]          });        }        return;      }      var declaredDependencies = [];      var externalDependencies = new Set();      if (declaredDependenciesNode.type !== 'ArrayExpression') {        // If the declared dependencies are not an array expression then we        // can't verify that the user provided the correct dependencies. Tell        // the user this in an error.        reportProblem({          node: declaredDependenciesNode,          message: "React Hook " + context.getSource(reactiveHook) + " was passed a " + 'dependency list that is not an array literal. This means we ' + "can't statically verify whether you've passed the correct " + 'dependencies.'        });      } else {        declaredDependenciesNode.elements.forEach(function (declaredDependencyNode) {          // Skip elided elements.          if (declaredDependencyNode === null) {            return;          } // If we see a spread element then add a special warning.          if (declaredDependencyNode.type === 'SpreadElement') {            reportProblem({              node: declaredDependencyNode,              message: "React Hook " + context.getSource(reactiveHook) + " has a spread " + "element in its dependency array. This means we can't " + "statically verify whether you've passed the " + 'correct dependencies.'            });            return;          } // Try to normalize the declared dependency. If we can't then an error          // will be thrown. We will catch that error and report an error.          var declaredDependency;          try {            declaredDependency = analyzePropertyChain(declaredDependencyNode, null);          } catch (error) {            if (/Unsupported node type/.test(error.message)) {              if (declaredDependencyNode.type === 'Literal') {                if (dependencies.has(declaredDependencyNode.value)) {                  reportProblem({                    node: declaredDependencyNode,                    message: "The " + declaredDependencyNode.raw + " literal is not a valid dependency " + "because it never changes. " + ("Did you mean to include " + declaredDependencyNode.value + " in the array instead?")                  });                } else {                  reportProblem({                    node: declaredDependencyNode,                    message: "The " + declaredDependencyNode.raw + " literal is not a valid dependency " + 'because it never changes. You can safely remove it.'                  });                }              } else {                reportProblem({                  node: declaredDependencyNode,                  message: "React Hook " + context.getSource(reactiveHook) + " has a " + "complex expression in the dependency array. " + 'Extract it to a separate variable so it can be statically checked.'                });              }              return;            } else {              throw error;            }          }          var maybeID = declaredDependencyNode;          while (maybeID.type === 'MemberExpression' || maybeID.type === 'OptionalMemberExpression' || maybeID.type === 'ChainExpression') {            maybeID = maybeID.object || maybeID.expression.object;          }          var isDeclaredInComponent = !componentScope.through.some(function (ref) {            return ref.identifier === maybeID;          }); // Add the dependency to our declared dependency map.          declaredDependencies.push({            key: declaredDependency,            node: declaredDependencyNode          });          if (!isDeclaredInComponent) {            externalDependencies.add(declaredDependency);          }        });      }      var _collectRecommendatio2 = collectRecommendations({        dependencies: dependencies,        declaredDependencies: declaredDependencies,        stableDependencies: stableDependencies,        externalDependencies: externalDependencies,        isEffect: isEffect      }),          suggestedDependencies = _collectRecommendatio2.suggestedDependencies,          unnecessaryDependencies = _collectRecommendatio2.unnecessaryDependencies,          missingDependencies = _collectRecommendatio2.missingDependencies,          duplicateDependencies = _collectRecommendatio2.duplicateDependencies;      var suggestedDeps = suggestedDependencies;      var problemCount = duplicateDependencies.size + missingDependencies.size + unnecessaryDependencies.size;      if (problemCount === 0) {        // If nothing else to report, check if some dependencies would        // invalidate on every render.        var constructions = scanForConstructions({          declaredDependencies: declaredDependencies,          declaredDependenciesNode: declaredDependenciesNode,          componentScope: componentScope,          scope: scope        });        constructions.forEach(function (_ref4) {          var construction = _ref4.construction,              isUsedOutsideOfHook = _ref4.isUsedOutsideOfHook,              depType = _ref4.depType;          var wrapperHook = depType === 'function' ? 'useCallback' : 'useMemo';          var constructionType = depType === 'function' ? 'definition' : 'initialization';          var defaultAdvice = "wrap the " + constructionType + " of '" + construction.name.name + "' in its own " + wrapperHook + "() Hook.";          var advice = isUsedOutsideOfHook ? "To fix this, " + defaultAdvice : "Move it inside the " + reactiveHookName + " callback. Alternatively, " + defaultAdvice;          var causation = depType === 'conditional' || depType === 'logical expression' ? 'could make' : 'makes';          var message = "The '" + construction.name.name + "' " + depType + " " + causation + " the dependencies of " + (reactiveHookName + " Hook (at line " + declaredDependenciesNode.loc.start.line + ") ") + ("change on every render. " + advice);          var suggest; // Only handle the simple case of variable assignments.          // Wrapping function declarations can mess up hoisting.          if (isUsedOutsideOfHook && construction.type === 'Variable' && // Objects may be mutated after construction, which would make this          // fix unsafe. Functions _probably_ won't be mutated, so we'll          // allow this fix for them.          depType === 'function') {            suggest = [{              desc: "Wrap the " + constructionType + " of '" + construction.name.name + "' in its own " + wrapperHook + "() Hook.",              fix: function (fixer) {                var _ref5 = wrapperHook === 'useMemo' ? ["useMemo(() => { return ", '; })'] : ['useCallback(', ')'],                    before = _ref5[0],                    after = _ref5[1];                return [// TODO: also add an import?                fixer.insertTextBefore(construction.node.init, before), // TODO: ideally we'd gather deps here but it would require                // restructuring the rule code. This will cause a new lint                // error to appear immediately for useCallback. Note we're                // not adding [] because would that changes semantics.                fixer.insertTextAfter(construction.node.init, after)];              }            }];          } // TODO: What if the function needs to change on every render anyway?          // Should we suggest removing effect deps as an appropriate fix too?          reportProblem({            // TODO: Why not report this at the dependency site?            node: construction.node,            message: message,            suggest: suggest          });        });        return;      } // If we're going to report a missing dependency,      // we might as well recalculate the list ignoring      // the currently specified deps. This can result      // in some extra deduplication. We can't do this      // for effects though because those have legit      // use cases for over-specifying deps.      if (!isEffect && missingDependencies.size > 0) {        suggestedDeps = collectRecommendations({          dependencies: dependencies,          declaredDependencies: [],          // Pretend we don't know          stableDependencies: stableDependencies,          externalDependencies: externalDependencies,          isEffect: isEffect        }).suggestedDependencies;      } // Alphabetize the suggestions, but only if deps were already alphabetized.      function areDeclaredDepsAlphabetized() {        if (declaredDependencies.length === 0) {          return true;        }        var declaredDepKeys = declaredDependencies.map(function (dep) {          return dep.key;        });        var sortedDeclaredDepKeys = declaredDepKeys.slice().sort();        return declaredDepKeys.join(',') === sortedDeclaredDepKeys.join(',');      }      if (areDeclaredDepsAlphabetized()) {        suggestedDeps.sort();      } // Most of our algorithm deals with dependency paths with optional chaining stripped.      // This function is the last step before printing a dependency, so now is a good time to      // check whether any members in our path are always used as optional-only. In that case,      // we will use ?. instead of . to concatenate those parts of the path.      function formatDependency(path) {        var members = path.split('.');        var finalPath = '';        for (var i = 0; i < members.length; i++) {          if (i !== 0) {            var pathSoFar = members.slice(0, i + 1).join('.');            var isOptional = optionalChains.get(pathSoFar) === true;            finalPath += isOptional ? '?.' : '.';          }          finalPath += members[i];        }        return finalPath;      }      function getWarningMessage(deps, singlePrefix, label, fixVerb) {        if (deps.size === 0) {          return null;        }        return (deps.size > 1 ? '' : singlePrefix + ' ') + label + ' ' + (deps.size > 1 ? 'dependencies' : 'dependency') + ': ' + joinEnglish(Array.from(deps).sort().map(function (name) {          return "'" + formatDependency(name) + "'";        })) + (". Either " + fixVerb + " " + (deps.size > 1 ? 'them' : 'it') + " or remove the dependency array.");      }      var extraWarning = '';      if (unnecessaryDependencies.size > 0) {        var badRef = null;        Array.from(unnecessaryDependencies.keys()).forEach(function (key) {          if (badRef !== null) {            return;          }          if (key.endsWith('.current')) {            badRef = key;          }        });        if (badRef !== null) {          extraWarning = " Mutable values like '" + badRef + "' aren't valid dependencies " + "because mutating them doesn't re-render the component.";        } else if (externalDependencies.size > 0) {          var dep = Array.from(externalDependencies)[0]; // Don't show this warning for things that likely just got moved *inside* the callback          // because in that case they're clearly not referring to globals.          if (!scope.set.has(dep)) {            extraWarning = " Outer scope values like '" + dep + "' aren't valid dependencies " + "because mutating them doesn't re-render the component.";          }        }      } // `props.foo()` marks `props` as a dependency because it has      // a `this` value. This warning can be confusing.      // So if we're going to show it, append a clarification.      if (!extraWarning && missingDependencies.has('props')) {        var propDep = dependencies.get('props');        if (propDep == null) {          return;        }        var refs = propDep.references;        if (!Array.isArray(refs)) {          return;        }        var isPropsOnlyUsedInMembers = true;        for (var i = 0; i < refs.length; i++) {          var ref = refs[i];          var id = fastFindReferenceWithParent(componentScope.block, ref.identifier);          if (!id) {            isPropsOnlyUsedInMembers = false;            break;          }          var parent = id.parent;          if (parent == null) {            isPropsOnlyUsedInMembers = false;            break;          }          if (parent.type !== 'MemberExpression' && parent.type !== 'OptionalMemberExpression') {            isPropsOnlyUsedInMembers = false;            break;          }        }        if (isPropsOnlyUsedInMembers) {          extraWarning = " However, 'props' will change when *any* prop changes, so the " + "preferred fix is to destructure the 'props' object outside of " + ("the " + reactiveHookName + " call and refer to those specific props ") + ("inside " + context.getSource(reactiveHook) + ".");        }      }      if (!extraWarning && missingDependencies.size > 0) {        // See if the user is trying to avoid specifying a callable prop.        // This usually means they're unaware of useCallback.        var missingCallbackDep = null;        missingDependencies.forEach(function (missingDep) {          if (missingCallbackDep) {            return;          } // Is this a variable from top scope?          var topScopeRef = componentScope.set.get(missingDep);          var usedDep = dependencies.get(missingDep);          if (usedDep.references[0].resolved !== topScopeRef) {            return;          } // Is this a destructured prop?          var def = topScopeRef.defs[0];          if (def == null || def.name == null || def.type !== 'Parameter') {            return;          } // Was it called in at least one case? Then it's a function.          var isFunctionCall = false;          var id;          for (var _i2 = 0; _i2 < usedDep.references.length; _i2++) {            id = usedDep.references[_i2].identifier;            if (id != null && id.parent != null && (id.parent.type === 'CallExpression' || id.parent.type === 'OptionalCallExpression') && id.parent.callee === id) {              isFunctionCall = true;              break;            }          }          if (!isFunctionCall) {            return;          } // If it's missing (i.e. in component scope) *and* it's a parameter          // then it is definitely coming from props destructuring.          // (It could also be props itself but we wouldn't be calling it then.)          missingCallbackDep = missingDep;        });        if (missingCallbackDep !== null) {          extraWarning = " If '" + missingCallbackDep + "' changes too often, " + "find the parent component that defines it " + "and wrap that definition in useCallback.";        }      }      if (!extraWarning && missingDependencies.size > 0) {        var setStateRecommendation = null;        missingDependencies.forEach(function (missingDep) {          if (setStateRecommendation !== null) {            return;          }          var usedDep = dependencies.get(missingDep);          var references = usedDep.references;          var id;          var maybeCall;          for (var _i3 = 0; _i3 < references.length; _i3++) {            id = references[_i3].identifier;            maybeCall = id.parent; // Try to see if we have setState(someExpr(missingDep)).            while (maybeCall != null && maybeCall !== componentScope.block) {              if (maybeCall.type === 'CallExpression') {                var correspondingStateVariable = setStateCallSites.get(maybeCall.callee);                if (correspondingStateVariable != null) {                  if (correspondingStateVariable.name === missingDep) {                    // setCount(count + 1)                    setStateRecommendation = {                      missingDep: missingDep,                      setter: maybeCall.callee.name,                      form: 'updater'                    };                  } else if (stateVariables.has(id)) {                    // setCount(count + increment)                    setStateRecommendation = {                      missingDep: missingDep,                      setter: maybeCall.callee.name,                      form: 'reducer'                    };                  } else {                    var resolved = references[_i3].resolved;                    if (resolved != null) {                      // If it's a parameter *and* a missing dep,                      // it must be a prop or something inside a prop.                      // Therefore, recommend an inline reducer.                      var def = resolved.defs[0];                      if (def != null && def.type === 'Parameter') {                        setStateRecommendation = {                          missingDep: missingDep,                          setter: maybeCall.callee.name,                          form: 'inlineReducer'                        };                      }                    }                  }                  break;                }              }              maybeCall = maybeCall.parent;            }            if (setStateRecommendation !== null) {              break;            }          }        });        if (setStateRecommendation !== null) {          switch (setStateRecommendation.form) {            case 'reducer':              extraWarning = " You can also replace multiple useState variables with useReducer " + ("if '" + setStateRecommendation.setter + "' needs the ") + ("current value of '" + setStateRecommendation.missingDep + "'.");              break;            case 'inlineReducer':              extraWarning = " If '" + setStateRecommendation.setter + "' needs the " + ("current value of '" + setStateRecommendation.missingDep + "', ") + "you can also switch to useReducer instead of useState and " + ("read '" + setStateRecommendation.missingDep + "' in the reducer.");              break;            case 'updater':              extraWarning = " You can also do a functional update '" + setStateRecommendation.setter + "(" + setStateRecommendation.missingDep.substring(0, 1) + " => ...)' if you only need '" + setStateRecommendation.missingDep + "'" + (" in the '" + setStateRecommendation.setter + "' call.");              break;            default:              throw new Error('Unknown case.');          }        }      }      reportProblem({        node: declaredDependenciesNode,        message: "React Hook " + context.getSource(reactiveHook) + " has " + ( // To avoid a long message, show the next actionable item.        getWarningMessage(missingDependencies, 'a', 'missing', 'include') || getWarningMessage(unnecessaryDependencies, 'an', 'unnecessary', 'exclude') || getWarningMessage(duplicateDependencies, 'a', 'duplicate', 'omit')) + extraWarning,        suggest: [{          desc: "Update the dependencies array to be: [" + suggestedDeps.map(formatDependency).join(', ') + "]",          fix: function (fixer) {            // TODO: consider preserving the comments or formatting?            return fixer.replaceText(declaredDependenciesNode, "[" + suggestedDeps.map(formatDependency).join(', ') + "]");          }        }]      });    }    function visitCallExpression(node) {      var callbackIndex = getReactiveHookCallbackIndex(node.callee, options);      if (callbackIndex === -1) {        // Not a React Hook call that needs deps.        return;      }      var callback = node.arguments[callbackIndex];      var reactiveHook = node.callee;      var reactiveHookName = getNodeWithoutReactNamespace(reactiveHook).name;      var declaredDependenciesNode = node.arguments[callbackIndex + 1];      var isEffect = /Effect($|[^a-z])/g.test(reactiveHookName); // Check whether a callback is supplied. If there is no callback supplied      // then the hook will not work and React will throw a TypeError.      // So no need to check for dependency inclusion.      if (!callback) {        reportProblem({          node: reactiveHook,          message: "React Hook " + reactiveHookName + " requires an effect callback. " + "Did you forget to pass a callback to the hook?"        });        return;      } // Check the declared dependencies for this reactive hook. If there is no      // second argument then the reactive callback will re-run on every render.      // So no need to check for dependency inclusion.      if (!declaredDependenciesNode && !isEffect) {        // These are only used for optimization.        if (reactiveHookName === 'useMemo' || reactiveHookName === 'useCallback') {          // TODO: Can this have a suggestion?          reportProblem({            node: reactiveHook,            message: "React Hook " + reactiveHookName + " does nothing when called with " + "only one argument. Did you forget to pass an array of " + "dependencies?"          });        }        return;      }      switch (callback.type) {        case 'FunctionExpression':        case 'ArrowFunctionExpression':          visitFunctionWithDependencies(callback, declaredDependenciesNode, reactiveHook, reactiveHookName, isEffect);          return;        // Handled        case 'Identifier':          if (!declaredDependenciesNode) {            // No deps, no problems.            return; // Handled          } // The function passed as a callback is not written inline.          // But perhaps it's in the dependencies array?          if (declaredDependenciesNode.elements && declaredDependenciesNode.elements.some(function (el) {            return el && el.type === 'Identifier' && el.name === callback.name;          })) {            // If it's already in the list of deps, we don't care because            // this is valid regardless.            return; // Handled          } // We'll do our best effort to find it, complain otherwise.          var variable = context.getScope().set.get(callback.name);          if (variable == null || variable.defs == null) {            // If it's not in scope, we don't care.            return; // Handled          } // The function passed as a callback is not written inline.          // But it's defined somewhere in the render scope.          // We'll do our best effort to find and check it, complain otherwise.          var def = variable.defs[0];          if (!def || !def.node) {            break; // Unhandled          }          if (def.type !== 'Variable' && def.type !== 'FunctionName') {            // Parameter or an unusual pattern. Bail out.            break; // Unhandled          }          switch (def.node.type) {            case 'FunctionDeclaration':              // useEffect(() => { ... }, []);              visitFunctionWithDependencies(def.node, declaredDependenciesNode, reactiveHook, reactiveHookName, isEffect);              return;            // Handled            case 'VariableDeclarator':              var init = def.node.init;              if (!init) {                break; // Unhandled              }              switch (init.type) {                // const effectBody = () => {...};                // useEffect(effectBody, []);                case 'ArrowFunctionExpression':                case 'FunctionExpression':                  // We can inspect this function as if it were inline.                  visitFunctionWithDependencies(init, declaredDependenciesNode, reactiveHook, reactiveHookName, isEffect);                  return;                // Handled              }              break;            // Unhandled          }          break;        // Unhandled        default:          // useEffect(generateEffectBody(), []);          reportProblem({            node: reactiveHook,            message: "React Hook " + reactiveHookName + " received a function whose dependencies " + "are unknown. Pass an inline function instead."          });          return;        // Handled      } // Something unusual. Fall back to suggesting to add the body itself as a dep.      reportProblem({        node: reactiveHook,        message: "React Hook " + reactiveHookName + " has a missing dependency: '" + callback.name + "'. " + "Either include it or remove the dependency array.",        suggest: [{          desc: "Update the dependencies array to be: [" + callback.name + "]",          fix: function (fixer) {            return fixer.replaceText(declaredDependenciesNode, "[" + callback.name + "]");          }        }]      });    }    return {      CallExpression: visitCallExpression    };  }}; // The meat of the logic.function collectRecommendations(_ref6) {  var dependencies = _ref6.dependencies,      declaredDependencies = _ref6.declaredDependencies,      stableDependencies = _ref6.stableDependencies,      externalDependencies = _ref6.externalDependencies,      isEffect = _ref6.isEffect;  // Our primary data structure.  // It is a logical representation of property chains:  // `props` -> `props.foo` -> `props.foo.bar` -> `props.foo.bar.baz`  //         -> `props.lol`  //         -> `props.huh` -> `props.huh.okay`  //         -> `props.wow`  // We'll use it to mark nodes that are *used* by the programmer,  // and the nodes that were *declared* as deps. Then we will  // traverse it to learn which deps are missing or unnecessary.  var depTree = createDepTree();  function createDepTree() {    return {      isUsed: false,      // True if used in code      isSatisfiedRecursively: false,      // True if specified in deps      isSubtreeUsed: false,      // True if something deeper is used by code      children: new Map() // Nodes for properties    };  } // Mark all required nodes first.  // Imagine exclamation marks next to each used deep property.  dependencies.forEach(function (_, key) {    var node = getOrCreateNodeByPath(depTree, key);    node.isUsed = true;    markAllParentsByPath(depTree, key, function (parent) {      parent.isSubtreeUsed = true;    });  }); // Mark all satisfied nodes.  // Imagine checkmarks next to each declared dependency.  declaredDependencies.forEach(function (_ref7) {    var key = _ref7.key;    var node = getOrCreateNodeByPath(depTree, key);    node.isSatisfiedRecursively = true;  });  stableDependencies.forEach(function (key) {    var node = getOrCreateNodeByPath(depTree, key);    node.isSatisfiedRecursively = true;  }); // Tree manipulation helpers.  function getOrCreateNodeByPath(rootNode, path) {    var keys = path.split('.');    var node = rootNode;    var _iterator3 = _createForOfIteratorHelper(keys),        _step3;    try {      for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {        var key = _step3.value;        var child = node.children.get(key);        if (!child) {          child = createDepTree();          node.children.set(key, child);        }        node = child;      }    } catch (err) {      _iterator3.e(err);    } finally {      _iterator3.f();    }    return node;  }  function markAllParentsByPath(rootNode, path, fn) {    var keys = path.split('.');    var node = rootNode;    var _iterator4 = _createForOfIteratorHelper(keys),        _step4;    try {      for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {        var key = _step4.value;        var child = node.children.get(key);        if (!child) {          return;        }        fn(child);        node = child;      }    } catch (err) {      _iterator4.e(err);    } finally {      _iterator4.f();    }  } // Now we can learn which dependencies are missing or necessary.  var missingDependencies = new Set();  var satisfyingDependencies = new Set();  scanTreeRecursively(depTree, missingDependencies, satisfyingDependencies, function (key) {    return key;  });  function scanTreeRecursively(node, missingPaths, satisfyingPaths, keyToPath) {    node.children.forEach(function (child, key) {      var path = keyToPath(key);      if (child.isSatisfiedRecursively) {        if (child.isSubtreeUsed) {          // Remember this dep actually satisfied something.          satisfyingPaths.add(path);        } // It doesn't matter if there's something deeper.        // It would be transitively satisfied since we assume immutability.        // `props.foo` is enough if you read `props.foo.id`.        return;      }      if (child.isUsed) {        // Remember that no declared deps satisfied this node.        missingPaths.add(path); // If we got here, nothing in its subtree was satisfied.        // No need to search further.        return;      }      scanTreeRecursively(child, missingPaths, satisfyingPaths, function (childKey) {        return path + '.' + childKey;      });    });  } // Collect suggestions in the order they were originally specified.  var suggestedDependencies = [];  var unnecessaryDependencies = new Set();  var duplicateDependencies = new Set();  declaredDependencies.forEach(function (_ref8) {    var key = _ref8.key;    // Does this declared dep satisfy a real need?    if (satisfyingDependencies.has(key)) {      if (suggestedDependencies.indexOf(key) === -1) {        // Good one.        suggestedDependencies.push(key);      } else {        // Duplicate.        duplicateDependencies.add(key);      }    } else {      if (isEffect && !key.endsWith('.current') && !externalDependencies.has(key)) {        // Effects are allowed extra "unnecessary" deps.        // Such as resetting scroll when ID changes.        // Consider them legit.        // The exception is ref.current which is always wrong.        if (suggestedDependencies.indexOf(key) === -1) {          suggestedDependencies.push(key);        }      } else {        // It's definitely not needed.        unnecessaryDependencies.add(key);      }    }  }); // Then add the missing ones at the end.  missingDependencies.forEach(function (key) {    suggestedDependencies.push(key);  });  return {    suggestedDependencies: suggestedDependencies,    unnecessaryDependencies: unnecessaryDependencies,    duplicateDependencies: duplicateDependencies,    missingDependencies: missingDependencies  };} // If the node will result in constructing a referentially unique value, return// its human readable type name, else return null.function getConstructionExpressionType(node) {  switch (node.type) {    case 'ObjectExpression':      return 'object';    case 'ArrayExpression':      return 'array';    case 'ArrowFunctionExpression':    case 'FunctionExpression':      return 'function';    case 'ClassExpression':      return 'class';    case 'ConditionalExpression':      if (getConstructionExpressionType(node.consequent) != null || getConstructionExpressionType(node.alternate) != null) {        return 'conditional';      }      return null;    case 'LogicalExpression':      if (getConstructionExpressionType(node.left) != null || getConstructionExpressionType(node.right) != null) {        return 'logical expression';      }      return null;    case 'JSXFragment':      return 'JSX fragment';    case 'JSXElement':      return 'JSX element';    case 'AssignmentExpression':      if (getConstructionExpressionType(node.right) != null) {        return 'assignment expression';      }      return null;    case 'NewExpression':      return 'object construction';    case 'Literal':      if (node.value instanceof RegExp) {        return 'regular expression';      }      return null;    case 'TypeCastExpression':      return getConstructionExpressionType(node.expression);    case 'TSAsExpression':      return getConstructionExpressionType(node.expression);  }  return null;} // Finds variables declared as dependencies// that would invalidate on every render.function scanForConstructions(_ref9) {  var declaredDependencies = _ref9.declaredDependencies,      declaredDependenciesNode = _ref9.declaredDependenciesNode,      componentScope = _ref9.componentScope,      scope = _ref9.scope;  var constructions = declaredDependencies.map(function (_ref10) {    var key = _ref10.key;    var ref = componentScope.variables.find(function (v) {      return v.name === key;    });    if (ref == null) {      return null;    }    var node = ref.defs[0];    if (node == null) {      return null;    } // const handleChange = function () {}    // const handleChange = () => {}    // const foo = {}    // const foo = []    // etc.    if (node.type === 'Variable' && node.node.type === 'VariableDeclarator' && node.node.id.type === 'Identifier' && // Ensure this is not destructed assignment    node.node.init != null) {      var constantExpressionType = getConstructionExpressionType(node.node.init);      if (constantExpressionType != null) {        return [ref, constantExpressionType];      }    } // function handleChange() {}    if (node.type === 'FunctionName' && node.node.type === 'FunctionDeclaration') {      return [ref, 'function'];    } // class Foo {}    if (node.type === 'ClassName' && node.node.type === 'ClassDeclaration') {      return [ref, 'class'];    }    return null;  }).filter(Boolean);  function isUsedOutsideOfHook(ref) {    var foundWriteExpr = false;    for (var i = 0; i < ref.references.length; i++) {      var reference = ref.references[i];      if (reference.writeExpr) {        if (foundWriteExpr) {          // Two writes to the same function.          return true;        } else {          // Ignore first write as it's not usage.          foundWriteExpr = true;          continue;        }      }      var currentScope = reference.from;      while (currentScope !== scope && currentScope != null) {        currentScope = currentScope.upper;      }      if (currentScope !== scope) {        // This reference is outside the Hook callback.        // It can only be legit if it's the deps array.        if (!isAncestorNodeOf(declaredDependenciesNode, reference.identifier)) {          return true;        }      }    }    return false;  }  return constructions.map(function (_ref11) {    var ref = _ref11[0],        depType = _ref11[1];    return {      construction: ref.defs[0],      depType: depType,      isUsedOutsideOfHook: isUsedOutsideOfHook(ref)    };  });}/** * Assuming () means the passed/returned node: * (props) => (props) * props.(foo) => (props.foo) * props.foo.(bar) => (props).foo.bar * props.foo.bar.(baz) => (props).foo.bar.baz */function getDependency(node) {  if ((node.parent.type === 'MemberExpression' || node.parent.type === 'OptionalMemberExpression') && node.parent.object === node && node.parent.property.name !== 'current' && !node.parent.computed && !(node.parent.parent != null && (node.parent.parent.type === 'CallExpression' || node.parent.parent.type === 'OptionalCallExpression') && node.parent.parent.callee === node.parent)) {    return getDependency(node.parent);  } else if ( // Note: we don't check OptionalMemberExpression because it can't be LHS.  node.type === 'MemberExpression' && node.parent && node.parent.type === 'AssignmentExpression' && node.parent.left === node) {    return node.object;  } else {    return node;  }}/** * Mark a node as either optional or required. * Note: If the node argument is an OptionalMemberExpression, it doesn't necessarily mean it is optional. * It just means there is an optional member somewhere inside. * This particular node might still represent a required member, so check .optional field. */function markNode(node, optionalChains, result) {  if (optionalChains) {    if (node.optional) {      // We only want to consider it optional if *all* usages were optional.      if (!optionalChains.has(result)) {        // Mark as (maybe) optional. If there's a required usage, this will be overridden.        optionalChains.set(result, true);      }    } else {      // Mark as required.      optionalChains.set(result, false);    }  }}/** * Assuming () means the passed node. * (foo) -> 'foo' * foo(.)bar -> 'foo.bar' * foo.bar(.)baz -> 'foo.bar.baz' * Otherwise throw. */function analyzePropertyChain(node, optionalChains) {  if (node.type === 'Identifier' || node.type === 'JSXIdentifier') {    var result = node.name;    if (optionalChains) {      // Mark as required.      optionalChains.set(result, false);    }    return result;  } else if (node.type === 'MemberExpression' && !node.computed) {    var object = analyzePropertyChain(node.object, optionalChains);    var property = analyzePropertyChain(node.property, null);    var _result = object + "." + property;    markNode(node, optionalChains, _result);    return _result;  } else if (node.type === 'OptionalMemberExpression' && !node.computed) {    var _object = analyzePropertyChain(node.object, optionalChains);    var _property = analyzePropertyChain(node.property, null);    var _result2 = _object + "." + _property;    markNode(node, optionalChains, _result2);    return _result2;  } else if (node.type === 'ChainExpression' && !node.computed) {    var expression = node.expression;    if (expression.type === 'CallExpression') {      throw new Error("Unsupported node type: " + expression.type);    }    var _object2 = analyzePropertyChain(expression.object, optionalChains);    var _property2 = analyzePropertyChain(expression.property, null);    var _result3 = _object2 + "." + _property2;    markNode(expression, optionalChains, _result3);    return _result3;  } else {    throw new Error("Unsupported node type: " + node.type);  }}function getNodeWithoutReactNamespace(node, options) {  if (node.type === 'MemberExpression' && node.object.type === 'Identifier' && node.object.name === 'React' && node.property.type === 'Identifier' && !node.computed) {    return node.property;  }  return node;} // What's the index of callback that needs to be analyzed for a given Hook?// -1 if it's not a Hook we care about (e.g. useState).// 0 for useEffect/useMemo/useCallback(fn).// 1 for useImperativeHandle(ref, fn).// For additionally configured Hooks, assume that they're like useEffect (0).function getReactiveHookCallbackIndex(calleeNode, options) {  var node = getNodeWithoutReactNamespace(calleeNode);  if (node.type !== 'Identifier') {    return -1;  }  switch (node.name) {    case 'useEffect':    case 'useLayoutEffect':    case 'useCallback':    case 'useMemo':      // useEffect(fn)      return 0;    case 'useImperativeHandle':      // useImperativeHandle(ref, fn)      return 1;    default:      if (node === calleeNode && options && options.additionalHooks) {        // Allow the user to provide a regular expression which enables the lint to        // target custom reactive hooks.        var name;        try {          name = analyzePropertyChain(node, null);        } catch (error) {          if (/Unsupported node type/.test(error.message)) {            return 0;          } else {            throw error;          }        }        return options.additionalHooks.test(name) ? 0 : -1;      } else {        return -1;      }  }}/** * ESLint won't assign node.parent to references from context.getScope() * * So instead we search for the node from an ancestor assigning node.parent * as we go. This mutates the AST. * * This traversal is: * - optimized by only searching nodes with a range surrounding our target node * - agnostic to AST node types, it looks for `{ type: string, ... }` */function fastFindReferenceWithParent(start, target) {  var queue = [start];  var item = null;  while (queue.length) {    item = queue.shift();    if (isSameIdentifier(item, target)) {      return item;    }    if (!isAncestorNodeOf(item, target)) {      continue;    }    for (var _i4 = 0, _Object$entries = Object.entries(item); _i4 < _Object$entries.length; _i4++) {      var _Object$entries$_i = _Object$entries[_i4],          key = _Object$entries$_i[0],          value = _Object$entries$_i[1];      if (key === 'parent') {        continue;      }      if (isNodeLike(value)) {        value.parent = item;        queue.push(value);      } else if (Array.isArray(value)) {        value.forEach(function (val) {          if (isNodeLike(val)) {            val.parent = item;            queue.push(val);          }        });      }    }  }  return null;}function joinEnglish(arr) {  var s = '';  for (var i = 0; i < arr.length; i++) {    s += arr[i];    if (i === 0 && arr.length === 2) {      s += ' and ';    } else if (i === arr.length - 2 && arr.length > 2) {      s += ', and ';    } else if (i < arr.length - 1) {      s += ', ';    }  }  return s;}function isNodeLike(val) {  return typeof val === 'object' && val !== null && !Array.isArray(val) && typeof val.type === 'string';}function isSameIdentifier(a, b) {  return (a.type === 'Identifier' || a.type === 'JSXIdentifier') && a.type === b.type && a.name === b.name && a.range[0] === b.range[0] && a.range[1] === b.range[1];}function isAncestorNodeOf(a, b) {  return a.range[0] <= b.range[0] && a.range[1] >= b.range[1];}var configs = {  recommended: {    plugins: ['react-hooks'],    rules: {      'react-hooks/rules-of-hooks': 'error',      'react-hooks/exhaustive-deps': 'warn'    }  }};var rules = {  'rules-of-hooks': RulesOfHooks,  'exhaustive-deps': ExhaustiveDeps};exports.configs = configs;exports.rules = rules;  })();}
 |