Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Breaking: runtime-deprecation on '~/.eslintrc' (refs eslint/rfcs#32) #12678

Merged
merged 14 commits into from Jan 7, 2020
Merged
49 changes: 37 additions & 12 deletions lib/cli-engine/cascading-config-array-factory.js
Expand Up @@ -26,6 +26,7 @@
const os = require("os");
const path = require("path");
const { validateConfigArray } = require("../shared/config-validator");
const { emitDeprecationWarning } = require("../shared/deprecation-warnings");
const { ConfigArrayFactory } = require("./config-array-factory");
const { ConfigArray, ConfigDependency, IgnorePattern } = require("./config-array");
const loadRules = require("./load-rules");
Expand Down Expand Up @@ -290,10 +291,11 @@ class CascadingConfigArrayFactory {
/**
* Load and normalize config files from the ancestor directories.
* @param {string} directoryPath The path to a leaf directory.
* @param {boolean} configsExistInSubdirs `true` if configurations exist in subdirectories.
* @returns {ConfigArray} The loaded config.
* @private
*/
_loadConfigInAncestors(directoryPath) {
_loadConfigInAncestors(directoryPath, configsExistInSubdirs = false) {
const {
baseConfigArray,
configArrayFactory,
Expand All @@ -315,14 +317,6 @@ class CascadingConfigArrayFactory {
}
debug(`No cache found: ${directoryPath}.`);

const homePath = os.homedir();

// Consider this is root.
if (directoryPath === homePath && cwd !== homePath) {
debug("Stop traversing because of considered root.");
return this._cacheConfig(directoryPath, baseConfigArray);
}

// Load the config on this directory.
try {
configArray = configArrayFactory.loadInDirectory(directoryPath);
Expand All @@ -335,6 +329,22 @@ class CascadingConfigArrayFactory {
throw error;
}

const homePath = os.homedir();

// Consider this is root.
if (directoryPath === homePath && cwd !== homePath) {
debug("Stop traversing because of considered root.");
if (configsExistInSubdirs && configArray.length > 0) {
const lastElement = configArray[configArray.length - 1];

emitDeprecationWarning(
lastElement.filePath,
"ESLINT_PERSONAL_CONFOG_SUPPRESS"
mysticatea marked this conversation as resolved.
Show resolved Hide resolved
);
}
return this._cacheConfig(directoryPath, baseConfigArray);
}

if (configArray.length > 0 && configArray.isRoot()) {
debug("Stop traversing because of 'root:true'.");
configArray.unshift(...baseConfigArray);
Expand All @@ -344,7 +354,10 @@ class CascadingConfigArrayFactory {
// Load from the ancestors and merge it.
const parentPath = path.dirname(directoryPath);
const parentConfigArray = parentPath && parentPath !== directoryPath
? this._loadConfigInAncestors(parentPath)
? this._loadConfigInAncestors(
parentPath,
configsExistInSubdirs || configArray.length > 0
)
: baseConfigArray;

if (configArray.length > 0) {
Expand Down Expand Up @@ -402,10 +415,22 @@ class CascadingConfigArrayFactory {
) {
debug("Loading the config file of the home directory.");

finalConfigArray = configArrayFactory.loadInDirectory(
const personalConfigArray = configArrayFactory.loadInDirectory(
os.homedir(),
{ name: "PersonalConfig", parent: finalConfigArray }
{ name: "PersonalConfig" }
);

if (personalConfigArray.length > 0) {
const lastElement =
personalConfigArray[personalConfigArray.length - 1];

emitDeprecationWarning(
lastElement.filePath,
"ESLINT_PERSONAL_CONFOG_LOAD"
mysticatea marked this conversation as resolved.
Show resolved Hide resolved
);
finalConfigArray =
finalConfigArray.concat(personalConfigArray);
}
}

// Apply CLI options.
Expand Down
29 changes: 2 additions & 27 deletions lib/shared/config-validator.js
Expand Up @@ -10,13 +10,12 @@
//------------------------------------------------------------------------------

const
path = require("path"),
util = require("util"),
lodash = require("lodash"),
configSchema = require("../../conf/config-schema"),
BuiltInEnvironments = require("../../conf/environments"),
BuiltInRules = require("../rules"),
ConfigOps = require("./config-ops");
ConfigOps = require("./config-ops"),
{ emitDeprecationWarning } = require("./deprecation-warnings");

const ajv = require("./ajv")();
const ruleValidators = new WeakMap();
Expand All @@ -26,11 +25,6 @@ const noop = Function.prototype;
// Private
//------------------------------------------------------------------------------
let validateSchema;

// Defitions for deprecation warnings.
const deprecationWarningMessages = {
ESLINT_LEGACY_ECMAFEATURES: "The 'ecmaFeatures' config file property is deprecated, and has no effect."
};
const severityMap = {
error: 2,
warn: 1,
Expand Down Expand Up @@ -254,25 +248,6 @@ function formatErrors(errors) {
}).map(message => `\t- ${message}.\n`).join("");
}

/**
* Emits a deprecation warning containing a given filepath. A new deprecation warning is emitted
* for each unique file path, but repeated invocations with the same file path have no effect.
* No warnings are emitted if the `--no-deprecation` or `--no-warnings` Node runtime flags are active.
* @param {string} source The name of the configuration source to report the warning for.
* @param {string} errorCode The warning message to show.
* @returns {void}
*/
const emitDeprecationWarning = lodash.memoize((source, errorCode) => {
const rel = path.relative(process.cwd(), source);
const message = deprecationWarningMessages[errorCode];

process.emitWarning(
`${message} (found in "${rel}")`,
"DeprecationWarning",
errorCode
);
});

/**
* Validates the top level properties of the config object.
* @param {Object} config The config object to validate.
Expand Down
56 changes: 56 additions & 0 deletions lib/shared/deprecation-warnings.js
@@ -0,0 +1,56 @@
/**
* @fileoverview Provide the function that emits deprecation warnings.
* @author Toru Nagashima <http://github.com/mysticatea>
*/
"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

const path = require("path");
const lodash = require("lodash");

//------------------------------------------------------------------------------
// Private
//------------------------------------------------------------------------------

// Defitions for deprecation warnings.
const deprecationWarningMessages = {
ESLINT_LEGACY_ECMAFEATURES:
"The 'ecmaFeatures' config file property is deprecated, and has no effect.",
mysticatea marked this conversation as resolved.
Show resolved Hide resolved
ESLINT_PERSONAL_CONFOG_LOAD:
mysticatea marked this conversation as resolved.
Show resolved Hide resolved
"The '~/.eslintrc.*' config file has been deprecated. " +
mysticatea marked this conversation as resolved.
Show resolved Hide resolved
"Please use config files for each project or '--config' option.",
mysticatea marked this conversation as resolved.
Show resolved Hide resolved
ESLINT_PERSONAL_CONFOG_SUPPRESS:
mysticatea marked this conversation as resolved.
Show resolved Hide resolved
"The '~/.eslintrc.*' config file has been deprecated. " +
mysticatea marked this conversation as resolved.
Show resolved Hide resolved
"Please remove it or add 'root:true' into the config file of your " +
mysticatea marked this conversation as resolved.
Show resolved Hide resolved
"projects in order to avoid loading '~/.eslintrc.*' accidentally."
};

/**
* Emits a deprecation warning containing a given filepath. A new deprecation warning is emitted
* for each unique file path, but repeated invocations with the same file path have no effect.
* No warnings are emitted if the `--no-deprecation` or `--no-warnings` Node runtime flags are active.
* @param {string} source The name of the configuration source to report the warning for.
* @param {string} errorCode The warning message to show.
* @returns {void}
*/
const emitDeprecationWarning = lodash.memoize((source, errorCode) => {
const rel = path.relative(process.cwd(), source);
const message = deprecationWarningMessages[errorCode];

process.emitWarning(
`${message} (found in "${rel}")`,
"DeprecationWarning",
errorCode
);
}, (...args) => JSON.stringify(args));

//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------

module.exports = {
emitDeprecationWarning
};