async function globSearch({
	basePath,
	patterns,
	rawPatterns,
	configLoader,
	errorOnUnmatchedPattern,
}) {
	if (patterns.length === 0) {
		return [];
	}

	/*
	 * In this section we are converting the patterns into Minimatch
	 * instances for performance reasons. Because we are doing the same
	 * matches repeatedly, it's best to compile those patterns once and
	 * reuse them multiple times.
	 *
	 * To do that, we convert any patterns with an absolute path into a
	 * relative path and normalize it to Posix-style slashes. We also keep
	 * track of the relative patterns to map them back to the original
	 * patterns, which we need in order to throw an error if there are any
	 * unmatched patterns.
	 */
	const relativeToPatterns = new Map();
	const matchers = patterns.map((pattern, i) => {
		const patternToUse = normalizeToPosix(path.relative(basePath, pattern));

		relativeToPatterns.set(patternToUse, patterns[i]);

		return new Minimatch(patternToUse, MINIMATCH_OPTIONS);
	});

	/*
	 * We track unmatched patterns because we may want to throw an error when
	 * they occur. To start, this set is initialized with all of the patterns.
	 * Every time a match occurs, the pattern is removed from the set, making
	 * it easy to tell if we have any unmatched patterns left at the end of
	 * search.
	 */
	const unmatchedPatterns = new Set([...relativeToPatterns.keys()]);
	const { hfs } = await import("@humanfs/node");

	const walk = hfs.walk(basePath, {
		async directoryFilter(entry) {
			if (!matchers.some(matcher => matcher.match(entry.path, true))) {
				return false;
			}

			const absolutePath = path.resolve(basePath, entry.path);
			const configs =
				await configLoader.loadConfigArrayForDirectory(absolutePath);

			return !configs.isDirectoryIgnored(absolutePath);
		},
		async entryFilter(entry) {
			const absolutePath = path.resolve(basePath, entry.path);

			// entries may be directories or files so filter out directories
			if (entry.isDirectory) {
				return false;
			}

			const configs =
				await configLoader.loadConfigArrayForFile(absolutePath);
			const config = configs.getConfig(absolutePath);

			/*
			 * Optimization: We need to track when patterns are left unmatched
			 * and so we use `unmatchedPatterns` to do that. There is a bit of
			 * complexity here because the same file can be matched by more than
			 * one pattern. So, when we start, we actually need to test every
			 * pattern against every file. Once we know there are no remaining
			 * unmatched patterns, then we can switch to just looking for the
			 * first matching pattern for improved speed.
			 */
			const matchesPattern =
				unmatchedPatterns.size > 0
					? matchers.reduce((previousValue, matcher) => {
							const pathMatches = matcher.match(entry.path);

							/*
							 * We updated the unmatched patterns set only if the path
							 * matches and the file has a config. If the file has no
							 * config, that means there wasn't a match for the
							 * pattern so it should not be removed.
							 *
							 * Performance note: `getConfig()` aggressively caches
							 * results so there is no performance penalty for calling
							 * it multiple times with the same argument.
							 */
							if (pathMatches && config) {
								unmatchedPatterns.delete(matcher.pattern);
							}

							return pathMatches || previousValue;
						}, false)
					: matchers.some(matcher => matcher.match(entry.path));

			return matchesPattern && config !== void 0;
		},
	});

	const filePaths = [];

	if (await hfs.isDirectory(basePath)) {
		for await (const entry of walk) {
			filePaths.push(path.resolve(basePath, entry.path));
		}
	}

	// now check to see if we have any unmatched patterns
	if (errorOnUnmatchedPattern && unmatchedPatterns.size > 0) {
		throw new UnmatchedSearchPatternsError({
			basePath,
			unmatchedPatterns: [...unmatchedPatterns].map(pattern =>
				relativeToPatterns.get(pattern),
			),
			patterns,
			rawPatterns,
		});
	}

	return filePaths;
}
Searches a directory looking for matching glob patterns. This uses
the config array's logic to determine if a directory or file should
be ignored, so it is consistent with how ignoring works throughout
ESLint.
@param {Object} options The options for this function.
@param {string} options.basePath The directory to search.
@param {Array<string>} options.patterns An array of absolute path glob patterns
     to match.
@param {Array<string>} options.rawPatterns An array of glob patterns
     as the user inputted them. Used for errors.
@param {ConfigLoader|LegacyConfigLoader} options.configLoader The config array to use for
     determining what to ignore.
@param {boolean} options.errorOnUnmatchedPattern Determines if an error
     should be thrown when a pattern is unmatched.
@returns {Promise<Array<string>>} An array of matching file paths
     or an empty array if there are no matches.
@throws {UnmatchedSearchPatternsError} If there is a pattern that doesn't
     match any files.