Skip to content

Commit

Permalink
Breaking: runtime-deprecation on '~/.eslintrc' (refs eslint/rfcs#32) (#…
Browse files Browse the repository at this point in the history
…12678)

Co-Authored-By: Kai Cataldo <kai@kaicataldo.com>
  • Loading branch information
mysticatea and kaicataldo committed Jan 7, 2020
1 parent 2c28fbb commit 1118fce
Show file tree
Hide file tree
Showing 7 changed files with 483 additions and 36 deletions.
2 changes: 1 addition & 1 deletion docs/user-guide/configuring.md
Expand Up @@ -1100,7 +1100,7 @@ This message occurs because ESLint is unsure if you wanted to actually lint the

## Personal Configuration File (deprecated)

⚠️ **This feature has been deprecated**. ESLint will print deprecation warnings beginning with the 7.0.0 release. This feature will then be removed in the 8.0.0 release. If you want to continue to use personal configuration files, please use the [`--config` CLI option](https://eslint.org/docs/user-guide/command-line-interface#-c---config). For more information regarding this decision, please see [RFC 28](https://github.com/eslint/rfcs/pull/28) and [RFC 32](https://github.com/eslint/rfcs/pull/32).
⚠️ **This feature has been deprecated**. This feature will be removed in the 8.0.0 release. If you want to continue to use personal configuration files, please use the [`--config` CLI option](https://eslint.org/docs/user-guide/command-line-interface#-c---config). For more information regarding this decision, please see [RFC 28](https://github.com/eslint/rfcs/pull/28) and [RFC 32](https://github.com/eslint/rfcs/pull/32).

`~/` refers to [the home directory of the current user on your preferred operating system](https://nodejs.org/api/os.html#os_os_homedir). The personal configuration file being referred to here is `~/.eslintrc.*` file, which is currently handled differently than other configuration files.

Expand Down
44 changes: 38 additions & 6 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 @@ -320,6 +322,16 @@ class CascadingConfigArrayFactory {
// Consider this is root.
if (directoryPath === homePath && cwd !== homePath) {
debug("Stop traversing because of considered root.");
if (configsExistInSubdirs) {
const filePath = ConfigArrayFactory.getPathToConfigFileInDirectory(directoryPath);

if (filePath) {
emitDeprecationWarning(
filePath,
"ESLINT_PERSONAL_CONFIG_SUPPRESS"
);
}
}
return this._cacheConfig(directoryPath, baseConfigArray);
}

Expand All @@ -344,7 +356,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 @@ -400,12 +415,29 @@ class CascadingConfigArrayFactory {
configArray.every(c => !c.filePath) &&
cliConfigArray.every(c => !c.filePath) // `--config` option can be a file.
) {
debug("Loading the config file of the home directory.");
const homePath = os.homedir();

debug("Loading the config file of the home directory:", homePath);

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

if (
personalConfigArray.length > 0 &&
!directoryPath.startsWith(homePath)
) {
const lastElement =
personalConfigArray[personalConfigArray.length - 1];

emitDeprecationWarning(
lastElement.filePath,
"ESLINT_PERSONAL_CONFIG_LOAD"
);
}

finalConfigArray = finalConfigArray.concat(personalConfigArray);
}

// Apply CLI options.
Expand Down
23 changes: 23 additions & 0 deletions lib/cli-engine/config-array-factory.js
Expand Up @@ -436,6 +436,29 @@ class ConfigArrayFactory {
);
}

/**
* Check if a config file on a given directory exists or not.
* @param {string} directoryPath The path to a directory.
* @returns {string | null} The path to the found config file. If not found then null.
*/
static getPathToConfigFileInDirectory(directoryPath) {
for (const filename of configFilenames) {
const filePath = path.join(directoryPath, filename);

if (fs.existsSync(filePath)) {
if (filename === "package.json") {
try {
loadPackageJSONConfigFile(filePath);
return filePath;
} catch (error) { /* ignore */ }
} else {
return filePath;
}
}
}
return null;
}

/**
* Load `.eslintignore` file.
* @param {string} filePath The path to a `.eslintignore` file to load.
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.",
ESLINT_PERSONAL_CONFIG_LOAD:
"'~/.eslintrc.*' config files have been deprecated. " +
"Please use a config file per project or the '--config' option.",
ESLINT_PERSONAL_CONFIG_SUPPRESS:
"'~/.eslintrc.*' config files have been deprecated. " +
"Please remove it or add 'root:true' to the config files in your " +
"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
};
2 changes: 1 addition & 1 deletion tests/bin/eslint.js
Expand Up @@ -388,7 +388,7 @@ describe("bin/eslint.js", () => {

const exitCodePromise = assertExitCode(child, 0);
const outputPromise = getOutput(child).then(output => {
assert.include(output.stderr, "The 'ecmaFeatures' config file property is deprecated, and has no effect.");
assert.include(output.stderr, "The 'ecmaFeatures' config file property is deprecated and has no effect.");
});

return Promise.all([exitCodePromise, outputPromise]);
Expand Down

0 comments on commit 1118fce

Please sign in to comment.