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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy