async lintFiles(patterns) {
		let normalizedPatterns = patterns;
		const {
			cacheFilePath,
			lintResultCache,
			linter,
			options: eslintOptions,
		} = privateMembers.get(this);

		/*
		 * Special cases:
		 * 1. `patterns` is an empty string
		 * 2. `patterns` is an empty array
		 *
		 * In both cases, we use the cwd as the directory to lint.
		 */
		if (
			patterns === "" ||
			(Array.isArray(patterns) && patterns.length === 0)
		) {
			/*
			 * Special case: If `passOnNoPatterns` is true, then we just exit
			 * without doing any work.
			 */
			if (eslintOptions.passOnNoPatterns) {
				return [];
			}

			normalizedPatterns = ["."];
		} else {
			if (
				!isNonEmptyString(patterns) &&
				!isArrayOfNonEmptyString(patterns)
			) {
				throw new Error(
					"'patterns' must be a non-empty string or an array of non-empty strings",
				);
			}

			if (typeof patterns === "string") {
				normalizedPatterns = [patterns];
			}
		}

		debug(`Using file patterns: ${normalizedPatterns}`);

		const {
			allowInlineConfig,
			cache,
			cwd,
			fix,
			fixTypes,
			ruleFilter,
			stats,
			globInputPaths,
			errorOnUnmatchedPattern,
			warnIgnored,
		} = eslintOptions;
		const startTime = Date.now();
		const fixTypesSet = fixTypes ? new Set(fixTypes) : null;

		// Delete cache file; should this be done here?
		if (!cache && cacheFilePath) {
			debug(`Deleting cache file at ${cacheFilePath}`);

			try {
				if (existsSync(cacheFilePath)) {
					await fs.unlink(cacheFilePath);
				}
			} catch (error) {
				if (existsSync(cacheFilePath)) {
					throw error;
				}
			}
		}

		const filePaths = await findFiles({
			patterns: normalizedPatterns,
			cwd,
			globInputPaths,
			configLoader: this.#configLoader,
			errorOnUnmatchedPattern,
		});
		const controller = new AbortController();
		const retryCodes = new Set(["ENFILE", "EMFILE"]);
		const retrier = new Retrier(error => retryCodes.has(error.code), {
			concurrency: 100,
		});

		debug(
			`${filePaths.length} files found in: ${Date.now() - startTime}ms`,
		);

		/*
		 * Because we need to process multiple files, including reading from disk,
		 * it is most efficient to start by reading each file via promises so that
		 * they can be done in parallel. Then, we can lint the returned text. This
		 * ensures we are waiting the minimum amount of time in between lints.
		 */
		const results = await Promise.all(
			filePaths.map(async filePath => {
				const configs =
					await this.#configLoader.loadConfigArrayForFile(filePath);
				const config = configs.getConfig(filePath);

				/*
				 * If a filename was entered that cannot be matched
				 * to a config, then notify the user.
				 */
				if (!config) {
					if (warnIgnored) {
						const configStatus = configs.getConfigStatus(filePath);

						return createIgnoreResult(filePath, cwd, configStatus);
					}

					return void 0;
				}

				// Skip if there is cached result.
				if (lintResultCache) {
					const cachedResult = lintResultCache.getCachedLintResults(
						filePath,
						config,
					);

					if (cachedResult) {
						const hadMessages =
							cachedResult.messages &&
							cachedResult.messages.length > 0;

						if (hadMessages && fix) {
							debug(
								`Reprocessing cached file to allow autofix: ${filePath}`,
							);
						} else {
							debug(
								`Skipping file since it hasn't changed: ${filePath}`,
							);
							return cachedResult;
						}
					}
				}

				// set up fixer for fixTypes if necessary
				const fixer = getFixerForFixTypes(fix, fixTypesSet, config);

				return retrier
					.retry(
						() =>
							fs
								.readFile(filePath, {
									encoding: "utf8",
									signal: controller.signal,
								})
								.then(text => {
									// fail immediately if an error occurred in another file
									controller.signal.throwIfAborted();

									// do the linting
									const result = verifyText({
										text,
										filePath,
										configs,
										cwd,
										fix: fixer,
										allowInlineConfig,
										ruleFilter,
										stats,
										linter,
									});

									/*
									 * Store the lint result in the LintResultCache.
									 * NOTE: The LintResultCache will remove the file source and any
									 * other properties that are difficult to serialize, and will
									 * hydrate those properties back in on future lint runs.
									 */
									if (lintResultCache) {
										lintResultCache.setCachedLintResults(
											filePath,
											config,
											result,
										);
									}

									return result;
								}),
						{ signal: controller.signal },
					)
					.catch(error => {
						controller.abort(error);
						throw error;
					});
			}),
		);

		// Persist the cache to disk.
		if (lintResultCache) {
			lintResultCache.reconcile();
		}

		const finalResults = results.filter(result => !!result);

		return processLintReport(this, {
			results: finalResults,
		});
	}
Executes the current configuration on an array of file and directory names.
@param {string|string[]} patterns An array of file and directory names.
@returns {Promise<LintResult[]>} The results of linting the file patterns given.