async function findFiles({
	patterns,
	globInputPaths,
	cwd,
	configLoader,
	errorOnUnmatchedPattern,
}) {
	const results = [];
	const missingPatterns = [];
	let globbyPatterns = [];
	let rawPatterns = [];
	const searches = new Map([
		[cwd, { patterns: globbyPatterns, rawPatterns: [] }],
	]);

	/*
	 * This part is a bit involved because we need to account for
	 * the different ways that the patterns can match directories.
	 * For each different way, we need to decide if we should look
	 * for a config file or just use the default config. (Directories
	 * without a config file always use the default config.)
	 *
	 * Here are the cases:
	 *
	 * 1. A directory is passed directly (e.g., "subdir"). In this case, we
	 * can assume that the user intends to lint this directory and we should
	 * not look for a config file in the parent directory, because the only
	 * reason to do that would be to ignore this directory (which we already
	 * know we don't want to do). Instead, we use the default config until we
	 * get to the directory that was passed, at which point we start looking
	 * for config files again.
	 *
	 * 2. A dot (".") or star ("*"). In this case, we want to read
	 * the config file in the current directory because the user is
	 * explicitly asking to lint the current directory. Note that "."
	 * will traverse into subdirectories while "*" will not.
	 *
	 * 3. A directory is passed in the form of "subdir/subsubdir".
	 * In this case, we don't want to look for a config file in the
	 * parent directory ("subdir"). We can skip looking for a config
	 * file until `entry.depth` is greater than 1 because there's no
	 * way that the pattern can match `entry.path` yet.
	 *
	 * 4. A directory glob pattern is passed (e.g., "subd*"). We want
	 * this case to act like case 2 because it's unclear whether or not
	 * any particular directory is meant to be traversed.
	 *
	 * 5. A recursive glob pattern is passed (e.g., "**"). We want this
	 * case to act like case 2.
	 */

	// check to see if we have explicit files and directories
	const filePaths = patterns.map(filePath => path.resolve(cwd, filePath));
	const stats = await Promise.all(
		filePaths.map(filePath => fsp.stat(filePath).catch(() => {})),
	);

	stats.forEach((stat, index) => {
		const filePath = filePaths[index];
		const pattern = normalizeToPosix(patterns[index]);

		if (stat) {
			// files are added directly to the list
			if (stat.isFile()) {
				results.push(filePath);
			}

			// directories need extensions attached
			if (stat.isDirectory()) {
				if (!searches.has(filePath)) {
					searches.set(filePath, { patterns: [], rawPatterns: [] });
				}
				({ patterns: globbyPatterns, rawPatterns } =
					searches.get(filePath));

				globbyPatterns.push(`${normalizeToPosix(filePath)}/**`);
				rawPatterns.push(pattern);
			}

			return;
		}

		// save patterns for later use based on whether globs are enabled
		if (globInputPaths && isGlobPattern(pattern)) {
			/*
			 * We are grouping patterns by their glob parent. This is done to
			 * make it easier to determine when a config file should be loaded.
			 */

			const basePath = path.resolve(cwd, globParent(pattern));

			if (!searches.has(basePath)) {
				searches.set(basePath, { patterns: [], rawPatterns: [] });
			}
			({ patterns: globbyPatterns, rawPatterns } =
				searches.get(basePath));

			globbyPatterns.push(filePath);
			rawPatterns.push(pattern);
		} else {
			missingPatterns.push(pattern);
		}
	});

	// there were patterns that didn't match anything, tell the user
	if (errorOnUnmatchedPattern && missingPatterns.length) {
		throw new NoFilesFoundError(missingPatterns[0], globInputPaths);
	}

	// now we are safe to do the search
	const globbyResults = await globMultiSearch({
		searches,
		configLoader,
		errorOnUnmatchedPattern,
	});

	return [...new Set([...results, ...globbyResults])];
}
Finds all files matching the options specified.
@param {Object} args The arguments objects.
@param {Array<string>} args.patterns An array of glob patterns.
@param {boolean} args.globInputPaths true to interpret glob patterns,
     false to not interpret glob patterns.
@param {string} args.cwd The current working directory to find from.
@param {ConfigLoader|LegacyConfigLoader} args.configLoader The config loeader for the current run.
@param {boolean} args.errorOnUnmatchedPattern Determines if an unmatched pattern
     should throw an error.
@returns {Promise<Array<string>>} The fully resolved file paths.
@throws {AllFilesIgnoredError} If there are no results due to an ignore pattern.
@throws {NoFilesFoundError} If no files matched the given patterns.