summaryrefslogtreecommitdiff
path: root/tools/eslint/lib/config.js
diff options
context:
space:
mode:
authorMichaƫl Zasso <mic.besace@gmail.com>2016-01-12 20:50:19 +0100
committerRoman Reiss <me@silverwind.io>2016-01-13 23:15:39 +0100
commit2d441493a4a46a511ba1bdf93e442c3288fbe92d (patch)
treec649c3aa100a57ff38ed267e3a5e5bba7ac8d961 /tools/eslint/lib/config.js
parented55169834a3ce16a271def9630c858626ded34d (diff)
downloadnode-new-2d441493a4a46a511ba1bdf93e442c3288fbe92d.tar.gz
tools: update eslint to v1.10.3
PR-URL: https://github.com/nodejs/io.js/pull/2286 Reviewed-By: Roman Reiss <me@silverwind.io>
Diffstat (limited to 'tools/eslint/lib/config.js')
-rw-r--r--tools/eslint/lib/config.js266
1 files changed, 87 insertions, 179 deletions
diff --git a/tools/eslint/lib/config.js b/tools/eslint/lib/config.js
index a4f8d0e87c..3eb174e72d 100644
--- a/tools/eslint/lib/config.js
+++ b/tools/eslint/lib/config.js
@@ -2,8 +2,9 @@
* @fileoverview Responsible for loading config files
* @author Seth McLaughlin
* @copyright 2014 Nicholas C. Zakas. All rights reserved.
- * @copyright 2013 Seth McLaughlin. All rights reserved.
* @copyright 2014 Michael McLaughlin. All rights reserved.
+ * @copyright 2013 Seth McLaughlin. All rights reserved.
+ * See LICENSE in root directory for full license.
*/
"use strict";
@@ -11,27 +12,22 @@
// Requirements
//------------------------------------------------------------------------------
-var fs = require("fs"),
- path = require("path"),
- environments = require("../conf/environments"),
+var path = require("path"),
+ ConfigOps = require("./config/config-ops"),
+ ConfigFile = require("./config/config-file"),
util = require("./util"),
FileFinder = require("./file-finder"),
- stripComments = require("strip-json-comments"),
- assign = require("object-assign"),
debug = require("debug"),
- yaml = require("js-yaml"),
userHome = require("user-home"),
- isAbsolutePath = require("path-is-absolute"),
- validator = require("./config-validator");
+ isResolvable = require("is-resolvable"),
+ pathIsInside = require("path-is-inside");
//------------------------------------------------------------------------------
// Constants
//------------------------------------------------------------------------------
-var LOCAL_CONFIG_FILENAME = ".eslintrc",
- PACKAGE_CONFIG_FILENAME = "package.json",
- PACKAGE_CONFIG_FIELD_NAME = "eslintConfig",
- PERSONAL_CONFIG_PATH = userHome ? path.join(userHome, LOCAL_CONFIG_FILENAME) : null;
+var PACKAGE_CONFIG_FILENAME = "package.json",
+ PERSONAL_CONFIG_DIR = userHome || null;
//------------------------------------------------------------------------------
// Private
@@ -46,97 +42,40 @@ var loadedPlugins = Object.create(null);
debug = debug("eslint:config");
/**
- * Determines if a given string represents a filepath or not using the same
- * conventions as require(), meaning that the first character must be nonalphanumeric
- * and not the @ sign which is used for scoped packages to be considered a file path.
- * @param {string} filePath The string to check.
- * @returns {boolean} True if it's a filepath, false if not.
+ * Check if item is an javascript object
+ * @param {*} item object to check for
+ * @returns {boolean} True if its an object
* @private
*/
-function isFilePath(filePath) {
- return isAbsolutePath(filePath) || !/\w|@/.test(filePath[0]);
+function isObject(item) {
+ return typeof item === "object" && !Array.isArray(item) && item !== null;
}
/**
* Load and parse a JSON config object from a file.
- * @param {string} filePath the path to the JSON config file
+ * @param {string|Object} configToLoad the path to the JSON config file or the config object itself.
* @returns {Object} the parsed config object (empty object if there was a parse error)
* @private
*/
-function loadConfig(filePath) {
- var config = {};
+function loadConfig(configToLoad) {
+ var config = {},
+ filePath = "";
- if (filePath) {
+ if (configToLoad) {
- if (isFilePath(filePath)) {
- try {
- config = yaml.safeLoad(stripComments(fs.readFileSync(filePath, "utf8"))) || {};
- } catch (e) {
- debug("Error reading YAML file: " + filePath);
- e.message = "Cannot read config file: " + filePath + "\nError: " + e.message;
- throw e;
- }
+ if (isObject(configToLoad)) {
+ config = configToLoad;
- if (path.basename(filePath) === PACKAGE_CONFIG_FILENAME) {
- config = config[PACKAGE_CONFIG_FIELD_NAME] || {};
+ if (config.extends) {
+ config = ConfigFile.applyExtends(config, filePath);
}
-
} else {
-
- // it's a package
- if (filePath.indexOf("eslint-config-") === -1) {
- if (filePath.indexOf("@") === 0) {
- // for scoped packages, insert the eslint-config after the first /
- filePath = filePath.replace(/^([^\/]+\/)(.*)$/, "$1eslint-config-$2");
- } else {
- filePath = "eslint-config-" + filePath;
- }
- }
-
- config = util.mergeConfigs(config, require(filePath));
+ filePath = configToLoad;
+ config = ConfigFile.load(filePath);
}
- validator.validate(config, filePath);
-
- // If an `extends` property is defined, it represents a configuration file to use as
- // a "parent". Load the referenced file and merge the configuration recursively.
- if (config.extends) {
- var configExtends = config.extends;
-
- if (!Array.isArray(config.extends)) {
- configExtends = [config.extends];
- }
-
- // Make the last element in an array take the highest precedence
- config = configExtends.reduceRight(function (previousValue, parentPath) {
-
- if (isFilePath(parentPath)) {
- // If the `extends` path is relative, use the directory of the current configuration
- // file as the reference point. Otherwise, use as-is.
- parentPath = (!isAbsolutePath(parentPath) ?
- path.join(path.dirname(filePath), parentPath) :
- parentPath
- );
- }
-
- try {
- return util.mergeConfigs(loadConfig(parentPath), previousValue);
- } catch (e) {
- // If the file referenced by `extends` failed to load, add the path to the
- // configuration file that referenced it to the error message so the user is
- // able to see where it was referenced from, then re-throw
- e.message += "\nReferenced from: " + filePath;
- throw e;
- }
-
- }, config);
-
- }
-
-
}
-
return config;
}
@@ -148,7 +87,7 @@ function loadConfig(filePath) {
function getPluginsConfig(pluginNames) {
var pluginConfig = {};
- pluginNames.forEach(function (pluginName) {
+ pluginNames.forEach(function(pluginName) {
var pluginNamespace = util.getNamespace(pluginName),
pluginNameWithoutNamespace = util.removeNameSpace(pluginName),
pluginNameWithoutPrefix = util.removePluginPrefix(pluginNameWithoutNamespace),
@@ -159,7 +98,7 @@ function getPluginsConfig(pluginNames) {
try {
plugin = require(pluginNamespace + util.PLUGIN_NAME_PREFIX + pluginNameWithoutPrefix);
loadedPlugins[pluginNameWithoutPrefix] = plugin;
- } catch(err) {
+ } catch (err) {
debug("Failed to load plugin configuration for " + pluginNameWithoutPrefix + ". Proceeding without it.");
plugin = { rulesConfig: {}};
}
@@ -175,7 +114,7 @@ function getPluginsConfig(pluginNames) {
rules[pluginNameWithoutPrefix + "/" + item] = plugin.rulesConfig[item];
});
- pluginConfig = util.mergeConfigs(pluginConfig, rules);
+ pluginConfig = ConfigOps.merge(pluginConfig, rules);
});
return {rules: pluginConfig};
@@ -187,11 +126,16 @@ function getPluginsConfig(pluginNames) {
* @private
*/
function getPersonalConfig() {
- var config = {};
+ var config = {},
+ filename;
+
+ if (PERSONAL_CONFIG_DIR) {
+ filename = ConfigFile.getFilenameForDirectory(PERSONAL_CONFIG_DIR);
- if (PERSONAL_CONFIG_PATH && fs.existsSync(PERSONAL_CONFIG_PATH)) {
- debug("Using personal config");
- config = loadConfig(PERSONAL_CONFIG_PATH);
+ if (filename) {
+ debug("Using personal config");
+ config = loadConfig(filename);
+ }
}
return config;
@@ -210,76 +154,45 @@ function getLocalConfig(thisConfig, directory) {
localConfigFile,
config = {},
localConfigFiles = thisConfig.findLocalConfigFiles(directory),
- numFiles = localConfigFiles.length;
+ numFiles = localConfigFiles.length,
+ rootPath,
+ projectConfigPath = ConfigFile.getFilenameForDirectory(process.cwd());
for (i = 0; i < numFiles; i++) {
localConfigFile = localConfigFiles[i];
- // Don't consider the personal config file in the home directory.
- if (localConfigFile === PERSONAL_CONFIG_PATH) {
+ // Don't consider the personal config file in the home directory,
+ // except if the home directory is the same as the current working directory
+ if (path.dirname(localConfigFile) === PERSONAL_CONFIG_DIR && localConfigFile !== projectConfigPath) {
+ continue;
+ }
+
+ // If root flag is set, don't consider file if it is above root
+ if (rootPath && !pathIsInside(path.dirname(localConfigFile), rootPath)) {
continue;
}
debug("Loading " + localConfigFile);
localConfig = loadConfig(localConfigFile);
- // Don't consider a local config file found if the config is empty.
- if (!Object.keys(localConfig).length) {
+ // Don't consider a local config file found if the config is null
+ if (!localConfig) {
continue;
}
+ // Check for root flag
+ if (localConfig.root === true) {
+ rootPath = path.dirname(localConfigFile);
+ }
+
found = true;
debug("Using " + localConfigFile);
- config = util.mergeConfigs(localConfig, config);
+ config = ConfigOps.merge(localConfig, config);
}
// Use the personal config file if there are no other local config files found.
- return found ? config : util.mergeConfigs(config, getPersonalConfig());
-}
-
-/**
- * Creates an environment config based on the specified environments.
- * @param {Object<string,boolean>} envs The environment settings.
- * @param {boolean} reset The value of the command line reset option. If true,
- * rules are not automatically merged into the config.
- * @returns {Object} A configuration object with the appropriate rules and globals
- * set.
- * @private
- */
-function createEnvironmentConfig(envs, reset) {
-
- var envConfig = {
- globals: {},
- env: envs || {},
- rules: {},
- ecmaFeatures: {}
- };
-
- if (envs) {
- Object.keys(envs).filter(function (name) {
- return envs[name];
- }).forEach(function(name) {
- var environment = environments[name];
-
- if (environment) {
-
- if (!reset && environment.rules) {
- assign(envConfig.rules, environment.rules);
- }
-
- if (environment.globals) {
- assign(envConfig.globals, environment.globals);
- }
-
- if (environment.ecmaFeatures) {
- assign(envConfig.ecmaFeatures, environment.ecmaFeatures);
- }
- }
- });
- }
-
- return envConfig;
+ return found ? config : ConfigOps.merge(config, getPersonalConfig());
}
//------------------------------------------------------------------------------
@@ -301,26 +214,18 @@ function Config(options) {
this.ignore = options.ignore;
this.ignorePath = options.ignorePath;
this.cache = {};
+ this.parser = options.parser;
- if (options.reset || options.baseConfig === false) {
- // If `options.reset` is truthy or `options.baseConfig` is set to `false`,
- // disable all default rules and environments
- this.baseConfig = { rules: {} };
- } else {
- // If `options.baseConfig` is an object, just use it,
- // otherwise use default base config from `conf/eslint.json`
- this.baseConfig = options.baseConfig ||
- require(path.resolve(__dirname, "..", "conf", "eslint.json"));
- }
+ this.baseConfig = options.baseConfig ? loadConfig(options.baseConfig) : { rules: {} };
this.useEslintrc = (options.useEslintrc !== false);
- this.env = (options.envs || []).reduce(function (envs, name) {
+ this.env = (options.envs || []).reduce(function(envs, name) {
envs[name] = true;
return envs;
}, {});
- this.globals = (options.globals || []).reduce(function (globals, def) {
+ this.globals = (options.globals || []).reduce(function(globals, def) {
// Default "foo" to false and handle "foo:false" and "foo:true"
var parts = def.split(":");
globals[parts[0]] = (parts.length > 1 && parts[1] === "true");
@@ -332,7 +237,11 @@ function Config(options) {
if (useConfig) {
debug("Using command line config " + useConfig);
- this.useSpecificConfig = loadConfig(path.resolve(process.cwd(), useConfig));
+ if (isResolvable(useConfig) || isResolvable("eslint-config-" + useConfig) || useConfig.charAt(0) === "@") {
+ this.useSpecificConfig = loadConfig(useConfig);
+ } else {
+ this.useSpecificConfig = loadConfig(path.resolve(process.cwd(), useConfig));
+ }
}
}
@@ -342,7 +251,7 @@ function Config(options) {
* @param {string} filePath a file in whose directory we start looking for a local config
* @returns {Object} config object
*/
-Config.prototype.getConfig = function (filePath) {
+Config.prototype.getConfig = function(filePath) {
var config,
userConfig,
directory = filePath ? path.dirname(filePath) : process.cwd(),
@@ -367,43 +276,42 @@ Config.prototype.getConfig = function (filePath) {
}
// Step 2: Create a copy of the baseConfig
- config = util.mergeConfigs({}, this.baseConfig);
-
- // Step 3: Merge in environment-specific globals and rules from .eslintrc files
- config = util.mergeConfigs(config, createEnvironmentConfig(userConfig.env, this.options.reset));
+ config = ConfigOps.merge({parser: this.parser}, this.baseConfig);
- // Step 4: Merge in the user-specified configuration from .eslintrc and package.json
- config = util.mergeConfigs(config, userConfig);
+ // Step 3: Merge in the user-specified configuration from .eslintrc and package.json
+ config = ConfigOps.merge(config, userConfig);
- // Step 5: Merge in command line config file
+ // Step 4: Merge in command line config file
if (this.useSpecificConfig) {
debug("Merging command line config file");
- if (this.useSpecificConfig.env) {
- config = util.mergeConfigs(config, createEnvironmentConfig(this.useSpecificConfig.env, this.options.reset));
- }
-
- config = util.mergeConfigs(config, this.useSpecificConfig);
+ config = ConfigOps.merge(config, this.useSpecificConfig);
}
- // Step 6: Merge in command line environments
+ // Step 5: Merge in command line environments
debug("Merging command line environment settings");
- config = util.mergeConfigs(config, createEnvironmentConfig(this.env, this.options.reset));
+ config = ConfigOps.merge(config, ConfigOps.createEnvironmentConfig(this.env));
- // Step 7: Merge in command line rules
+ // Step 6: Merge in command line rules
if (this.options.rules) {
debug("Merging command line rules");
- config = util.mergeConfigs(config, { rules: this.options.rules });
+ config = ConfigOps.merge(config, { rules: this.options.rules });
}
- // Step 8: Merge in command line globals
- config = util.mergeConfigs(config, { globals: this.globals });
+ // Step 7: Merge in command line globals
+ config = ConfigOps.merge(config, { globals: this.globals });
+ // Step 8: Merge in command line plugins
+ if (this.options.plugins) {
+ debug("Merging command line plugins");
+ pluginConfig = getPluginsConfig(this.options.plugins);
+ config = ConfigOps.merge(config, { plugins: this.options.plugins });
+ }
// Step 9: Merge in plugin specific rules in reverse
if (config.plugins) {
pluginConfig = getPluginsConfig(config.plugins);
- config = util.mergeConfigs(pluginConfig, config);
+ config = ConfigOps.merge(pluginConfig, config);
}
this.cache[directory] = config;
@@ -416,10 +324,10 @@ Config.prototype.getConfig = function (filePath) {
* @param {string} directory The directory to start searching from.
* @returns {string[]} The paths of local config files found.
*/
-Config.prototype.findLocalConfigFiles = function (directory) {
+Config.prototype.findLocalConfigFiles = function(directory) {
if (!this.localConfigFinder) {
- this.localConfigFinder = new FileFinder(LOCAL_CONFIG_FILENAME, PACKAGE_CONFIG_FILENAME);
+ this.localConfigFinder = new FileFinder(ConfigFile.CONFIG_FILES, PACKAGE_CONFIG_FILENAME);
}
return this.localConfigFinder.findAllInDirectoryAndParents(directory);