text: "use strict";
  Object.defineProperty(exports, "__esModule", { value: true });
  exports.detectTestingLibraryUtils = void 0;
  const experimental_utils_1 = require("@typescript-eslint/experimental-utils");
  const node_utils_1 = require("../node-utils");
  const utils_1 = require("../utils");
  const SETTING_OPTION_OFF = 'off';
  const USER_EVENT_PACKAGE = '@testing-library/user-event';
  const REACT_DOM_TEST_UTILS_PACKAGE = 'react-dom/test-utils';
  const FIRE_EVENT_NAME = 'fireEvent';
  const CREATE_EVENT_NAME = 'createEvent';
  const USER_EVENT_NAME = 'userEvent';
  const RENDER_NAME = 'render';
  function detectTestingLibraryUtils(ruleCreate, { skipRuleReportingCheck = false } = {}) {
      return (context, optionsWithDefault) => {
          let importedTestingLibraryNode = null;
          let importedCustomModuleNode = null;
          let importedUserEventLibraryNode = null;
          let importedReactDomTestUtilsNode = null;
          const customModuleSetting = context.settings['testing-library/utils-module'];
          const customRendersSetting = context.settings['testing-library/custom-renders'];
          const customQueriesSetting = context.settings['testing-library/custom-queries'];
          function isPotentialTestingLibraryFunction(node, isPotentialFunctionCallback) {
              if (!node) {
                  return false;
              }
              const referenceNode = (0, node_utils_1.getReferenceNode)(node);
              const referenceNodeIdentifier = (0, node_utils_1.getPropertyIdentifierNode)(referenceNode);
              if (!referenceNodeIdentifier) {
                  return false;
              }
              const importedUtilSpecifier = getTestingLibraryImportedUtilSpecifier(referenceNodeIdentifier);
              const originalNodeName = (0, node_utils_1.isImportSpecifier)(importedUtilSpecifier) &&
                  importedUtilSpecifier.local.name !== importedUtilSpecifier.imported.name
                  ? importedUtilSpecifier.imported.name
                  : undefined;
              if (!isPotentialFunctionCallback(node.name, originalNodeName)) {
                  return false;
              }
              if (isAggressiveModuleReportingEnabled()) {
                  return true;
              }
              return isNodeComingFromTestingLibrary(referenceNodeIdentifier);
          }
          const isAggressiveModuleReportingEnabled = () => !customModuleSetting;
          const isAggressiveRenderReportingEnabled = () => {
              const isSwitchedOff = customRendersSetting === SETTING_OPTION_OFF;
              const hasCustomOptions = Array.isArray(customRendersSetting) && customRendersSetting.length > 0;
              return !isSwitchedOff && !hasCustomOptions;
          };
          const isAggressiveQueryReportingEnabled = () => {
              const isSwitchedOff = customQueriesSetting === SETTING_OPTION_OFF;
              const hasCustomOptions = Array.isArray(customQueriesSetting) && customQueriesSetting.length > 0;
              return !isSwitchedOff && !hasCustomOptions;
          };
          const getCustomModule = () => {
              if (!isAggressiveModuleReportingEnabled() &&
                  customModuleSetting !== SETTING_OPTION_OFF) {
                  return customModuleSetting;
              }
              return undefined;
          };
          const getCustomRenders = () => {
              if (!isAggressiveRenderReportingEnabled() &&
                  customRendersSetting !== SETTING_OPTION_OFF) {
                  return customRendersSetting;
              }
              return [];
          };
          const getCustomQueries = () => {
              if (!isAggressiveQueryReportingEnabled() &&
                  customQueriesSetting !== SETTING_OPTION_OFF) {
                  return customQueriesSetting;
              }
              return [];
          };
          const getTestingLibraryImportNode = () => {
              return importedTestingLibraryNode;
          };
          const getCustomModuleImportNode = () => {
              return importedCustomModuleNode;
          };
          const getTestingLibraryImportName = () => {
              return (0, node_utils_1.getImportModuleName)(importedTestingLibraryNode);
          };
          const getCustomModuleImportName = () => {
              return (0, node_utils_1.getImportModuleName)(importedCustomModuleNode);
          };
          const isTestingLibraryImported = (isStrict = false) => {
              const isSomeModuleImported = !!importedTestingLibraryNode || !!importedCustomModuleNode;
              return ((!isStrict && isAggressiveModuleReportingEnabled()) ||
                  isSomeModuleImported);
          };
          const isQuery = (node) => {
              const hasQueryPattern = /^(get|query|find)(All)?By.+$/.test(node.name);
              if (!hasQueryPattern) {
                  return false;
              }
              if (isAggressiveQueryReportingEnabled()) {
                  return true;
              }
              const customQueries = getCustomQueries();
              const isBuiltInQuery = utils_1.ALL_QUERIES_COMBINATIONS.includes(node.name);
              const isReportableCustomQuery = customQueries.some((pattern) => new RegExp(pattern).test(node.name));
              return isBuiltInQuery || isReportableCustomQuery;
          };
          const isGetQueryVariant = (node) => {
              return isQuery(node) && node.name.startsWith('get');
          };
          const isQueryQueryVariant = (node) => {
              return isQuery(node) && node.name.startsWith('query');
          };
          const isFindQueryVariant = (node) => {
              return isQuery(node) && node.name.startsWith('find');
          };
          const isSyncQuery = (node) => {
              return isGetQueryVariant(node) || isQueryQueryVariant(node);
          };
          const isAsyncQuery = (node) => {
              return isFindQueryVariant(node);
          };
          const isCustomQuery = (node) => {
              return isQuery(node) && !utils_1.ALL_QUERIES_COMBINATIONS.includes(node.name);
          };
          const isBuiltInQuery = (node) => {
              return isQuery(node) && utils_1.ALL_QUERIES_COMBINATIONS.includes(node.name);
          };
          const isAsyncUtil = (node, validNames = utils_1.ASYNC_UTILS) => {
              return isPotentialTestingLibraryFunction(node, (identifierNodeName, originalNodeName) => {
                  return (validNames.includes(identifierNodeName) ||
                      (!!originalNodeName &&
                          validNames.includes(originalNodeName)));
              });
          };
          const isFireEventUtil = (node) => {
              return isPotentialTestingLibraryFunction(node, (identifierNodeName, originalNodeName) => {
                  return [identifierNodeName, originalNodeName].includes('fireEvent');
              });
          };
          const isUserEventUtil = (node) => {
              const userEvent = findImportedUserEventSpecifier();
              let userEventName;
              if (userEvent) {
                  userEventName = userEvent.name;
              }
              else if (isAggressiveModuleReportingEnabled()) {
                  userEventName = USER_EVENT_NAME;
              }
              if (!userEventName) {
                  return false;
              }
              return node.name === userEventName;
          };
          const isFireEventMethod = (node) => {
              const fireEventUtil = findImportedTestingLibraryUtilSpecifier(FIRE_EVENT_NAME);
              let fireEventUtilName;
              if (fireEventUtil) {
                  fireEventUtilName = experimental_utils_1.ASTUtils.isIdentifier(fireEventUtil)
                      ? fireEventUtil.name
                      : fireEventUtil.local.name;
              }
              else if (isAggressiveModuleReportingEnabled()) {
                  fireEventUtilName = FIRE_EVENT_NAME;
              }
              if (!fireEventUtilName) {
                  return false;
              }
              const parentMemberExpression = node.parent && (0, node_utils_1.isMemberExpression)(node.parent)
                  ? node.parent
                  : undefined;
              const parentCallExpression = node.parent && (0, node_utils_1.isCallExpression)(node.parent) ? node.parent : undefined;
              if (!parentMemberExpression && !parentCallExpression) {
                  return false;
              }
              if (parentCallExpression) {
                  return [fireEventUtilName, FIRE_EVENT_NAME].includes(node.name);
              }
              const definedParentMemberExpression = parentMemberExpression;
              const regularCall = experimental_utils_1.ASTUtils.isIdentifier(definedParentMemberExpression.object) &&
                  (0, node_utils_1.isCallExpression)(definedParentMemberExpression.parent) &&
                  definedParentMemberExpression.object.name === fireEventUtilName &&
                  node.name !== FIRE_EVENT_NAME &&
                  node.name !== fireEventUtilName;
              const wildcardCall = (0, node_utils_1.isMemberExpression)(definedParentMemberExpression.object) &&
                  experimental_utils_1.ASTUtils.isIdentifier(definedParentMemberExpression.object.object) &&
                  definedParentMemberExpression.object.object.name ===
                      fireEventUtilName &&
                  experimental_utils_1.ASTUtils.isIdentifier(definedParentMemberExpression.object.property) &&
                  definedParentMemberExpression.object.property.name ===
                      FIRE_EVENT_NAME &&
                  node.name !== FIRE_EVENT_NAME &&
                  node.name !== fireEventUtilName;
              const wildcardCallWithCallExpression = experimental_utils_1.ASTUtils.isIdentifier(definedParentMemberExpression.object) &&
                  definedParentMemberExpression.object.name === fireEventUtilName &&
                  experimental_utils_1.ASTUtils.isIdentifier(definedParentMemberExpression.property) &&
                  definedParentMemberExpression.property.name === FIRE_EVENT_NAME &&
                  !(0, node_utils_1.isMemberExpression)(definedParentMemberExpression.parent) &&
                  node.name === FIRE_EVENT_NAME &&
                  node.name !== fireEventUtilName;
              return regularCall || wildcardCall || wildcardCallWithCallExpression;
          };
          const isUserEventMethod = (node) => {
              const userEvent = findImportedUserEventSpecifier();
              let userEventName;
              if (userEvent) {
                  userEventName = userEvent.name;
              }
              else if (isAggressiveModuleReportingEnabled()) {
                  userEventName = USER_EVENT_NAME;
              }
              if (!userEventName) {
                  return false;
              }
              const parentMemberExpression = node.parent && (0, node_utils_1.isMemberExpression)(node.parent)
                  ? node.parent
                  : undefined;
              if (!parentMemberExpression) {
                  return false;
              }
              if ([userEventName, USER_EVENT_NAME].includes(node.name) ||
                  (experimental_utils_1.ASTUtils.isIdentifier(parentMemberExpression.object) &&
                      parentMemberExpression.object.name === node.name)) {
                  return false;
              }
              return (experimental_utils_1.ASTUtils.isIdentifier(parentMemberExpression.object) &&
                  parentMemberExpression.object.name === userEventName);
          };
          const isRenderUtil = (node) => isPotentialTestingLibraryFunction(node, (identifierNodeName, originalNodeName) => {
              if (isAggressiveRenderReportingEnabled()) {
                  return identifierNodeName.toLowerCase().includes(RENDER_NAME);
              }
              return [RENDER_NAME, ...getCustomRenders()].some((validRenderName) => validRenderName === identifierNodeName ||
                  (Boolean(originalNodeName) &&
                      validRenderName === originalNodeName));
          });
          const isCreateEventUtil = (node) => {
              const isCreateEventCallback = (identifierNodeName, originalNodeName) => [identifierNodeName, originalNodeName].includes(CREATE_EVENT_NAME);
              if ((0, node_utils_1.isCallExpression)(node) &&
                  (0, node_utils_1.isMemberExpression)(node.callee) &&
                  experimental_utils_1.ASTUtils.isIdentifier(node.callee.object)) {
                  return isPotentialTestingLibraryFunction(node.callee.object, isCreateEventCallback);
              }
              if ((0, node_utils_1.isCallExpression)(node) &&
                  (0, node_utils_1.isMemberExpression)(node.callee) &&
                  (0, node_utils_1.isMemberExpression)(node.callee.object) &&
                  experimental_utils_1.ASTUtils.isIdentifier(node.callee.object.property)) {
                  return isPotentialTestingLibraryFunction(node.callee.object.property, isCreateEventCallback);
              }
              const identifier = (0, node_utils_1.getDeepestIdentifierNode)(node);
              return isPotentialTestingLibraryFunction(identifier, isCreateEventCallback);
          };
          const isRenderVariableDeclarator = (node) => {
              if (!node.init) {
                  return false;
              }
              const initIdentifierNode = (0, node_utils_1.getDeepestIdentifierNode)(node.init);
              if (!initIdentifierNode) {
                  return false;
              }
              return isRenderUtil(initIdentifierNode);
          };
          const isDebugUtil = (identifierNode, validNames = utils_1.DEBUG_UTILS) => {
              const isBuiltInConsole = (0, node_utils_1.isMemberExpression)(identifierNode.parent) &&
                  experimental_utils_1.ASTUtils.isIdentifier(identifierNode.parent.object) &&
                  identifierNode.parent.object.name === 'console';
              return (!isBuiltInConsole &&
                  isPotentialTestingLibraryFunction(identifierNode, (identifierNodeName, originalNodeName) => {
                      return (validNames.includes(identifierNodeName) ||
                          (!!originalNodeName &&
                              validNames.includes(originalNodeName)));
                  }));
          };
          const isActUtil = (node) => {
              const isTestingLibraryAct = isPotentialTestingLibraryFunction(node, (identifierNodeName, originalNodeName) => {
                  return [identifierNodeName, originalNodeName]
                      .filter(Boolean)
                      .includes('act');
              });
              const isReactDomTestUtilsAct = (() => {
                  if (!importedReactDomTestUtilsNode) {
                      return false;
                  }
                  const referenceNode = (0, node_utils_1.getReferenceNode)(node);
                  const referenceNodeIdentifier = (0, node_utils_1.getPropertyIdentifierNode)(referenceNode);
                  if (!referenceNodeIdentifier) {
                      return false;
                  }
                  const importedUtilSpecifier = (0, node_utils_1.findImportSpecifier)(node.name, importedReactDomTestUtilsNode);
                  if (!importedUtilSpecifier) {
                      return false;
                  }
                  const importDeclaration = (() => {
                      if ((0, node_utils_1.isImportDeclaration)(importedUtilSpecifier.parent)) {
                          return importedUtilSpecifier.parent;
                      }
                      const variableDeclarator = (0, node_utils_1.findClosestVariableDeclaratorNode)(importedUtilSpecifier);
                      if ((0, node_utils_1.isCallExpression)(variableDeclarator === null || variableDeclarator === void 0 ? void 0 : variableDeclarator.init)) {
                          return variableDeclarator === null || variableDeclarator === void 0 ? void 0 : variableDeclarator.init;
                      }
                      return undefined;
                  })();
                  if (!importDeclaration) {
                      return false;
                  }
                  const importDeclarationName = (0, node_utils_1.getImportModuleName)(importDeclaration);
                  if (!importDeclarationName) {
                      return false;
                  }
                  if (importDeclarationName !== REACT_DOM_TEST_UTILS_PACKAGE) {
                      return false;
                  }
                  return (0, node_utils_1.hasImportMatch)(importedUtilSpecifier, referenceNodeIdentifier.name);
              })();
              return isTestingLibraryAct || isReactDomTestUtilsAct;
          };
          const isTestingLibraryUtil = (node) => {
              return (isAsyncUtil(node) ||
                  isQuery(node) ||
                  isRenderUtil(node) ||
                  isFireEventMethod(node) ||
                  isUserEventMethod(node) ||
                  isActUtil(node) ||
                  isCreateEventUtil(node));
          };
          const isPresenceAssert = (node) => {
              const { matcher, isNegated } = (0, node_utils_1.getAssertNodeInfo)(node);
              if (!matcher) {
                  return false;
              }
              return isNegated
                  ? utils_1.ABSENCE_MATCHERS.includes(matcher)
                  : utils_1.PRESENCE_MATCHERS.includes(matcher);
          };
          const isAbsenceAssert = (node) => {
              const { matcher, isNegated } = (0, node_utils_1.getAssertNodeInfo)(node);
              if (!matcher) {
                  return false;
              }
              return isNegated
                  ? utils_1.PRESENCE_MATCHERS.includes(matcher)
                  : utils_1.ABSENCE_MATCHERS.includes(matcher);
          };
          const findImportedTestingLibraryUtilSpecifier = (specifierName) => {
              var _a;
              const node = (_a = getCustomModuleImportNode()) !== null && _a !== void 0 ? _a : getTestingLibraryImportNode();
              if (!node) {
                  return undefined;
              }
              return (0, node_utils_1.findImportSpecifier)(specifierName, node);
          };
          const findImportedUserEventSpecifier = () => {
              if (!importedUserEventLibraryNode) {
                  return null;
              }
              if ((0, node_utils_1.isImportDeclaration)(importedUserEventLibraryNode)) {
                  const userEventIdentifier = importedUserEventLibraryNode.specifiers.find((specifier) => (0, node_utils_1.isImportDefaultSpecifier)(specifier));
                  if (userEventIdentifier) {
                      return userEventIdentifier.local;
                  }
              }
              else {
                  if (!experimental_utils_1.ASTUtils.isVariableDeclarator(importedUserEventLibraryNode.parent)) {
                      return null;
                  }
                  const requireNode = importedUserEventLibraryNode.parent;
                  if (!experimental_utils_1.ASTUtils.isIdentifier(requireNode.id)) {
                      return null;
                  }
                  return requireNode.id;
              }
              return null;
          };
          const getTestingLibraryImportedUtilSpecifier = (node) => {
              var _a;
              const identifierName = (_a = (0, node_utils_1.getPropertyIdentifierNode)(node)) === null || _a === void 0 ? void 0 : _a.name;
              if (!identifierName) {
                  return undefined;
              }
              return findImportedTestingLibraryUtilSpecifier(identifierName);
          };
          const canReportErrors = () => {
              return skipRuleReportingCheck || isTestingLibraryImported();
          };
          const isNodeComingFromTestingLibrary = (node) => {
              var _a;
              const importNode = getTestingLibraryImportedUtilSpecifier(node);
              if (!importNode) {
                  return false;
              }
              const referenceNode = (0, node_utils_1.getReferenceNode)(node);
              const referenceNodeIdentifier = (0, node_utils_1.getPropertyIdentifierNode)(referenceNode);
              if (!referenceNodeIdentifier) {
                  return false;
              }
              const importDeclaration = (() => {
                  if ((0, node_utils_1.isImportDeclaration)(importNode.parent)) {
                      return importNode.parent;
                  }
                  const variableDeclarator = (0, node_utils_1.findClosestVariableDeclaratorNode)(importNode);
                  if ((0, node_utils_1.isCallExpression)(variableDeclarator === null || variableDeclarator === void 0 ? void 0 : variableDeclarator.init)) {
                      return variableDeclarator === null || variableDeclarator === void 0 ? void 0 : variableDeclarator.init;
                  }
                  return undefined;
              })();
              if (!importDeclaration) {
                  return false;
              }
              const importDeclarationName = (0, node_utils_1.getImportModuleName)(importDeclaration);
              if (!importDeclarationName) {
                  return false;
              }
              const identifierName = (_a = (0, node_utils_1.getPropertyIdentifierNode)(node)) === null || _a === void 0 ? void 0 : _a.name;
              if (!identifierName) {
                  return false;
              }
              const hasImportElementMatch = (0, node_utils_1.hasImportMatch)(importNode, identifierName);
              const hasImportModuleMatch = /testing-library/g.test(importDeclarationName) ||
                  (typeof customModuleSetting === 'string' &&
                      importDeclarationName.endsWith(customModuleSetting));
              return hasImportElementMatch && hasImportModuleMatch;
          };
          const helpers = {
              getTestingLibraryImportNode,
              getCustomModuleImportNode,
              getTestingLibraryImportName,
              getCustomModuleImportName,
              isTestingLibraryImported,
              isTestingLibraryUtil,
              isGetQueryVariant,
              isQueryQueryVariant,
              isFindQueryVariant,
              isSyncQuery,
              isAsyncQuery,
              isQuery,
              isCustomQuery,
              isBuiltInQuery,
              isAsyncUtil,
              isFireEventUtil,
              isUserEventUtil,
              isFireEventMethod,
              isUserEventMethod,
              isRenderUtil,
              isCreateEventUtil,
              isRenderVariableDeclarator,
              isDebugUtil,
              isActUtil,
              isPresenceAssert,
              isAbsenceAssert,
              canReportErrors,
              findImportedTestingLibraryUtilSpecifier,
              isNodeComingFromTestingLibrary,
          };
          const detectionInstructions = {
              ImportDeclaration(node) {
                  if (typeof node.source.value !== 'string') {
                      return;
                  }
                  if (!importedTestingLibraryNode &&
                      /testing-library/g.test(node.source.value)) {
                      importedTestingLibraryNode = node;
                  }
                  const customModule = getCustomModule();
                  if (customModule &&
                      !importedCustomModuleNode &&
                      node.source.value.endsWith(customModule)) {
                      importedCustomModuleNode = node;
                  }
                  if (!importedUserEventLibraryNode &&
                      node.source.value === USER_EVENT_PACKAGE) {
                      importedUserEventLibraryNode = node;
                  }
                  if (!importedUserEventLibraryNode &&
                      node.source.value === REACT_DOM_TEST_UTILS_PACKAGE) {
                      importedReactDomTestUtilsNode = node;
                  }
              },
              [`CallExpression > Identifier[name="require"]`](node) {
                  const callExpression = node.parent;
                  const { arguments: args } = callExpression;
                  if (!importedTestingLibraryNode &&
                      args.some((arg) => (0, node_utils_1.isLiteral)(arg) &&
                          typeof arg.value === 'string' &&
                          /testing-library/g.test(arg.value))) {
                      importedTestingLibraryNode = callExpression;
                  }
                  const customModule = getCustomModule();
                  if (!importedCustomModuleNode &&
                      args.some((arg) => customModule &&
                          (0, node_utils_1.isLiteral)(arg) &&
                          typeof arg.value === 'string' &&
                          arg.value.endsWith(customModule))) {
                      importedCustomModuleNode = callExpression;
                  }
                  if (!importedCustomModuleNode &&
                      args.some((arg) => (0, node_utils_1.isLiteral)(arg) &&
                          typeof arg.value === 'string' &&
                          arg.value === USER_EVENT_PACKAGE)) {
                      importedUserEventLibraryNode = callExpression;
                  }
                  if (!importedReactDomTestUtilsNode &&
                      args.some((arg) => (0, node_utils_1.isLiteral)(arg) &&
                          typeof arg.value === 'string' &&
                          arg.value === REACT_DOM_TEST_UTILS_PACKAGE)) {
                      importedReactDomTestUtilsNode = callExpression;
                  }
              },
          };
          const ruleInstructions = ruleCreate(context, optionsWithDefault, helpers);
          const enhancedRuleInstructions = {};
          const allKeys = new Set(Object.keys(detectionInstructions).concat(Object.keys(ruleInstructions)));
          allKeys.forEach((instruction) => {
              enhancedRuleInstructions[instruction] = (node) => {
                  var _a, _b;
                  if (instruction in detectionInstructions) {
                      (_a = detectionInstructions[instruction]) === null || _a === void 0 ? void 0 : _a.call(detectionInstructions, node);
                  }
                  if (canReportErrors() && ruleInstructions[instruction]) {
                      return (_b = ruleInstructions[instruction]) === null || _b === void 0 ? void 0 : _b.call(ruleInstructions, node);
                  }
                  return undefined;
              };
          });
          return enhancedRuleInstructions;
      };
  }
  exports.detectTestingLibraryUtils = detectTestingLibraryUtils;
  