Skip to content

Commit a806994

Browse files
nzakasfasttime
andauthored
refactor: Remove eslintrc from flat config functionality (#19833)
* refactor: Remove eslintrc from flat config functionality * Fix knip error * Fix knip again * Update lib/shared/relative-module-resolver.js Co-authored-by: Francesco Trotta <github@fasttime.org> * Remove unused file --------- Co-authored-by: Francesco Trotta <github@fasttime.org>
1 parent 19cdd22 commit a806994

File tree

9 files changed

+252
-33
lines changed

9 files changed

+252
-33
lines changed

lib/cli.js

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,14 @@ const fs = require("node:fs"),
2828
log = require("./shared/logging"),
2929
RuntimeInfo = require("./shared/runtime-info"),
3030
{ normalizeSeverityToString } = require("./shared/severity");
31-
const {
32-
Legacy: { naming },
33-
} = require("@eslint/eslintrc");
3431
const { ModuleImporter } = require("@humanwhocodes/module-importer");
3532
const { getCacheFile } = require("./eslint/eslint-helpers");
3633
const { SuppressionsService } = require("./services/suppressions-service");
3734
const debug = require("debug")("eslint:cli");
35+
const {
36+
normalizePackageName,
37+
getShorthandName,
38+
} = require("./shared/naming.js");
3839

3940
//------------------------------------------------------------------------------
4041
// Types
@@ -67,10 +68,7 @@ async function loadPlugins(importer, pluginNames) {
6768

6869
await Promise.all(
6970
pluginNames.map(async pluginName => {
70-
const longName = naming.normalizePackageName(
71-
pluginName,
72-
"eslint-plugin",
73-
);
71+
const longName = normalizePackageName(pluginName, "eslint-plugin");
7472
const module = await importer.import(longName);
7573

7674
if (!("default" in module)) {
@@ -79,10 +77,7 @@ async function loadPlugins(importer, pluginNames) {
7977
);
8078
}
8179

82-
const shortName = naming.getShorthandName(
83-
pluginName,
84-
"eslint-plugin",
85-
);
80+
const shortName = getShorthandName(pluginName, "eslint-plugin");
8681

8782
plugins[shortName] = module.default;
8883
}),

lib/eslint/eslint.js

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,6 @@ const path = require("node:path");
1515
const { version } = require("../../package.json");
1616
const { Linter } = require("../linter");
1717
const { defaultConfig } = require("../config/default-config");
18-
const {
19-
Legacy: {
20-
ConfigOps: { getRuleSeverity },
21-
ModuleResolver,
22-
naming,
23-
},
24-
} = require("@eslint/eslintrc");
2518

2619
const {
2720
findFiles,
@@ -41,6 +34,13 @@ const LintResultCache = require("../cli-engine/lint-result-cache");
4134
const { Retrier } = require("@humanwhocodes/retry");
4235
const { ConfigLoader, LegacyConfigLoader } = require("../config/config-loader");
4336
const { WarningService } = require("../services/warning-service");
37+
const { Config } = require("../config/config.js");
38+
const {
39+
getShorthandName,
40+
getNamespaceFromTerm,
41+
normalizePackageName,
42+
} = require("../shared/naming.js");
43+
const { resolve } = require("../shared/relative-module-resolver.js");
4444

4545
/*
4646
* This is necessary to allow overwriting writeFile for testing purposes.
@@ -160,7 +160,7 @@ function getOrFindUsedDeprecatedRules(eslint, maybeFilePath) {
160160

161161
if (config.rules) {
162162
for (const [ruleId, ruleConf] of Object.entries(config.rules)) {
163-
if (getRuleSeverity(ruleConf) === 0) {
163+
if (Config.getRuleNumericSeverity(ruleConf) === 0) {
164164
continue;
165165
}
166166
const rule = config.getRuleDefinition(ruleId);
@@ -174,7 +174,7 @@ function getOrFindUsedDeprecatedRules(eslint, maybeFilePath) {
174174
replacedBy: usesNewFormat
175175
? (meta.deprecated.replacedBy?.map(
176176
replacement =>
177-
`${replacement.plugin?.name !== void 0 ? `${naming.getShorthandName(replacement.plugin.name, "eslint-plugin")}/` : ""}${replacement.rule?.name ?? ""}`,
177+
`${replacement.plugin?.name !== void 0 ? `${getShorthandName(replacement.plugin.name, "eslint-plugin")}/` : ""}${replacement.rule?.name ?? ""}`,
178178
) ?? [])
179179
: meta.replacedBy || [],
180180
info: usesNewFormat ? meta.deprecated : void 0,
@@ -489,8 +489,7 @@ class ESLint {
489489
for (const [pluginName, plugin] of Object.entries(
490490
options.plugins,
491491
)) {
492-
plugins[naming.getShorthandName(pluginName, "eslint-plugin")] =
493-
plugin;
492+
plugins[getShorthandName(pluginName, "eslint-plugin")] = plugin;
494493
}
495494

496495
defaultConfigs.push({
@@ -998,7 +997,7 @@ class ESLint {
998997

999998
// replace \ with / for Windows compatibility
1000999
const normalizedFormatName = name.replace(/\\/gu, "/");
1001-
const namespace = naming.getNamespaceFromTerm(normalizedFormatName);
1000+
const namespace = getNamespaceFromTerm(normalizedFormatName);
10021001

10031002
// grab our options
10041003
const { cwd } = privateMembers.get(this).options;
@@ -1010,16 +1009,13 @@ class ESLint {
10101009
formatterPath = path.resolve(cwd, normalizedFormatName);
10111010
} else {
10121011
try {
1013-
const npmFormat = naming.normalizePackageName(
1012+
const npmFormat = normalizePackageName(
10141013
normalizedFormatName,
10151014
"eslint-formatter",
10161015
);
10171016

10181017
// TODO: This is pretty dirty...would be nice to clean up at some point.
1019-
formatterPath = ModuleResolver.resolve(
1020-
npmFormat,
1021-
getPlaceholderPath(cwd),
1022-
);
1018+
formatterPath = resolve(npmFormat, getPlaceholderPath(cwd));
10231019
} catch {
10241020
formatterPath = path.resolve(
10251021
__dirname,

lib/linter/apply-disable-directives.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@
1919
//------------------------------------------------------------------------------
2020

2121
const escapeRegExp = require("escape-string-regexp");
22-
const {
23-
Legacy: { ConfigOps },
24-
} = require("@eslint/eslintrc/universal");
22+
const { Config } = require("../config/config.js");
2523

2624
/**
2725
* Compares the locations of two objects in a source file
@@ -539,7 +537,7 @@ module.exports = ({
539537
configuredRules && ruleFilter
540538
? new Set(
541539
Object.keys(configuredRules).filter(ruleId => {
542-
const severity = ConfigOps.getRuleSeverity(
540+
const severity = Config.getRuleNumericSeverity(
543541
configuredRules[ruleId],
544542
);
545543

lib/shared/naming.js

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/**
2+
* @fileoverview Common helpers for naming of plugins, formatters and configs
3+
*/
4+
5+
"use strict";
6+
7+
const NAMESPACE_REGEX = /^@.*\//iu;
8+
9+
/**
10+
* Brings package name to correct format based on prefix
11+
* @param {string} name The name of the package.
12+
* @param {string} prefix Can be either "eslint-plugin", "eslint-config" or "eslint-formatter"
13+
* @returns {string} Normalized name of the package
14+
* @private
15+
*/
16+
function normalizePackageName(name, prefix) {
17+
let normalizedName = name;
18+
19+
/**
20+
* On Windows, name can come in with Windows slashes instead of Unix slashes.
21+
* Normalize to Unix first to avoid errors later on.
22+
* https://github.com/eslint/eslint/issues/5644
23+
*/
24+
if (normalizedName.includes("\\")) {
25+
normalizedName = normalizedName.replace(/\\/gu, "/");
26+
}
27+
28+
if (normalizedName.charAt(0) === "@") {
29+
/**
30+
* it's a scoped package
31+
* package name is the prefix, or just a username
32+
*/
33+
const scopedPackageShortcutRegex = new RegExp(
34+
`^(@[^/]+)(?:/(?:${prefix})?)?$`,
35+
"u",
36+
),
37+
scopedPackageNameRegex = new RegExp(`^${prefix}(-|$)`, "u");
38+
39+
if (scopedPackageShortcutRegex.test(normalizedName)) {
40+
normalizedName = normalizedName.replace(
41+
scopedPackageShortcutRegex,
42+
`$1/${prefix}`,
43+
);
44+
} else if (!scopedPackageNameRegex.test(normalizedName.split("/")[1])) {
45+
/**
46+
* for scoped packages, insert the prefix after the first / unless
47+
* the path is already @scope/eslint or @scope/eslint-xxx-yyy
48+
*/
49+
normalizedName = normalizedName.replace(
50+
/^@([^/]+)\/(.*)$/u,
51+
`@$1/${prefix}-$2`,
52+
);
53+
}
54+
} else if (!normalizedName.startsWith(`${prefix}-`)) {
55+
normalizedName = `${prefix}-${normalizedName}`;
56+
}
57+
58+
return normalizedName;
59+
}
60+
61+
/**
62+
* Removes the prefix from a fullname.
63+
* @param {string} fullname The term which may have the prefix.
64+
* @param {string} prefix The prefix to remove.
65+
* @returns {string} The term without prefix.
66+
*/
67+
function getShorthandName(fullname, prefix) {
68+
if (fullname[0] === "@") {
69+
let matchResult = new RegExp(`^(@[^/]+)/${prefix}$`, "u").exec(
70+
fullname,
71+
);
72+
73+
if (matchResult) {
74+
return matchResult[1];
75+
}
76+
77+
matchResult = new RegExp(`^(@[^/]+)/${prefix}-(.+)$`, "u").exec(
78+
fullname,
79+
);
80+
if (matchResult) {
81+
return `${matchResult[1]}/${matchResult[2]}`;
82+
}
83+
} else if (fullname.startsWith(`${prefix}-`)) {
84+
return fullname.slice(prefix.length + 1);
85+
}
86+
87+
return fullname;
88+
}
89+
90+
/**
91+
* Gets the scope (namespace) of a term.
92+
* @param {string} term The term which may have the namespace.
93+
* @returns {string} The namespace of the term if it has one.
94+
*/
95+
function getNamespaceFromTerm(term) {
96+
const match = term.match(NAMESPACE_REGEX);
97+
98+
return match ? match[0] : "";
99+
}
100+
101+
//------------------------------------------------------------------------------
102+
// Public Interface
103+
//------------------------------------------------------------------------------
104+
105+
module.exports = {
106+
normalizePackageName,
107+
getShorthandName,
108+
getNamespaceFromTerm,
109+
};
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* Utility for resolving a module relative to another module
3+
* @author Teddy Katz
4+
*/
5+
6+
"use strict";
7+
8+
const Module = require("node:module");
9+
10+
/*
11+
* `Module.createRequire` is added in v12.2.0. It supports URL as well.
12+
* We only support the case where the argument is a filepath, not a URL.
13+
*/
14+
const createRequire = Module.createRequire;
15+
16+
/**
17+
* Resolves a Node module relative to another module
18+
* @param {string} moduleName The name of a Node module, or a path to a Node module.
19+
* @param {string} relativeToPath An absolute path indicating the module that `moduleName` should be resolved relative to. This must be
20+
* a file rather than a directory, but the file need not actually exist.
21+
* @returns {string} The absolute path that would result from calling `require.resolve(moduleName)` in a file located at `relativeToPath`
22+
* @throws {Error} When the module cannot be resolved.
23+
*/
24+
function resolve(moduleName, relativeToPath) {
25+
return createRequire(relativeToPath).resolve(moduleName);
26+
}
27+
28+
exports.resolve = resolve;

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@
176176
"jiti": "^2.2.0",
177177
"jiti-v2.0": "npm:jiti@2.0.x",
178178
"jiti-v2.1": "npm:jiti@2.1.x",
179-
"knip": "^5.32.0",
179+
"knip": "^5.60.2",
180180
"lint-staged": "^11.0.0",
181181
"load-perf": "^0.2.0",
182182
"markdown-it": "^12.2.0",

tests/fixtures/relative-module-resolver/file2.js

Whitespace-only changes.

tests/lib/shared/naming.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* @fileoverview Tests for naming util
3+
*/
4+
5+
"use strict";
6+
7+
//------------------------------------------------------------------------------
8+
// Requirements
9+
//------------------------------------------------------------------------------
10+
11+
const { assert } = require("chai");
12+
const naming = require("../../../lib/shared/naming.js");
13+
14+
//------------------------------------------------------------------------------
15+
// Tests
16+
//------------------------------------------------------------------------------
17+
18+
describe("naming", () => {
19+
describe("normalizePackageName()", () => {
20+
[
21+
["foo", "eslint-config-foo"],
22+
["eslint-config-foo", "eslint-config-foo"],
23+
["@z/foo", "@z/eslint-config-foo"],
24+
["@z\\foo", "@z/eslint-config-foo"],
25+
["@z\\foo\\bar.js", "@z/eslint-config-foo/bar.js"],
26+
["@z/eslint-config", "@z/eslint-config"],
27+
["@z/eslint-config-foo", "@z/eslint-config-foo"],
28+
].forEach(([input, expected]) => {
29+
it(`should return ${expected} when passed ${input}`, () => {
30+
const result = naming.normalizePackageName(
31+
input,
32+
"eslint-config",
33+
);
34+
35+
assert.strictEqual(result, expected);
36+
});
37+
});
38+
});
39+
40+
describe("getShorthandName()", () => {
41+
[
42+
["foo", "foo"],
43+
["eslint-config-foo", "foo"],
44+
["@z", "@z"],
45+
["@z/eslint-config", "@z"],
46+
["@z/foo", "@z/foo"],
47+
["@z/eslint-config-foo", "@z/foo"],
48+
].forEach(([input, expected]) => {
49+
it(`should return ${expected} when passed ${input}`, () => {
50+
const result = naming.getShorthandName(input, "eslint-config");
51+
52+
assert.strictEqual(result, expected);
53+
});
54+
});
55+
});
56+
57+
describe("getNamespaceFromTerm()", () => {
58+
it("should remove namespace when passed with namespace", () => {
59+
const namespace = naming.getNamespaceFromTerm(
60+
"@namespace/eslint-plugin-test",
61+
);
62+
63+
assert.strictEqual(namespace, "@namespace/");
64+
});
65+
});
66+
});
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* @fileoverview Tests for relative module resolver.
3+
*/
4+
5+
"use strict";
6+
7+
const { assert } = require("chai");
8+
const path = require("node:path");
9+
const ModuleResolver = require("../../../lib/shared/relative-module-resolver.js");
10+
11+
describe("ModuleResolver", () => {
12+
describe("resolve()", () => {
13+
it("should correctly resolve a relative path", () => {
14+
assert.strictEqual(
15+
ModuleResolver.resolve(
16+
"./file2.js",
17+
path.resolve(
18+
"./tests/fixtures/relative-module-resolver/file.js",
19+
),
20+
),
21+
path.resolve(
22+
"./tests/fixtures/relative-module-resolver/file2.js",
23+
),
24+
);
25+
});
26+
});
27+
});

0 commit comments

Comments
 (0)