Skip to content

Commit

Permalink
Merge pull request #4657 from eslint/issue-4472
Browse files Browse the repository at this point in the history
Update: Add cwd option for cli-engine (fixes #4472)
  • Loading branch information
nzakas committed Dec 13, 2015
2 parents d235f33 + eb1ef88 commit 5858786
Show file tree
Hide file tree
Showing 12 changed files with 142 additions and 78 deletions.
3 changes: 2 additions & 1 deletion docs/developer-guide/nodejs-api.md
Expand Up @@ -133,7 +133,8 @@ The `CLIEngine` is a constructor, and you can create a new instance by passing i
* `parser` - Specify the parser to be used (default: `espree`). Corresponds to `--parser`.
* `cache` - Operate only on changed files (default: `false`). Corresponds to `--cache`.
* `cacheFile` - Name of the file where the cache will be stored (default: `.eslintcache`). Corresponds to `--cache-file`. Deprecated: use `cacheLocation` instead.
* `cacheLocation` - Name of the file or directory where the cache will be stored (default: `.eslintcache`). Correspond to `--cache-location`
* `cacheLocation` - Name of the file or directory where the cache will be stored (default: `.eslintcache`). Correspond to `--cache-location`.
* `cwd` - Path to a directory that should be considered as the current working directory.

For example:

Expand Down
17 changes: 10 additions & 7 deletions lib/cli-engine.js
Expand Up @@ -96,7 +96,8 @@ var defaultOptions = {
cacheLocation: "",
cacheFile: ".eslintcache",
fix: false,
allowInlineConfig: true
allowInlineConfig: true,
cwd: process.cwd()
},
loadedPlugins = Object.create(null);

Expand Down Expand Up @@ -325,22 +326,23 @@ function md5Hash(str) {
* if cacheFile points to a file or looks like a file then in will just use that file
*
* @param {string} cacheFile The name of file to be used to store the cache
* @param {string} cwd Current working directory
* @returns {string} the resolved path to the cache file
*/
function getCacheFile(cacheFile) {
function getCacheFile(cacheFile, cwd) {
// make sure the path separators are normalized for the environment/os
// keeping the trailing path separator if present
cacheFile = path.normalize(cacheFile);

var resolvedCacheFile = path.resolve(cacheFile);
var resolvedCacheFile = path.resolve(cwd, cacheFile);
var looksLikeADirectory = cacheFile[cacheFile.length - 1 ] === path.sep;

/**
* return the name for the cache file in case the provided parameter is a directory
* @returns {string} the resolved path to the cacheFile
*/
function getCacheFileForDirectory() {
return path.join(resolvedCacheFile, ".cache_" + md5Hash(process.cwd()));
return path.join(resolvedCacheFile, ".cache_" + md5Hash(cwd));
}

var fileStats;
Expand Down Expand Up @@ -396,7 +398,7 @@ function CLIEngine(options) {
this.options = assign(Object.create(defaultOptions), options || {});


var cacheFile = getCacheFile(this.options.cacheLocation || this.options.cacheFile);
var cacheFile = getCacheFile(this.options.cacheLocation || this.options.cacheFile, this.options.cwd);

/**
* cache used to not operate on files that haven't changed since last successful
Expand All @@ -411,9 +413,10 @@ function CLIEngine(options) {

// load in additional rules
if (this.options.rulePaths) {
var cwd = this.options.cwd;
this.options.rulePaths.forEach(function(rulesdir) {
debug("Loading rules from " + rulesdir);
rules.load(rulesdir);
rules.load(rulesdir, cwd);
});
}

Expand Down Expand Up @@ -444,7 +447,7 @@ CLIEngine.getFormatter = function(format) {

// if there's a slash, then it's a file
if (format.indexOf("/") > -1) {
formatterPath = path.resolve(process.cwd(), format);
formatterPath = path.resolve(this.options.cwd, format);
} else {
formatterPath = "./formatters/" + format;
}
Expand Down
9 changes: 4 additions & 5 deletions lib/config.js
Expand Up @@ -155,7 +155,7 @@ function getLocalConfig(thisConfig, directory) {
localConfigFiles = thisConfig.findLocalConfigFiles(directory),
numFiles = localConfigFiles.length,
rootPath,
projectConfigPath = ConfigFile.getFilenameForDirectory(process.cwd());
projectConfigPath = ConfigFile.getFilenameForDirectory(thisConfig.options.cwd);

for (i = 0; i < numFiles; i++) {

Expand Down Expand Up @@ -203,7 +203,6 @@ function getLocalConfig(thisConfig, directory) {
* @constructor
* @class Config
* @param {Object} options Options to be passed in
* @param {string} [cwd] current working directory. Defaults to process.cwd()
*/
function Config(options) {
var useConfig;
Expand Down Expand Up @@ -239,7 +238,7 @@ function Config(options) {
if (isResolvable(useConfig) || isResolvable("eslint-config-" + useConfig) || useConfig.charAt(0) === "@") {
this.useSpecificConfig = loadConfig(useConfig);
} else {
this.useSpecificConfig = loadConfig(path.resolve(process.cwd(), useConfig));
this.useSpecificConfig = loadConfig(path.resolve(this.options.cwd, useConfig));
}
}
}
Expand All @@ -253,7 +252,7 @@ function Config(options) {
Config.prototype.getConfig = function(filePath) {
var config,
userConfig,
directory = filePath ? path.dirname(filePath) : process.cwd(),
directory = filePath ? path.dirname(filePath) : this.options.cwd,
pluginConfig;

debug("Constructing config for " + (filePath ? filePath : "text"));
Expand Down Expand Up @@ -326,7 +325,7 @@ Config.prototype.getConfig = function(filePath) {
Config.prototype.findLocalConfigFiles = function(directory) {

if (!this.localConfigFinder) {
this.localConfigFinder = new FileFinder(ConfigFile.CONFIG_FILES);
this.localConfigFinder = new FileFinder(ConfigFile.CONFIG_FILES, this.options.cwd);
}

return this.localConfigFinder.findAllInDirectoryAndParents(directory);
Expand Down
8 changes: 5 additions & 3 deletions lib/file-finder.js
Expand Up @@ -41,9 +41,11 @@ function getDirectoryEntries(directory) {
* FileFinder
* @constructor
* @param {string[]} files The basename(s) of the file(s) to find.
* @param {stirng} cwd Current working directory
*/
function FileFinder(files) {
function FileFinder(files, cwd) {
this.fileNames = Array.isArray(files) ? files : [files];
this.cwd = cwd;
this.cache = {};
}

Expand Down Expand Up @@ -86,7 +88,7 @@ FileFinder.prototype.findInDirectoryOrParents = function(directory) {
searched;

if (!directory) {
directory = process.cwd();
directory = this.cwd;
}

if (cache.hasOwnProperty(directory)) {
Expand Down Expand Up @@ -144,7 +146,7 @@ FileFinder.prototype.findAllInDirectoryAndParents = function(directory) {
searched;

if (!directory) {
directory = process.cwd();
directory = this.cwd;
}

if (cache.hasOwnProperty(directory)) {
Expand Down
7 changes: 4 additions & 3 deletions lib/ignored-paths.js
Expand Up @@ -61,11 +61,12 @@ var ignoreFileFinder;

/**
* Find an ignore file in the current directory or a parent directory.
* @param {string} cwd Current working directory
* @returns {string} Path of ignore file or an empty string.
*/
function findIgnoreFile() {
function findIgnoreFile(cwd) {
if (!ignoreFileFinder) {
ignoreFileFinder = new FileFinder(ESLINT_IGNORE_FILENAME);
ignoreFileFinder = new FileFinder(ESLINT_IGNORE_FILENAME, cwd);
}

return ignoreFileFinder.findInDirectoryOrParents();
Expand Down Expand Up @@ -97,7 +98,7 @@ IgnoredPaths.load = function(options) {
options = options || {};

if (options.ignore) {
patterns = loadIgnoreFile(options.ignorePath || findIgnoreFile());
patterns = loadIgnoreFile(options.ignorePath || findIgnoreFile(options.cwd));
} else {
patterns = [];
}
Expand Down
7 changes: 4 additions & 3 deletions lib/load-rules.js
Expand Up @@ -18,14 +18,15 @@ var fs = require("fs"),

/**
* Load all rule modules from specified directory.
* @param {String} [rulesDir] Path to rules directory, may be relative. Defaults to `lib/rules`.
* @param {string} [rulesDir] Path to rules directory, may be relative. Defaults to `lib/rules`.
* @param {string} cwd Current working directory
* @returns {Object} Loaded rule modules by rule ids (file names).
*/
module.exports = function(rulesDir) {
module.exports = function(rulesDir, cwd) {
if (!rulesDir) {
rulesDir = path.join(__dirname, "rules");
} else {
rulesDir = path.resolve(process.cwd(), rulesDir);
rulesDir = path.resolve(cwd, rulesDir);
}

var rules = Object.create(null);
Expand Down
13 changes: 7 additions & 6 deletions lib/rules.js
Expand Up @@ -23,7 +23,7 @@ var rules = Object.create(null);

/**
* Registers a rule module for rule id in storage.
* @param {String} ruleId Rule id (file name).
* @param {string} ruleId Rule id (file name).
* @param {Function} ruleModule Rule handler.
* @returns {void}
*/
Expand All @@ -33,11 +33,12 @@ function define(ruleId, ruleModule) {

/**
* Loads and registers all rules from passed rules directory.
* @param {String} [rulesDir] Path to rules directory, may be relative. Defaults to `lib/rules`.
* @param {string} [rulesDir] Path to rules directory, may be relative. Defaults to `lib/rules`.
* @param {string} cwd Current working directory
* @returns {void}
*/
function load(rulesDir) {
var newRules = loadRules(rulesDir);
function load(rulesDir, cwd) {
var newRules = loadRules(rulesDir, cwd);
Object.keys(newRules).forEach(function(ruleId) {
define(ruleId, newRules[ruleId]);
});
Expand All @@ -46,7 +47,7 @@ function load(rulesDir) {
/**
* Registers all given rules of a plugin.
* @param {Object} pluginRules A key/value map of rule definitions.
* @param {String} pluginName The name of the plugin without prefix (`eslint-plugin-`).
* @param {string} pluginName The name of the plugin without prefix (`eslint-plugin-`).
* @returns {void}
*/
function importPlugin(pluginRules, pluginName) {
Expand All @@ -60,7 +61,7 @@ function importPlugin(pluginRules, pluginName) {

/**
* Access rule handler by id (file name).
* @param {String} ruleId Rule id (file name).
* @param {string} ruleId Rule id (file name).
* @returns {Function} Rule handler.
*/
function get(ruleId) {
Expand Down
41 changes: 40 additions & 1 deletion tests/lib/cli-engine.js
Expand Up @@ -570,7 +570,6 @@ describe("CLIEngine", function() {
assert.equal(report.results[0].messages.length, 0);
});


it("should give a warning when loading a custom rule that doesn't exist", function() {

engine = new CLIEngine({
Expand Down Expand Up @@ -621,6 +620,25 @@ describe("CLIEngine", function() {
assert.equal(report.results[0].messages[0].severity, 1);
});

it("should load custom rule from the provided cwd", function() {
var cwd = path.resolve(getFixturePath("rules"));
engine = new CLIEngine({
ignore: false,
cwd: cwd,
rulePaths: ["./"],
configFile: "eslint.json"
});

var filePath = fs.realpathSync(getFixturePath("rules", "test", "test-custom-rule.js"));

var report = engine.executeOnFiles([filePath]);
assert.equal(report.results.length, 1);
assert.equal(report.results[0].filePath, filePath);
assert.equal(report.results[0].messages.length, 2);
assert.equal(report.results[0].messages[0].ruleId, "custom-rule");
assert.equal(report.results[0].messages[0].severity, 1);
});

it("should return messages when multiple custom rules match a file", function() {

engine = new CLIEngine({
Expand Down Expand Up @@ -1295,6 +1313,27 @@ describe("CLIEngine", function() {
sandbox.restore();
});

it("should create the cache file inside cwd when no cacheLocation provided", function() {
var cwd = path.resolve(getFixturePath("cli-engine"));

engine = new CLIEngine({
useEslintrc: false,
cache: true,
cwd: cwd,
rules: {
"no-console": 0
},
extensions: ["js"],
ignore: false
});

var file = getFixturePath("cli-engine", "console.js");

engine.executeOnFiles([file]);

assert.isTrue(fs.existsSync(path.resolve(cwd, ".eslintcache")), "the cache for eslint was created at provided cwd");
});

it("should invalidate the cache if the configuration changed between executions", function() {
assert.isFalse(fs.existsSync(path.resolve(".eslintcache")), "the cache for eslint does not exist");

Expand Down

0 comments on commit 5858786

Please sign in to comment.