diff options
Diffstat (limited to 'tools/eslint/lib/file-finder.js')
-rw-r--r-- | tools/eslint/lib/file-finder.js | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/tools/eslint/lib/file-finder.js b/tools/eslint/lib/file-finder.js new file mode 100644 index 0000000000..3cdf9150fd --- /dev/null +++ b/tools/eslint/lib/file-finder.js @@ -0,0 +1,167 @@ +/** + * @fileoverview Util class to find config files. + * @author Aliaksei Shytkin + * @copyright 2014 Michael McLaughlin. All rights reserved. + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var 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 []; + } +} + +//------------------------------------------------------------------------------ +// API +//------------------------------------------------------------------------------ + +/** + * FileFinder + * @constructor + * @param {...string} arguments The basename(s) of the file(s) to find. + */ +function FileFinder() { + this.fileNames = Array.prototype.slice.call(arguments); + this.cache = {}; +} + +/** + * Find one instance of a specified file name in directory or in a parent directory. + * Cache the results. + * Does not check if a matching directory entry is a file, and intentionally + * only searches for the first file name in this.fileNames. + * Is currently used by lib/ignored_paths.js to find an .eslintignore file. + * @param {string} directory The directory to start the search from. + * @returns {string} Path of the file found, or an empty string if not found. + */ +FileFinder.prototype.findInDirectoryOrParents = function (directory) { + var cache = this.cache, + child, + dirs, + filePath, + i, + name, + searched; + + if (!directory) { + directory = process.cwd(); + } + + if (cache.hasOwnProperty(directory)) { + return cache[directory]; + } + + dirs = []; + searched = 0; + name = this.fileNames[0]; + + while (directory !== child) { + dirs[searched++] = directory; + + if (getDirectoryEntries(directory).indexOf(name) !== -1) { + filePath = path.resolve(directory, name); + break; + } + + child = directory; + + // Assign parent directory to directory. + directory = path.dirname(directory); + } + + for (i = 0; i < searched; i++) { + cache[dirs[i]] = filePath; + } + + return filePath || String(); +}; + +/** + * 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} directory The directory to start the search from. + * @returns {string[]} The file paths found. + */ +FileFinder.prototype.findAllInDirectoryAndParents = function (directory) { + var cache = this.cache, + child, + dirs, + name, + fileNames, + fileNamesCount, + filePath, + i, + j, + searched; + + if (!directory) { + directory = process.cwd(); + } + + if (cache.hasOwnProperty(directory)) { + return cache[directory]; + } + + dirs = []; + searched = 0; + fileNames = this.fileNames; + fileNamesCount = fileNames.length; + + do { + dirs[searched++] = directory; + cache[directory] = []; + + for (i = 0; i < fileNamesCount; i++) { + name = fileNames[i]; + + if (getDirectoryEntries(directory).indexOf(name) !== -1) { + filePath = path.resolve(directory, name); + + // Add the file path to the cache of each directory searched. + for (j = 0; j < searched; j++) { + cache[dirs[j]].push(filePath); + } + } + } + child = directory; + + // Assign parent directory to directory. + directory = path.dirname(directory); + + if (directory === child) { + return cache[dirs[0]]; + } + } while (!cache.hasOwnProperty(directory)); + + // Add what has been cached previously to the cache of each directory searched. + for (i = 0; i < searched; i++) { + dirs.push.apply(cache[dirs[i]], cache[directory]); + } + + return cache[dirs[0]]; +}; + +module.exports = FileFinder; |