Repository: eslint/eslint
File: lib/eslint/eslint-helpers.js (JavaScript)

Code before:
 * @param {string} options.cwd The directory to search.
 * @param {Array<string>} options.patterns An array of glob patterns
 *      to match.
 * @param {FlatConfigArray} options.configs The config array to use for
 *      determining what to ignore.
 * @returns {Promise<Array<string>>} An array of matching file paths
 *      or an empty array if there are no matches.
 */
async function globSearch({ cwd, patterns, configs }) {

    if (patterns.length === 0) {
        return [];
    }

    const matchers = patterns.map(pattern => new minimatch.Minimatch(pattern));

    return (await doFsWalk(cwd, {

        deepFilter(entry) {
            return !configs.isDirectoryIgnored(entry.path);
        },

        entryFilter(entry) {

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

            const posixName = normalizeToPosix(path.relative(cwd, entry.path));
            const matchesPattern = matchers.some(matcher => {

                /*
                 * Patterns can either be relative, like `foo/bar` or
                 * absolute like `c:/foo/bar/**` and so we need to apply
                 * the match either against the relative or absolute filename,
                 * respectively.
                 */
                if (path.isAbsolute(matcher.pattern)) {
                    return matcher.match(entry.path);
                }

                return matcher.match(posixName);
            });

            return matchesPattern && !configs.isFileIgnored(entry.path);
        }
    })).map(entry => entry.path);

}


Review comment (suggestion):
`deepFilter` determines whether or not we descend into a directory. So, we want to cut off things like `node_modules` here to avoid the traversal.

Code after:
 * @param {Object} options The options for this function.
 * @param {string} options.cwd The directory to search.
 * @param {Array<string>} options.patterns An array of glob patterns
 *      to match.
 * @param {FlatConfigArray} options.configs The config array to use for
 *      determining what to ignore.
 * @returns {Promise<Array<string>>} An array of matching file paths
 *      or an empty array if there are no matches.
 */
async function globSearch({ cwd, patterns, configs }) {

    if (patterns.length === 0) {
        return [];
    }

    const matchers = patterns.map(pattern => {
        const patternToUse = path.isAbsolute(pattern)
            ? normalizeToPosix(path.relative(cwd, pattern))
            : pattern;

        return new minimatch.Minimatch(patternToUse);
    });

    return (await doFsWalk(cwd, {

        deepFilter(entry) {
            const relativePath = normalizeToPosix(path.relative(cwd, entry.path));
            const matchesPattern = matchers.some(matcher => matcher.match(relativePath, true));

            return matchesPattern && !configs.isDirectoryIgnored(entry.path);
        },
        entryFilter(entry) {
            const relativePath = normalizeToPosix(path.relative(cwd, entry.path));

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

            const matchesPattern = matchers.some(matcher => matcher.match(relativePath));

            return matchesPattern && !configs.isFileIgnored(entry.path);
        }
    })).map(entry => entry.path);

}

/**
 * Determines if a given glob pattern will return any results.
 * Used primarily to help with useful error messages.
 * @param {Object} options The options for the function.