Skip to content

Commit

Permalink
New: Add resolveRelativeToConfigFile setting to enable modern module …
Browse files Browse the repository at this point in the history
…resolution (fixes #3458)
  • Loading branch information
octogonz committed Oct 19, 2019
1 parent 84f71de commit d8dac5a
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 3 deletions.
1 change: 1 addition & 0 deletions conf/config-schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const baseConfigProperties = {
settings: { type: "object" },
noInlineConfig: { type: "boolean" },
reportUnusedDisableDirectives: { type: "boolean" },
resolveRelativeToConfigFile: { type: "boolean" },

ecmaFeatures: { type: "object" } // deprecated; logs a warning when used
};
Expand Down
33 changes: 31 additions & 2 deletions lib/cli-engine/config-array-factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,12 @@ class ConfigArrayFactory {
cwd = process.cwd(),
resolvePluginsRelativeTo = cwd
} = {}) {
internalSlotsMap.set(this, { additionalPluginPool, cwd, resolvePluginsRelativeTo: path.resolve(cwd, resolvePluginsRelativeTo) });
internalSlotsMap.set(this, {
additionalPluginPool,
cwd,
resolvePluginsRelativeTo: path.resolve(cwd, resolvePluginsRelativeTo),
resolveRelativeToConfigFile: false
});
}

/**
Expand Down Expand Up @@ -532,6 +537,7 @@ class ConfigArrayFactory {
plugins: pluginList,
processor,
reportUnusedDisableDirectives,
resolveRelativeToConfigFile,
root,
rules,
settings,
Expand All @@ -540,6 +546,23 @@ class ConfigArrayFactory {
filePath,
name
) {
if (resolveRelativeToConfigFile) {
const internalSlot = internalSlotsMap.get(this);

/*
* If we encounter a config file with resolveRelativeToConfigFile=true, then we enable that behavior
* permanently for all subsequent config files. This approach is needed because ESLint normally waits
* to calculate config options until after everything is loaded, wheres plugins get loaded right away.
* This design isn't ideal, but it works in practice because "resolveRelativeToConfigFile" has a
* relatively simple use case: It opts-in to the modern module resolution behavior that eventually
* should be the default for ESLint.
*/
if (!internalSlot.resolveRelativeToConfigFile) {
debug("Plugins will be resolved using the resolveRelativeToConfigFile behavior");
internalSlot.resolveRelativeToConfigFile = true;
}
}

const extendList = Array.isArray(extend) ? extend : [extend];

// Flatten `extends`.
Expand Down Expand Up @@ -842,7 +865,13 @@ class ConfigArrayFactory {
let error;

try {
filePath = ModuleResolver.resolve(request, relativeTo);
const { resolveRelativeToConfigFile } = internalSlotsMap.get(this);

if (resolveRelativeToConfigFile) {
filePath = ModuleResolver.resolve(request, importerPath);
} else {
filePath = ModuleResolver.resolve(request, relativeTo);
}
} catch (resolveError) {
error = resolveError;
/* istanbul ignore else */
Expand Down
6 changes: 6 additions & 0 deletions lib/cli-engine/config-array/config-array.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ const { ExtractedConfig } = require("./extracted-config");
* @property {Record<string, DependentPlugin>|undefined} plugins The plugin loaders.
* @property {string|undefined} processor The processor name to refer plugin's processor.
* @property {boolean|undefined} reportUnusedDisableDirectives The flag to report unused `eslint-disable` comments.
* @property {boolean|undefined} resolveRelativeToConfigFile When set to `true`, plugins are resolved relative to the config file that imports them.
* @property {boolean|undefined} root The flag to express root.
* @property {Record<string, RuleConf>|undefined} rules The rule settings
* @property {Object|undefined} settings The shared settings.
Expand Down Expand Up @@ -260,6 +261,11 @@ function createConfig(instance, indices) {
config.reportUnusedDisableDirectives = element.reportUnusedDisableDirectives;
}

// Adopt the resolveRelativeToConfigFile which was found at first.
if (config.resolveRelativeToConfigFile === void 0 && element.resolveRelativeToConfigFile !== void 0) {
config.resolveRelativeToConfigFile = element.resolveRelativeToConfigFile;
}

// Merge others.
mergeWithoutOverwrite(config.env, element.env);
mergeWithoutOverwrite(config.globals, element.globals);
Expand Down
6 changes: 6 additions & 0 deletions lib/cli-engine/config-array/extracted-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ class ExtractedConfig {
*/
this.reportUnusedDisableDirectives = void 0;

/**
* When set to `true`, plugins are resolved relative to the config file that imports them.
* @type {boolean|undefined}
*/
this.resolveRelativeToConfigFile = void 0;

/**
* Rule settings.
* @type {Record<string, [SeverityConf, ...any[]]>}
Expand Down
2 changes: 2 additions & 0 deletions lib/shared/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ module.exports = {};
* @property {string[]} [plugins] The plugin specifiers.
* @property {string} [processor] The processor specifier.
* @property {boolean|undefined} reportUnusedDisableDirectives The flag to report unused `eslint-disable` comments.
* @property {boolean|undefined} resolveRelativeToConfigFile When set to `true`, plugins are resolved relative to the config file that imports them.
* @property {boolean} [root] The root flag.
* @property {Record<string, RuleConf>} [rules] The rule settings.
* @property {Object} [settings] The shared settings.
Expand All @@ -56,6 +57,7 @@ module.exports = {};
* @property {string[]} [plugins] The plugin specifiers.
* @property {string} [processor] The processor specifier.
* @property {boolean|undefined} reportUnusedDisableDirectives The flag to report unused `eslint-disable` comments.
* @property {boolean|undefined} resolveRelativeToConfigFile When set to `true`, plugins are resolved relative to the config file that imports them.
* @property {Record<string, RuleConf>} [rules] The rule settings.
* @property {Object} [settings] The shared settings.
*/
Expand Down
1 change: 1 addition & 0 deletions tests/lib/cli-engine/config-array-factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ function assertConfig(actual, providedExpected) {
parserOptions: {},
plugins: [],
reportUnusedDisableDirectives: void 0,
resolveRelativeToConfigFile: void 0,
rules: {},
settings: {},
...providedExpected
Expand Down
5 changes: 4 additions & 1 deletion tests/lib/cli-engine/config-array/config-array.js
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@ describe("ConfigArray", () => {
},
plugins: {},
processor: null,
resolveRelativeToConfigFile: void 0,
reportUnusedDisableDirectives: void 0,
rules: {},
settings: {}
Expand Down Expand Up @@ -466,6 +467,7 @@ describe("ConfigArray", () => {
},
plugins: {},
processor: null,
resolveRelativeToConfigFile: void 0,
reportUnusedDisableDirectives: void 0,
rules: {},
settings: {}
Expand Down Expand Up @@ -609,7 +611,8 @@ describe("ConfigArray", () => {
settings: {},
processor: null,
noInlineConfig: void 0,
reportUnusedDisableDirectives: void 0
reportUnusedDisableDirectives: void 0,
resolveRelativeToConfigFile: void 0
});
assert.deepStrictEqual(config[0], {
rules: {
Expand Down

0 comments on commit d8dac5a

Please sign in to comment.