text: /** @license React v2.3.0
   * 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';
  
  /* eslint-disable no-for-of-loops/no-for-of-loops */
  
  /**
   * Catch all identifiers that begin with "use" followed by an uppercase Latin
   * character to exclude identifiers like "user".
   */
  
  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)) {
      // Only consider React.useFoo() to be namespace hooks for now to avoid false positives.
      // We can expand this check later.
      var obj = node.object;
      return obj.type === 'Identifier' && obj.name === 'React';
    } 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 isInsideComponentOrHook(node) {
    while (node) {
      var functionName = getFunctionName(node);
  
      if (functionName) {
        if (isComponentName(functionName) || isHook(functionName)) {
          return true;
        }
      }
  
      node = node.parent;
    }
  
    return false;
  }
  
  var RuleOfHooks = {
    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) {
            var cache = countPathsFromStart.cache;
            var paths = cache.get(segment.id); // If `paths` is null then we've found a cycle! Add it to `cyclic` and
            // any other segments which are a part of this cycle.
  
            if (paths === null) {
              if (cyclic.has(segment.id)) {
                return 0;
              } else {
                cyclic.add(segment.id);
                var _iteratorNormalCompletion = true;
                var _didIteratorError = false;
                var _iteratorError = undefined;
  
                try {
                  for (var _iterator = segment.prevSegments[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
                    var prevSegment = _step.value;
                    countPathsFromStart(prevSegment);
                  }
                } catch (err) {
                  _didIteratorError = true;
                  _iteratorError = err;
                } finally {
                  try {
                    if (!_iteratorNormalCompletion && _iterator.return != null) {
                      _iterator.return();
                    }
                  } finally {
                    if (_didIteratorError) {
                      throw _iteratorError;
                    }
                  }
                }
  
                return 0;
              }
            } // We have a cached `paths`. Return it.
  
  
            if (paths !== undefined) {
              return paths;
            } // Compute `paths` and cache it. Guarding against cycles.
  
  
            cache.set(segment.id, null);
  
            if (codePath.thrownSegments.includes(segment)) {
              paths = 0;
            } else if (segment.prevSegments.length === 0) {
              paths = 1;
            } else {
              paths = 0;
              var _iteratorNormalCompletion2 = true;
              var _didIteratorError2 = false;
              var _iteratorError2 = undefined;
  
              try {
                for (var _iterator2 = segment.prevSegments[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
                  var _prevSegment = _step2.value;
                  paths += countPathsFromStart(_prevSegment);
                }
              } catch (err) {
                _didIteratorError2 = true;
                _iteratorError2 = err;
              } finally {
                try {
                  if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
                    _iterator2.return();
                  }
                } finally {
                  if (_didIteratorError2) {
                    throw _iteratorError2;
                  }
                }
              }
            } // 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 === 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) {
            var cache = countPathsToEnd.cache;
            var paths = cache.get(segment.id); // If `paths` is null then we've found a cycle! Add it to `cyclic` and
            // any other segments which are a part of this cycle.
  
            if (paths === null) {
              if (cyclic.has(segment.id)) {
                return 0;
              } else {
                cyclic.add(segment.id);
                var _iteratorNormalCompletion3 = true;
                var _didIteratorError3 = false;
                var _iteratorError3 = undefined;
  
                try {
                  for (var _iterator3 = segment.nextSegments[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
                    var nextSegment = _step3.value;
                    countPathsToEnd(nextSegment);
                  }
                } catch (err) {
                  _didIteratorError3 = true;
                  _iteratorError3 = err;
                } finally {
                  try {
                    if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
                      _iterator3.return();
                    }
                  } finally {
                    if (_didIteratorError3) {
                      throw _iteratorError3;
                    }
                  }
                }
  
                return 0;
              }
            } // We have a cached `paths`. Return it.
  
  
            if (paths !== undefined) {
              return paths;
            } // Compute `paths` and cache it. Guarding against cycles.
  
  
            cache.set(segment.id, null);
  
            if (codePath.thrownSegments.includes(segment)) {
              paths = 0;
            } else if (segment.nextSegments.length === 0) {
              paths = 1;
            } else {
              paths = 0;
              var _iteratorNormalCompletion4 = true;
              var _didIteratorError4 = false;
              var _iteratorError4 = undefined;
  
              try {
                for (var _iterator4 = segment.nextSegments[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
                  var _nextSegment = _step4.value;
                  paths += countPathsToEnd(_nextSegment);
                }
              } catch (err) {
                _didIteratorError4 = true;
                _iteratorError4 = err;
              } finally {
                try {
                  if (!_iteratorNormalCompletion4 && _iterator4.return != null) {
                    _iterator4.return();
                  }
                } finally {
                  if (_didIteratorError4) {
                    throw _iteratorError4;
                  }
                }
              }
            }
  
            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 _iteratorNormalCompletion5 = true;
              var _didIteratorError5 = false;
              var _iteratorError5 = undefined;
  
              try {
                for (var _iterator5 = segment.prevSegments[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
                  var prevSegment = _step5.value;
                  var prevLength = shortestPathLengthToStart(prevSegment);
  
                  if (prevLength < length) {
                    length = prevLength;
                  }
                }
              } catch (err) {
                _didIteratorError5 = true;
                _iteratorError5 = err;
              } finally {
                try {
                  if (!_iteratorNormalCompletion5 && _iterator5.return != null) {
                    _iterator5.return();
                  }
                } finally {
                  if (_didIteratorError5) {
                    throw _iteratorError5;
                  }
                }
              }
  
              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.
  
          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) : false; // 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 _iteratorNormalCompletion6 = true;
          var _didIteratorError6 = false;
          var _iteratorError6 = undefined;
  
          try {
            for (var _iterator6 = codePath.finalSegments[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
              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) {
            _didIteratorError6 = true;
            _iteratorError6 = err;
          } finally {
            try {
              if (!_iteratorNormalCompletion6 && _iterator6.return != null) {
                _iterator6.return();
              }
            } finally {
              if (_didIteratorError6) {
                throw _iteratorError6;
              }
            }
          }
  
          var _iteratorNormalCompletion7 = true;
          var _didIteratorError7 = false;
          var _iteratorError7 = undefined;
  
          try {
            for (var _iterator7 = reactHooksMap[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
              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 _iteratorNormalCompletion8 = true;
              var _didIteratorError8 = false;
              var _iteratorError8 = undefined;
  
              try {
                for (var _iterator8 = reactHooks[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
                  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) {// Ignore class methods for now because they produce too many
                    // false positives due to feature flag checks. We're less
                    // sensitive to them in classes because hooks would produce
                    // runtime errors in classes anyway, and because a use*()
                    // call in a class, if it works, is unambiguously *not* a hook.
                  } else if (codePathFunctionName) {
                    // Custom message if we found an invalid function name.
                    var _message = "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.';
  
                    context.report({
                      node: hook,
                      message: _message
                    });
                  } else if (codePathNode.type === 'Program') {
                    // These are dangerous if you have inline requires enabled.
                    var _message2 = "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: _message2
                    });
                  } 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 _message3 = "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: _message3
                      });
                    }
                  }
                }
              } catch (err) {
                _didIteratorError8 = true;
                _iteratorError8 = err;
              } finally {
                try {
                  if (!_iteratorNormalCompletion8 && _iterator8.return != null) {
                    _iterator8.return();
                  }
                } finally {
                  if (_didIteratorError8) {
                    throw _iteratorError8;
                  }
                }
              }
            }
          } catch (err) {
            _didIteratorError7 = true;
            _iteratorError7 = err;
          } finally {
            try {
              if (!_iteratorNormalCompletion7 && _iterator7.return != null) {
                _iterator7.return();
              }
            } finally {
              if (_didIteratorError7) {
                throw _iteratorError7;
              }
            }
          }
        },
        // 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 usecase.
   */
  
  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: {
      fixable: 'code',
      schema: [{
        type: 'object',
        additionalProperties: false,
        properties: {
          additionalHooks: {
            type: 'string'
          }
        }
      }]
    },
    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 options = {
        additionalHooks: additionalHooks
      }; // Should be shared between visitors.
  
      var setStateCallSites = new WeakMap();
      var stateVariables = new WeakSet();
      var staticKnownValueCache = 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;
        };
      }
  
      return {
        FunctionExpression: visitFunctionExpression,
        ArrowFunctionExpression: visitFunctionExpression
      };
      /**
       * Visitor for both function expressions and arrow function expressions.
       */
  
      function visitFunctionExpression(node) {
        // We only want to lint nodes which are reactive hook callbacks.
        if (node.type !== 'FunctionExpression' && node.type !== 'ArrowFunctionExpression' || node.parent.type !== 'CallExpression') {
          return;
        }
  
        var callbackIndex = getReactiveHookCallbackIndex(node.parent.callee, options);
  
        if (node.parent.arguments[callbackIndex] !== node) {
          return;
        } // Get the reactive hook node.
  
  
        var reactiveHook = node.parent.callee;
        var reactiveHookName = getNodeWithoutReactNamespace(reactiveHook).name;
        var isEffect = reactiveHookName.endsWith('Effect'); // Get 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.
  
        var depsIndex = callbackIndex + 1;
        var declaredDependenciesNode = node.parent.arguments[depsIndex];
  
        if (!declaredDependenciesNode && !isEffect) {
          // These are only used for optimization.
          if (reactiveHookName === 'useMemo' || reactiveHookName === 'useCallback') {
            // TODO: Can this have an autofix?
            context.report({
              node: node.parent.callee,
              message: "React Hook " + reactiveHookName + " does nothing when called with " + "only one argument. Did you forget to pass an array of " + "dependencies?"
            });
          }
  
          return;
        }
  
        if (isEffect && node.async) {
          context.report({
            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://fb.me/react-hooks-data-fetching'
          });
        } // Get the current scope.
  
  
        var scope = context.getScope(); // 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;
        } // 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 static 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 isStaticKnownHookValue(resolved) {
          if (!Array.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;
          } // 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 static
            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 static.
            return true;
          } else if (name === 'useState' || name === 'useReducer') {
            // Only consider second value in initializing tuple static.
            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]) {
                if (name === 'useState') {
                  var references = resolved.references;
  
                  for (var i = 0; i < references.length; i++) {
                    setStateCallSites.set(references[i].identifier, id.elements[0]);
                  }
                } // Setter is static.
  
  
                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;
              }
            }
          } // By default assume it's dynamic.
  
  
          return false;
        } // Some are just functions that don't reference anything dynamic.
  
  
        function isFunctionWithoutCapturedValues(resolved) {
          if (!Array.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) && // Static values are fine though,
            // although we won't check functions deeper.
            !memoizedIsStaticKnownHookValue(ref.resolved)) {
              return false;
            }
          } // If we got here, this function doesn't capture anything
          // from render--or everything it captures is known static.
  
  
          return true;
        } // Remember such values. Avoid re-running extra checks on them.
  
  
        var memoizedIsStaticKnownHookValue = memoizeWithWeakMap(isStaticKnownHookValue, staticKnownValueCache);
        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 static.
  
  
        var dependencies = new Map();
        gatherDependenciesRecursively(scope);
  
        function gatherDependenciesRecursively(currentScope) {
          var _iteratorNormalCompletion = true;
          var _didIteratorError = false;
          var _iteratorError = undefined;
  
          try {
            for (var _iterator = currentScope.references[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
              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 = toPropertyAccessString(dependencyNode); // 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.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
                });
              }
  
              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 static.
  
  
              if (!dependencies.has(dependency)) {
                var resolved = reference.resolved;
                var isStatic = memoizedIsStaticKnownHookValue(resolved) || memoizedIsFunctionWithoutCapturedValues(resolved);
                dependencies.set(dependency, {
                  isStatic: isStatic,
                  references: [reference]
                });
              } else {
                dependencies.get(dependency).references.push(reference);
              }
            }
          } catch (err) {
            _didIteratorError = true;
            _iteratorError = err;
          } finally {
            try {
              if (!_iteratorNormalCompletion && _iterator.return != null) {
                _iterator.return();
              }
            } finally {
              if (_didIteratorError) {
                throw _iteratorError;
              }
            }
          }
  
          var _iteratorNormalCompletion2 = true;
          var _didIteratorError2 = false;
          var _iteratorError2 = undefined;
  
          try {
            for (var _iterator2 = currentScope.childScopes[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
              var childScope = _step2.value;
              gatherDependenciesRecursively(childScope);
            }
          } catch (err) {
            _didIteratorError2 = true;
            _iteratorError2 = err;
          } finally {
            try {
              if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
                _iterator2.return();
              }
            } finally {
              if (_didIteratorError2) {
                throw _iteratorError2;
              }
            }
          }
        } // 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
            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;
          }
  
          context.report({
            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);
          context.report({
            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 optional and report bad usage first.
  
  
        var optionalDependencies = new Set();
        dependencies.forEach(function (_ref2, key) {
          var isStatic = _ref2.isStatic,
              references = _ref2.references;
  
          if (isStatic) {
            optionalDependencies.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 isStatic = _ref3.isStatic,
                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: [],
              optionalDependencies: optionalDependencies,
              externalDependencies: new Set(),
              isEffect: true
            }),
                _suggestedDependencies = _collectRecommendatio.suggestedDependencies;
  
            context.report({
              node: node.parent.callee,
              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."),
              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.
          context.report({
            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') {
              context.report({
                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 = toPropertyAccessString(declaredDependencyNode);
            } catch (error) {
              if (/Unsupported node type/.test(error.message)) {
                if (declaredDependencyNode.type === 'Literal') {
                  if (dependencies.has(declaredDependencyNode.value)) {
                    context.report({
                      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 {
                    context.report({
                      node: declaredDependencyNode,
                      message: "The " + declaredDependencyNode.raw + " literal is not a valid dependency " + 'because it never changes. You can safely remove it.'
                    });
                  }
                } else {
                  context.report({
                    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 = maybeID.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,
          optionalDependencies: optionalDependencies,
          externalDependencies: externalDependencies,
          isEffect: isEffect
        }),
            suggestedDependencies = _collectRecommendatio2.suggestedDependencies,
            unnecessaryDependencies = _collectRecommendatio2.unnecessaryDependencies,
            missingDependencies = _collectRecommendatio2.missingDependencies,
            duplicateDependencies = _collectRecommendatio2.duplicateDependencies;
  
        var problemCount = duplicateDependencies.size + missingDependencies.size + unnecessaryDependencies.size;
  
        if (problemCount === 0) {
          // If nothing else to report, check if some callbacks
          // are bare and would invalidate on every render.
          var bareFunctions = scanForDeclaredBareFunctions({
            declaredDependencies: declaredDependencies,
            declaredDependenciesNode: declaredDependenciesNode,
            componentScope: componentScope,
            scope: scope
          });
          bareFunctions.forEach(function (_ref4) {
            var fn = _ref4.fn,
                suggestUseCallback = _ref4.suggestUseCallback;
            var message = "The '" + fn.name.name + "' function makes the dependencies of " + (reactiveHookName + " Hook (at line " + declaredDependenciesNode.loc.start.line + ") ") + "change on every render.";
  
            if (suggestUseCallback) {
              message += " To fix this, " + ("wrap the '" + fn.name.name + "' definition into its own useCallback() Hook.");
            } else {
              message += " Move it inside the " + reactiveHookName + " callback. " + ("Alternatively, wrap the '" + fn.name.name + "' definition into its own useCallback() Hook.");
            } // TODO: What if the function needs to change on every render anyway?
            // Should we suggest removing effect deps as an appropriate fix too?
  
  
            context.report({
              // TODO: Why not report this at the dependency site?
              node: fn.node,
              message: message,
              fix: function (fixer) {
                // Only handle the simple case: arrow functions.
                // Wrapping function declarations can mess up hoisting.
                if (suggestUseCallback && fn.type === 'Variable') {
                  return [// TODO: also add an import?
                  fixer.insertTextBefore(fn.node.init, 'useCallback('), // 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(fn.node.init, ')')];
                }
              }
            });
          });
          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) {
          suggestedDependencies = collectRecommendations({
            dependencies: dependencies,
            declaredDependencies: [],
            // Pretend we don't know
            optionalDependencies: optionalDependencies,
            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()) {
          suggestedDependencies.sort();
        }
  
        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 "'" + 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') {
              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.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.');
            }
          }
        }
  
        context.report({
          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,
          fix: function (fixer) {
            // TODO: consider preserving the comments or formatting?
            return fixer.replaceText(declaredDependenciesNode, "[" + suggestedDependencies.join(', ') + "]");
          }
        });
      }
    }
  }; // The meat of the logic.
  
  function collectRecommendations(_ref5) {
    var dependencies = _ref5.dependencies,
        declaredDependencies = _ref5.declaredDependencies,
        optionalDependencies = _ref5.optionalDependencies,
        externalDependencies = _ref5.externalDependencies,
        isEffect = _ref5.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 {
        isRequired: false,
        // True if used in code
        isSatisfiedRecursively: false,
        // True if specified in deps
        hasRequiredNodesBelow: 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.isRequired = true;
      markAllParentsByPath(depTree, key, function (parent) {
        parent.hasRequiredNodesBelow = true;
      });
    }); // Mark all satisfied nodes.
    // Imagine checkmarks next to each declared dependency.
  
    declaredDependencies.forEach(function (_ref6) {
      var key = _ref6.key;
      var node = getOrCreateNodeByPath(depTree, key);
      node.isSatisfiedRecursively = true;
    });
    optionalDependencies.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 _iteratorNormalCompletion3 = true;
      var _didIteratorError3 = false;
      var _iteratorError3 = undefined;
  
      try {
        for (var _iterator3 = keys[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
          var key = _step3.value;
          var child = node.children.get(key);
  
          if (!child) {
            child = createDepTree();
            node.children.set(key, child);
          }
  
          node = child;
        }
      } catch (err) {
        _didIteratorError3 = true;
        _iteratorError3 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
            _iterator3.return();
          }
        } finally {
          if (_didIteratorError3) {
            throw _iteratorError3;
          }
        }
      }
  
      return node;
    }
  
    function markAllParentsByPath(rootNode, path, fn) {
      var keys = path.split('.');
      var node = rootNode;
      var _iteratorNormalCompletion4 = true;
      var _didIteratorError4 = false;
      var _iteratorError4 = undefined;
  
      try {
        for (var _iterator4 = keys[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
          var key = _step4.value;
          var child = node.children.get(key);
  
          if (!child) {
            return;
          }
  
          fn(child);
          node = child;
        }
      } catch (err) {
        _didIteratorError4 = true;
        _iteratorError4 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion4 && _iterator4.return != null) {
            _iterator4.return();
          }
        } finally {
          if (_didIteratorError4) {
            throw _iteratorError4;
          }
        }
      }
    } // 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.hasRequiredNodesBelow) {
            // 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.isRequired) {
          // 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 (_ref7) {
      var key = _ref7.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
    };
  } // Finds functions declared as dependencies
  // that would invalidate on every render.
  
  
  function scanForDeclaredBareFunctions(_ref8) {
    var declaredDependencies = _ref8.declaredDependencies,
        declaredDependenciesNode = _ref8.declaredDependenciesNode,
        componentScope = _ref8.componentScope,
        scope = _ref8.scope;
    var bareFunctions = declaredDependencies.map(function (_ref9) {
      var key = _ref9.key;
      var fnRef = componentScope.set.get(key);
  
      if (fnRef == null) {
        return null;
      }
  
      var fnNode = fnRef.defs[0];
  
      if (fnNode == null) {
        return null;
      } // const handleChange = function () {}
      // const handleChange = () => {}
  
  
      if (fnNode.type === 'Variable' && fnNode.node.type === 'VariableDeclarator' && fnNode.node.init != null && (fnNode.node.init.type === 'ArrowFunctionExpression' || fnNode.node.init.type === 'FunctionExpression')) {
        return fnRef;
      } // function handleChange() {}
  
  
      if (fnNode.type === 'FunctionName' && fnNode.node.type === 'FunctionDeclaration') {
        return fnRef;
      }
  
      return null;
    }).filter(Boolean);
  
    function isUsedOutsideOfHook(fnRef) {
      var foundWriteExpr = false;
  
      for (var i = 0; i < fnRef.references.length; i++) {
        var reference = fnRef.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 bareFunctions.map(function (fnRef) {
      return {
        fn: fnRef.defs[0],
        suggestUseCallback: isUsedOutsideOfHook(fnRef)
      };
    });
  }
  /**
   * 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.object === node && node.parent.property.name !== 'current' && !node.parent.computed && !(node.parent.parent != null && node.parent.parent.type === 'CallExpression' && node.parent.parent.callee === node.parent)) {
      return getDependency(node.parent);
    } else {
      return node;
    }
  }
  /**
   * Assuming () means the passed node.
   * (foo) -> 'foo'
   * foo.(bar) -> 'foo.bar'
   * foo.bar.(baz) -> 'foo.bar.baz'
   * Otherwise throw.
   */
  
  
  function toPropertyAccessString(node) {
    if (node.type === 'Identifier') {
      return node.name;
    } else if (node.type === 'MemberExpression' && !node.computed) {
      var object = toPropertyAccessString(node.object);
      var property = toPropertyAccessString(node.property);
      return object + "." + property;
    } 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 null;
    }
  
    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 = toPropertyAccessString(node);
          } 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.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 rules = {
    'rules-of-hooks': RuleOfHooks,
    'exhaustive-deps': ExhaustiveDeps
  };
  
  var src = Object.freeze({
  	rules: rules
  });
  
  var eslintPluginReactHooks = src;
  
  module.exports = eslintPluginReactHooks;
    })();
  }
  