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

New: Add resolveRelativeToConfigFile setting (fixes #3458) #12460

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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