|
|
|
/**
|
|
|
|
* @fileoverview Responsible for loading ignore config files and managing ignore patterns
|
|
|
|
* @author Jonathan Rajavuori
|
|
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// Requirements
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
var lodash = require("lodash"),
|
|
|
|
fs = require("fs"),
|
|
|
|
path = require("path"),
|
|
|
|
debug = require("debug"),
|
|
|
|
ignore = require("ignore");
|
|
|
|
|
|
|
|
debug = debug("eslint:ignored-paths");
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// Constants
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
var ESLINT_IGNORE_FILENAME = ".eslintignore";
|
|
|
|
var DEFAULT_IGNORE_PATTERNS = [
|
|
|
|
"/node_modules/",
|
|
|
|
"/bower_components/"
|
|
|
|
];
|
|
|
|
var DEFAULT_OPTIONS = {
|
|
|
|
dotfiles: false,
|
|
|
|
cwd: process.cwd()
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// Helpers
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Find an ignore file in the current directory.
|
|
|
|
* @param {stirng} cwd Current working directory
|
|
|
|
* @returns {string} Path of ignore file or an empty string.
|
|
|
|
*/
|
|
|
|
function findIgnoreFile(cwd) {
|
|
|
|
cwd = cwd || DEFAULT_OPTIONS.cwd;
|
|
|
|
|
|
|
|
var ignoreFilePath = path.resolve(cwd, ESLINT_IGNORE_FILENAME);
|
|
|
|
return fs.existsSync(ignoreFilePath) ? ignoreFilePath : "";
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Replace Windows with Unix style paths and remove ./ prefix
|
|
|
|
* @param {string} filepath Path to normalize
|
|
|
|
* @returns {string} Normalized filepath
|
|
|
|
*/
|
|
|
|
function normalizeFilepath(filepath) {
|
|
|
|
filepath = filepath.replace(/\\/g, "/");
|
|
|
|
filepath = filepath.replace(/^\.\//, "");
|
|
|
|
return filepath;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove a prefix from a filepath
|
|
|
|
* @param {string} filepath Path to remove the prefix from
|
|
|
|
* @param {string} prefix Prefix to remove from filepath
|
|
|
|
* @returns {string} Normalized filepath
|
|
|
|
*/
|
|
|
|
function removePrefixFromFilepath(filepath, prefix) {
|
|
|
|
prefix += "/";
|
|
|
|
if (filepath.indexOf(prefix) === 0) {
|
|
|
|
filepath = filepath.substr(prefix.length);
|
|
|
|
}
|
|
|
|
return filepath;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Resolves a filepath
|
|
|
|
* @param {string} filepath Path resolve
|
|
|
|
* @param {string} baseDir Base directory to resolve the filepath from
|
|
|
|
* @returns {string} Resolved filepath
|
|
|
|
*/
|
|
|
|
function resolveFilepath(filepath, baseDir) {
|
|
|
|
if (baseDir) {
|
|
|
|
var base = normalizeFilepath(path.resolve(baseDir));
|
|
|
|
filepath = removePrefixFromFilepath(filepath, base);
|
|
|
|
filepath = removePrefixFromFilepath(filepath, fs.realpathSync(base));
|
|
|
|
}
|
|
|
|
filepath.replace(/^\//, "");
|
|
|
|
return filepath;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Normalize and resolve a filepath relative to a given base directory
|
|
|
|
* @param {string} filepath Path resolve
|
|
|
|
* @param {string} baseDir Base directory to resolve the filepath from
|
|
|
|
* @returns {string} Normalized and resolved filepath
|
|
|
|
*/
|
|
|
|
function normalizeAndResolveFilepath(filepath, baseDir) {
|
|
|
|
filepath = normalizeFilepath(filepath);
|
|
|
|
return resolveFilepath(filepath, baseDir);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Merge options with defaults
|
|
|
|
* @param {object} options Options to merge with DEFAULT_OPTIONS constant
|
|
|
|
* @returns {object} Merged options
|
|
|
|
*/
|
|
|
|
function mergeDefaultOptions(options) {
|
|
|
|
options = (options || {});
|
|
|
|
return lodash.assign({}, DEFAULT_OPTIONS, options);
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// Public Interface
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
/**
|
|
|
|
* IgnoredPaths
|
|
|
|
* @constructor
|
|
|
|
* @class IgnoredPaths
|
|
|
|
* @param {Object} options object containing 'ignore', 'ignorePath' and 'patterns' properties
|
|
|
|
*/
|
|
|
|
function IgnoredPaths(options) {
|
|
|
|
|
|
|
|
options = mergeDefaultOptions(options);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* add pattern to node-ignore instance
|
|
|
|
* @param {object} ig, instance of node-ignore
|
|
|
|
* @param {string} pattern, pattern do add to ig
|
|
|
|
* @returns {array} raw ignore rules
|
|
|
|
*/
|
|
|
|
function addPattern(ig, pattern) {
|
|
|
|
return ig.addPattern(pattern);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* add ignore file to node-ignore instance
|
|
|
|
* @param {object} ig, instance of node-ignore
|
|
|
|
* @param {string} filepath, file to add to ig
|
|
|
|
* @returns {array} raw ignore rules
|
|
|
|
*/
|
|
|
|
function addIgnoreFile(ig, filepath) {
|
|
|
|
return ig.addIgnoreFile(filepath);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.defaultPatterns = DEFAULT_IGNORE_PATTERNS.concat(options.patterns || []);
|
|
|
|
this.baseDir = ".";
|
|
|
|
|
|
|
|
this.ig = {
|
|
|
|
custom: new ignore.Ignore({
|
|
|
|
twoGlobstars: true,
|
|
|
|
ignore: []
|
|
|
|
}),
|
|
|
|
default: new ignore.Ignore({
|
|
|
|
twoGlobstars: true,
|
|
|
|
ignore: []
|
|
|
|
})
|
|
|
|
};
|
|
|
|
|
|
|
|
if (options.dotfiles !== true) {
|
|
|
|
addPattern(this.ig.default, ".*");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.ignore !== false) {
|
|
|
|
|
|
|
|
addPattern(this.ig.default, this.defaultPatterns);
|
|
|
|
|
|
|
|
var ignorePath;
|
|
|
|
|
|
|
|
if (options.ignorePattern) {
|
|
|
|
addPattern(this.ig.custom, options.ignorePattern);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.ignorePath) {
|
|
|
|
debug("Using specific ignore file");
|
|
|
|
|
|
|
|
try {
|
|
|
|
fs.statSync(options.ignorePath);
|
|
|
|
ignorePath = options.ignorePath;
|
|
|
|
} catch (e) {
|
|
|
|
e.message = "Cannot read ignore file: " + options.ignorePath + "\nError: " + e.message;
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
debug("Looking for ignore file in " + options.cwd);
|
|
|
|
ignorePath = findIgnoreFile(options.cwd);
|
|
|
|
|
|
|
|
try {
|
|
|
|
fs.statSync(ignorePath);
|
|
|
|
debug("Loaded ignore file " + ignorePath);
|
|
|
|
} catch (e) {
|
|
|
|
debug("Could not find ignore file in cwd");
|
|
|
|
this.options = options;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ignorePath) {
|
|
|
|
debug("Adding " + ignorePath);
|
|
|
|
this.baseDir = path.dirname(ignorePath);
|
|
|
|
addIgnoreFile(this.ig.custom, ignorePath);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
this.options = options;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Determine whether a file path is included in the default or custom ignore patterns
|
|
|
|
* @param {string} filepath Path to check
|
|
|
|
* @param {string} [category=null] check 'default', 'custom' or both (null)
|
|
|
|
* @returns {boolean} true if the file path matches one or more patterns, false otherwise
|
|
|
|
*/
|
|
|
|
IgnoredPaths.prototype.contains = function(filepath, category) {
|
|
|
|
|
|
|
|
var result = false;
|
|
|
|
filepath = normalizeAndResolveFilepath(filepath, this.baseDir);
|
|
|
|
|
|
|
|
if ((typeof category === "undefined") || (category === "default")) {
|
|
|
|
result = result || (this.ig.default.filter([filepath]).length === 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((typeof category === "undefined") || (category === "custom")) {
|
|
|
|
result = result || (this.ig.custom.filter([filepath]).length === 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
module.exports = IgnoredPaths;
|