function getWildcardDirectoryFromSpec(spec, useCaseSensitiveFileNames) {
  const match = wildcardDirectoryPattern.exec(spec);
  if (match) {
    const questionWildcardIndex = spec.indexOf("?");
    const starWildcardIndex = spec.indexOf("*");
    const lastDirectorySeperatorIndex = spec.lastIndexOf(directorySeparator);
    return {
      key: useCaseSensitiveFileNames ? match[0] : toFileNameLowerCase(match[0]),
      flags: questionWildcardIndex !== -1 && questionWildcardIndex < lastDirectorySeperatorIndex || starWildcardIndex !== -1 && starWildcardIndex < lastDirectorySeperatorIndex ? 1 /* Recursive */ : 0 /* None */
    };
  }
  if (isImplicitGlob(spec.substring(spec.lastIndexOf(directorySeparator) + 1))) {
    return {
      key: removeTrailingDirectorySeparator(useCaseSensitiveFileNames ? spec : toFileNameLowerCase(spec)),
      flags: 1 /* Recursive */
    };
  }
  return void 0;
}
/");
  if (wildcardIndex === -1) {
    return false;
  }
  const lastDotIndex = endsWith(s, "/..") ? s.length : s.lastIndexOf("/../");
  return lastDotIndex > wildcardIndex;
}
function matchesExclude(pathToCheck, excludeSpecs, useCaseSensitiveFileNames, currentDirectory) {
  return matchesExcludeWorker(
    pathToCheck,
    filter(excludeSpecs, (spec) => !invalidDotDotAfterRecursiveWildcard(spec)),
    useCaseSensitiveFileNames,
    currentDirectory
  );
}
function matchesExcludeWorker(pathToCheck, excludeSpecs, useCaseSensitiveFileNames, currentDirectory, basePath) {
  const excludePattern = getRegularExpressionForWildcard(excludeSpecs, combinePaths(normalizePath(currentDirectory), basePath), "exclude");
  const excludeRegex = excludePattern && getRegexFromPattern(excludePattern, useCaseSensitiveFileNames);
  if (!excludeRegex)
    return false;
  if (excludeRegex.test(pathToCheck))
    return true;
  return !hasExtension(pathToCheck) && excludeRegex.test(ensureTrailingDirectorySeparator(pathToCheck));
}
function validateSpecs(specs, errors, disallowTrailingRecursion, jsonSourceFile, specKey) {
  return specs.filter((spec) => {
    if (!isString(spec))
      return false;
    const diag2 = specToDiagnostic(spec, disallowTrailingRecursion);
    if (diag2 !== void 0) {
      errors.push(createDiagnostic(...diag2));
    }
    return diag2 === void 0;
  });
  function createDiagnostic(message, spec) {
    const element = getTsConfigPropArrayElementValue(jsonSourceFile, specKey, spec);
    return element ? createDiagnosticForNodeInSourceFile(jsonSourceFile, element, message, spec) : createCompilerDiagnostic(message, spec);
  }
}
function specToDiagnostic(spec, disallowTrailingRecursion) {
  Debug.assert(typeof spec === "string");
  if (disallowTrailingRecursion && invalidTrailingRecursionPattern.test(spec)) {
    return [Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, spec];
  } else if (invalidDotDotAfterRecursiveWildcard(spec)) {
    return [Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, spec];
  }
}
function getWildcardDirectories({ validatedIncludeSpecs: include, validatedExcludeSpecs: exclude }, path, useCaseSensitiveFileNames) {
  const rawExcludeRegex = getRegularExpressionForWildcard(exclude, path, "exclude");
  const excludeRegex = rawExcludeRegex && new RegExp(rawExcludeRegex, useCaseSensitiveFileNames ? "" : "i");
  const wildcardDirectories = {};
  if (include !== void 0) {
    const recursiveKeys = [];
    for (const file of include) {
      const spec = normalizePath(combinePaths(path, file));
      if (excludeRegex && excludeRegex.test(spec)) {
        continue;
      }
      const match = getWildcardDirectoryFromSpec(spec, useCaseSensitiveFileNames);
      if (match) {
        const { key, flags } = match;
        const existingFlags = wildcardDirectories[key];
        if (existingFlags === void 0 || existingFlags < flags) {
          wildcardDirectories[key] = flags;
          if (flags === 1 /* Recursive