| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 | /** * @fileoverview Util class to find config files. * @author Aliaksei Shytkin */"use strict";//------------------------------------------------------------------------------// Requirements//------------------------------------------------------------------------------const fs = require("fs"),    path = require("path");//------------------------------------------------------------------------------// Helpers//------------------------------------------------------------------------------/** * Get the entries for a directory. Including a try-catch may be detrimental to * function performance, so move it out here a separate function. * @param {string} directory The directory to search in. * @returns {string[]} The entries in the directory or an empty array on error. * @private */function getDirectoryEntries(directory) {    try {        return fs.readdirSync(directory);    } catch (ex) {        return [];    }}/** * Create a hash of filenames from a directory listing * @param {string[]} entries Array of directory entries. * @param {string} directory Path to a current directory. * @param {string[]} supportedConfigs List of support filenames. * @returns {Object} Hashmap of filenames */function normalizeDirectoryEntries(entries, directory, supportedConfigs) {    const fileHash = {};    entries.forEach(entry => {        if (supportedConfigs.indexOf(entry) >= 0) {            const resolvedEntry = path.resolve(directory, entry);            if (fs.statSync(resolvedEntry).isFile()) {                fileHash[entry] = resolvedEntry;            }        }    });    return fileHash;}//------------------------------------------------------------------------------// API//------------------------------------------------------------------------------/** * FileFinder class */class FileFinder {    /**     * @param {string[]} files The basename(s) of the file(s) to find.     * @param {stirng} cwd Current working directory     */    constructor(files, cwd) {        this.fileNames = Array.isArray(files) ? files : [files];        this.cwd = cwd || process.cwd();        this.cache = {};    }    /**     * Find all instances of files with the specified file names, in directory and     * parent directories. Cache the results.     * Does not check if a matching directory entry is a file.     * Searches for all the file names in this.fileNames.     * Is currently used by lib/config.js to find .eslintrc and package.json files.     * @param  {string} relativeDirectory The directory to start the search from.     * @returns {GeneratorFunction} to iterate the file paths found     */    *findAllInDirectoryAndParents(relativeDirectory) {        const cache = this.cache;        const initialDirectory = relativeDirectory            ? path.resolve(this.cwd, relativeDirectory)            : this.cwd;        if (cache.hasOwnProperty(initialDirectory)) {            yield* cache[initialDirectory];            return; // to avoid doing the normal loop afterwards        }        const dirs = [];        const fileNames = this.fileNames;        let searched = 0;        let directory = initialDirectory;        do {            dirs[searched++] = directory;            cache[directory] = [];            const filesMap = normalizeDirectoryEntries(getDirectoryEntries(directory), directory, fileNames);            if (Object.keys(filesMap).length) {                for (let k = 0; k < fileNames.length; k++) {                    if (filesMap[fileNames[k]]) {                        const filePath = filesMap[fileNames[k]];                        // Add the file path to the cache of each directory searched.                        for (let j = 0; j < searched; j++) {                            cache[dirs[j]].push(filePath);                        }                        yield filePath;                        break;                    }                }            }            const child = directory;            // Assign parent directory to directory.            directory = path.dirname(directory);            if (directory === child) {                return;            }        } while (!cache.hasOwnProperty(directory));        // Add what has been cached previously to the cache of each directory searched.        for (let i = 0; i < searched; i++) {            [].push.apply(cache[dirs[i]], cache[directory]);        }        yield* cache[dirs[0]];    }}module.exports = FileFinder;
 |