From e7581dd83302708ecf5c963e963075febe1a0885 Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Tue, 17 Dec 2019 21:12:06 +0900 Subject: [PATCH] Breaking: runtime-deprecation on '~/.eslintrc' (refs eslint/rfcs#32) --- .../cascading-config-array-factory.js | 49 ++++++++++++---- lib/shared/config-validator.js | 29 +--------- lib/shared/deprecation-warnings.js | 56 +++++++++++++++++++ 3 files changed, 95 insertions(+), 39 deletions(-) create mode 100644 lib/shared/deprecation-warnings.js diff --git a/lib/cli-engine/cascading-config-array-factory.js b/lib/cli-engine/cascading-config-array-factory.js index 52703a873bb..4a5ab73ff09 100644 --- a/lib/cli-engine/cascading-config-array-factory.js +++ b/lib/cli-engine/cascading-config-array-factory.js @@ -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"); @@ -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, @@ -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); @@ -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" + ); + } + return this._cacheConfig(directoryPath, baseConfigArray); + } + if (configArray.length > 0 && configArray.isRoot()) { debug("Stop traversing because of 'root:true'."); configArray.unshift(...baseConfigArray); @@ -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) { @@ -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" + ); + finalConfigArray = + finalConfigArray.concat(personalConfigArray); + } } // Apply CLI options. diff --git a/lib/shared/config-validator.js b/lib/shared/config-validator.js index aca6e1fb274..70eaf0a9670 100644 --- a/lib/shared/config-validator.js +++ b/lib/shared/config-validator.js @@ -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(); @@ -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, @@ -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. diff --git a/lib/shared/deprecation-warnings.js b/lib/shared/deprecation-warnings.js new file mode 100644 index 00000000000..fce52549bd1 --- /dev/null +++ b/lib/shared/deprecation-warnings.js @@ -0,0 +1,56 @@ +/** + * @fileoverview Provide the function that emits deprecation warnings. + * @author Toru Nagashima + */ +"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_CONFOG_LOAD: + "The '~/.eslintrc.*' config file has been deprecated. " + + "Please use config files for each project or '--config' option.", + ESLINT_PERSONAL_CONFOG_SUPPRESS: + "The '~/.eslintrc.*' config file has been deprecated. " + + "Please remove it or add 'root:true' into the config file of 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 +};