@codacy/tools-eslint-9 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +235 -98
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -39,6 +39,9 @@ var import_tooling2 = require("@codacy/tooling");
|
|
|
39
39
|
var import_tooling = require("@codacy/tooling");
|
|
40
40
|
var import_path3 = __toESM(require("path"));
|
|
41
41
|
var import_fs3 = __toESM(require("fs"));
|
|
42
|
+
var import_module = require("module");
|
|
43
|
+
var import_async_hooks = require("async_hooks");
|
|
44
|
+
var import_promises = require("timers/promises");
|
|
42
45
|
|
|
43
46
|
// src/patterns.json
|
|
44
47
|
var patterns_default = [
|
|
@@ -30662,7 +30665,27 @@ var descriptor = {
|
|
|
30662
30665
|
};
|
|
30663
30666
|
|
|
30664
30667
|
// src/adapter.ts
|
|
30668
|
+
var yieldToEventLoop = () => (0, import_promises.setTimeout)(0);
|
|
30665
30669
|
var TOOL_ID2 = "ESLint9";
|
|
30670
|
+
var ESLINT_MAX_FILE_SIZE_BYTES = 512 * 1024;
|
|
30671
|
+
var LINT_BATCH_SIZE = 50;
|
|
30672
|
+
var ESLINT_SKIP_DIRS = /* @__PURE__ */ new Set([".yarn", "vendor", ".next", ".nuxt"]);
|
|
30673
|
+
function shouldSkipFile(filePath, repositoryRoot) {
|
|
30674
|
+
const relPath = import_path3.default.relative(repositoryRoot, filePath).replace(/\\/g, "/");
|
|
30675
|
+
const segments = relPath.split("/");
|
|
30676
|
+
for (const seg of segments) {
|
|
30677
|
+
if (ESLINT_SKIP_DIRS.has(seg)) return `path contains skip directory "${seg}"`;
|
|
30678
|
+
}
|
|
30679
|
+
if (/\.min\.[cm]?[jt]sx?$/.test(import_path3.default.basename(filePath))) return "minified file";
|
|
30680
|
+
try {
|
|
30681
|
+
const stat = import_fs3.default.statSync(filePath);
|
|
30682
|
+
if (stat.size > ESLINT_MAX_FILE_SIZE_BYTES) {
|
|
30683
|
+
return `file size ${Math.round(stat.size / 1024)} KB exceeds ESLint limit`;
|
|
30684
|
+
}
|
|
30685
|
+
} catch {
|
|
30686
|
+
}
|
|
30687
|
+
return void 0;
|
|
30688
|
+
}
|
|
30666
30689
|
var LOCAL_CONFIG_FILES = [
|
|
30667
30690
|
"eslint.config.js",
|
|
30668
30691
|
"eslint.config.mjs",
|
|
@@ -30754,6 +30777,62 @@ function removeRulesByPluginFromFlatConfig(config, pluginPrefix) {
|
|
|
30754
30777
|
}
|
|
30755
30778
|
return removed;
|
|
30756
30779
|
}
|
|
30780
|
+
async function resolveProjectESLint(repositoryRoot) {
|
|
30781
|
+
try {
|
|
30782
|
+
const projectRequire = (0, import_module.createRequire)(import_path3.default.join(repositoryRoot, "__placeholder__.js"));
|
|
30783
|
+
const mod = projectRequire("eslint");
|
|
30784
|
+
const version = mod.ESLint?.version ?? "";
|
|
30785
|
+
const major = parseInt(version.split(".")[0], 10);
|
|
30786
|
+
if (major !== 9) return void 0;
|
|
30787
|
+
return { ESLintClass: mod.ESLint, version };
|
|
30788
|
+
} catch {
|
|
30789
|
+
return void 0;
|
|
30790
|
+
}
|
|
30791
|
+
}
|
|
30792
|
+
var consoleCaptureStorage = new import_async_hooks.AsyncLocalStorage();
|
|
30793
|
+
var consoleGlobalsPatched = false;
|
|
30794
|
+
function patchConsoleGlobals() {
|
|
30795
|
+
if (consoleGlobalsPatched) return;
|
|
30796
|
+
consoleGlobalsPatched = true;
|
|
30797
|
+
const origLog = console.log.bind(console);
|
|
30798
|
+
const origInfo = console.info.bind(console);
|
|
30799
|
+
const origWarn = console.warn.bind(console);
|
|
30800
|
+
const origError = console.error.bind(console);
|
|
30801
|
+
const origEmitWarning = process.emitWarning.bind(process);
|
|
30802
|
+
const intercept = (orig) => (...args) => {
|
|
30803
|
+
const sink = consoleCaptureStorage.getStore();
|
|
30804
|
+
if (!sink) {
|
|
30805
|
+
orig(...args);
|
|
30806
|
+
return;
|
|
30807
|
+
}
|
|
30808
|
+
const msg = args.map(String).join(" ").trim();
|
|
30809
|
+
if (msg) sink(msg);
|
|
30810
|
+
};
|
|
30811
|
+
console.log = intercept(origLog);
|
|
30812
|
+
console.info = intercept(origInfo);
|
|
30813
|
+
console.warn = intercept(origWarn);
|
|
30814
|
+
console.error = intercept(origError);
|
|
30815
|
+
process.emitWarning = ((warning, ...rest) => {
|
|
30816
|
+
const sink = consoleCaptureStorage.getStore();
|
|
30817
|
+
if (!sink) {
|
|
30818
|
+
origEmitWarning(warning, ...rest);
|
|
30819
|
+
return;
|
|
30820
|
+
}
|
|
30821
|
+
let msg = typeof warning === "string" ? warning : warning.message;
|
|
30822
|
+
let type = typeof rest[0] === "string" ? rest[0] : void 0;
|
|
30823
|
+
if (rest[0] && typeof rest[0] === "object") {
|
|
30824
|
+
const opts = rest[0];
|
|
30825
|
+
if (opts.type) type = opts.type;
|
|
30826
|
+
if (opts.detail) msg += ` - ${opts.detail}`;
|
|
30827
|
+
}
|
|
30828
|
+
if (!type && warning instanceof Error) type = warning.name;
|
|
30829
|
+
sink(type ? `${type}: ${msg}` : msg);
|
|
30830
|
+
});
|
|
30831
|
+
}
|
|
30832
|
+
async function withCapturedConsole(fn, onMessage) {
|
|
30833
|
+
patchConsoleGlobals();
|
|
30834
|
+
return consoleCaptureStorage.run(onMessage, fn);
|
|
30835
|
+
}
|
|
30757
30836
|
var adapter = {
|
|
30758
30837
|
...descriptor,
|
|
30759
30838
|
patternsMetadata: patterns_default,
|
|
@@ -30818,7 +30897,25 @@ var adapter = {
|
|
|
30818
30897
|
const startedAt = /* @__PURE__ */ new Date();
|
|
30819
30898
|
const issues = [];
|
|
30820
30899
|
const errors = [];
|
|
30821
|
-
const
|
|
30900
|
+
const allAbsoluteFiles = ctx.targetFiles.map((f) => import_path3.default.resolve(ctx.repositoryRoot, f));
|
|
30901
|
+
const absoluteFiles = [];
|
|
30902
|
+
for (const f of allAbsoluteFiles) {
|
|
30903
|
+
const skipReason = shouldSkipFile(f, ctx.repositoryRoot);
|
|
30904
|
+
if (skipReason) {
|
|
30905
|
+
const relPath = import_path3.default.relative(ctx.repositoryRoot, f);
|
|
30906
|
+
ctx.logger.debug("Skipping file", { toolId: TOOL_ID2, file: relPath, reason: skipReason });
|
|
30907
|
+
} else {
|
|
30908
|
+
absoluteFiles.push(f);
|
|
30909
|
+
}
|
|
30910
|
+
}
|
|
30911
|
+
if (absoluteFiles.length < allAbsoluteFiles.length) {
|
|
30912
|
+
const skipped = allAbsoluteFiles.length - absoluteFiles.length;
|
|
30913
|
+
ctx.logger.info("Skipped oversized/generated files", {
|
|
30914
|
+
toolId: TOOL_ID2,
|
|
30915
|
+
skipped,
|
|
30916
|
+
remaining: absoluteFiles.length
|
|
30917
|
+
});
|
|
30918
|
+
}
|
|
30822
30919
|
if (absoluteFiles.length === 0) {
|
|
30823
30920
|
const completedAt2 = /* @__PURE__ */ new Date();
|
|
30824
30921
|
return (0, import_tooling.buildResult)(TOOL_ID2, startedAt, completedAt2, issues, errors, ctx.targetFiles.length);
|
|
@@ -30840,7 +30937,16 @@ var adapter = {
|
|
|
30840
30937
|
}
|
|
30841
30938
|
const eslintOptions = { cwd: ctx.repositoryRoot };
|
|
30842
30939
|
if (codacyConfig.useLocalConfigurationFile && codacyConfig.localConfigurationFile) {
|
|
30843
|
-
|
|
30940
|
+
const projectESLint = await resolveProjectESLint(ctx.repositoryRoot);
|
|
30941
|
+
if (projectESLint) {
|
|
30942
|
+
ESLintClass = projectESLint.ESLintClass;
|
|
30943
|
+
ctx.logger.info("Using project ESLint", {
|
|
30944
|
+
toolId: TOOL_ID2,
|
|
30945
|
+
version: projectESLint.version
|
|
30946
|
+
});
|
|
30947
|
+
} else {
|
|
30948
|
+
eslintOptions.overrideConfigFile = codacyConfig.localConfigurationFile;
|
|
30949
|
+
}
|
|
30844
30950
|
} else if (codacyConfig.patterns.length > 0) {
|
|
30845
30951
|
const buildStartMs = Date.now();
|
|
30846
30952
|
try {
|
|
@@ -30876,117 +30982,148 @@ var adapter = {
|
|
|
30876
30982
|
let attempt = 0;
|
|
30877
30983
|
let results = [];
|
|
30878
30984
|
try {
|
|
30879
|
-
const
|
|
30880
|
-
|
|
30881
|
-
|
|
30882
|
-
|
|
30883
|
-
|
|
30884
|
-
|
|
30885
|
-
|
|
30886
|
-
|
|
30887
|
-
|
|
30888
|
-
|
|
30889
|
-
|
|
30890
|
-
|
|
30891
|
-
|
|
30892
|
-
|
|
30893
|
-
|
|
30894
|
-
const
|
|
30895
|
-
|
|
30896
|
-
|
|
30897
|
-
|
|
30898
|
-
|
|
30899
|
-
|
|
30900
|
-
|
|
30901
|
-
|
|
30902
|
-
|
|
30903
|
-
|
|
30904
|
-
|
|
30905
|
-
|
|
30906
|
-
|
|
30907
|
-
|
|
30908
|
-
|
|
30909
|
-
|
|
30910
|
-
|
|
30911
|
-
|
|
30912
|
-
|
|
30985
|
+
const capturedMessages = [];
|
|
30986
|
+
results = await withCapturedConsole(
|
|
30987
|
+
async () => {
|
|
30988
|
+
let lintResults = [];
|
|
30989
|
+
const probeStartMs = Date.now();
|
|
30990
|
+
let lastProbeFailure;
|
|
30991
|
+
ctx.onProgress?.("Validating config");
|
|
30992
|
+
while (attempt <= MAX_CONFIG_RETRIES) {
|
|
30993
|
+
const probeEslint = new ESLintClass(eslintOptions);
|
|
30994
|
+
const failure = await probeConfig(probeEslint, ctx.repositoryRoot);
|
|
30995
|
+
if (!failure) {
|
|
30996
|
+
lastProbeFailure = void 0;
|
|
30997
|
+
break;
|
|
30998
|
+
}
|
|
30999
|
+
lastProbeFailure = failure;
|
|
31000
|
+
const rule = extractInvalidRule(failure.message);
|
|
31001
|
+
if (!rule) throw failure;
|
|
31002
|
+
if (isParserServicesError(failure.message)) {
|
|
31003
|
+
const prefix = rulePluginPrefix(rule);
|
|
31004
|
+
if (prefix) {
|
|
31005
|
+
const removedRules = removeRulesByPluginFromFlatConfig(
|
|
31006
|
+
eslintOptions.overrideConfig,
|
|
31007
|
+
prefix
|
|
31008
|
+
);
|
|
31009
|
+
if (removedRules.length > 0) {
|
|
31010
|
+
ctx.logger.warn("Skipping plugin requiring parserServices", {
|
|
31011
|
+
toolId: TOOL_ID2,
|
|
31012
|
+
plugin: prefix,
|
|
31013
|
+
count: removedRules.length
|
|
31014
|
+
});
|
|
31015
|
+
errors.push({
|
|
31016
|
+
toolId: TOOL_ID2,
|
|
31017
|
+
phase: "toolConfig",
|
|
31018
|
+
kind: "InvalidRuleConfig",
|
|
31019
|
+
message: `Plugin "${prefix}/*" (${removedRules.length} rule${removedRules.length === 1 ? "" : "s"}) skipped: requires typescript-eslint parserServices (no tsconfig.json in the analysed repo).`,
|
|
31020
|
+
level: "warning"
|
|
31021
|
+
});
|
|
31022
|
+
attempt++;
|
|
31023
|
+
continue;
|
|
31024
|
+
}
|
|
31025
|
+
}
|
|
30913
31026
|
}
|
|
31027
|
+
const removed = removeRuleFromFlatConfig(eslintOptions.overrideConfig, rule);
|
|
31028
|
+
if (!removed) throw failure;
|
|
31029
|
+
ctx.logger.warn("Skipping rule rejected during probe", { toolId: TOOL_ID2, rule });
|
|
31030
|
+
errors.push({
|
|
31031
|
+
toolId: TOOL_ID2,
|
|
31032
|
+
phase: "toolConfig",
|
|
31033
|
+
kind: "InvalidRuleConfig",
|
|
31034
|
+
message: `Rule "${rule}" was skipped: ${truncateForError(failure.message)}`,
|
|
31035
|
+
level: "warning"
|
|
31036
|
+
});
|
|
31037
|
+
attempt++;
|
|
30914
31038
|
}
|
|
30915
|
-
|
|
30916
|
-
const removed = removeRuleFromFlatConfig(eslintOptions.overrideConfig, rule);
|
|
30917
|
-
if (!removed) throw failure;
|
|
30918
|
-
ctx.logger.warn("Skipping rule rejected during probe", { toolId: TOOL_ID2, rule });
|
|
30919
|
-
errors.push({
|
|
30920
|
-
toolId: TOOL_ID2,
|
|
30921
|
-
phase: "toolConfig",
|
|
30922
|
-
kind: "InvalidRuleConfig",
|
|
30923
|
-
message: `Rule "${rule}" was skipped: ${truncateForError(failure.message)}`,
|
|
30924
|
-
level: "warning"
|
|
30925
|
-
});
|
|
30926
|
-
attempt++;
|
|
30927
|
-
}
|
|
30928
|
-
ctx.logger.debug("Config probe complete", {
|
|
30929
|
-
toolId: TOOL_ID2,
|
|
30930
|
-
durationMs: Date.now() - probeStartMs,
|
|
30931
|
-
rulesSkipped: attempt
|
|
30932
|
-
});
|
|
30933
|
-
if (lastProbeFailure) throw lastProbeFailure;
|
|
30934
|
-
while (true) {
|
|
30935
|
-
try {
|
|
30936
|
-
const instantiateStartMs = Date.now();
|
|
30937
|
-
const eslint = new ESLintClass(eslintOptions);
|
|
30938
|
-
ctx.logger.debug("ESLint instance created", {
|
|
31039
|
+
ctx.logger.debug("Config probe complete", {
|
|
30939
31040
|
toolId: TOOL_ID2,
|
|
30940
|
-
durationMs: Date.now() -
|
|
31041
|
+
durationMs: Date.now() - probeStartMs,
|
|
31042
|
+
rulesSkipped: attempt
|
|
30941
31043
|
});
|
|
30942
|
-
|
|
30943
|
-
|
|
30944
|
-
|
|
30945
|
-
|
|
30946
|
-
|
|
30947
|
-
|
|
30948
|
-
|
|
30949
|
-
|
|
30950
|
-
|
|
30951
|
-
|
|
30952
|
-
|
|
30953
|
-
|
|
30954
|
-
|
|
30955
|
-
|
|
30956
|
-
|
|
30957
|
-
|
|
30958
|
-
|
|
30959
|
-
|
|
30960
|
-
|
|
30961
|
-
|
|
30962
|
-
|
|
30963
|
-
|
|
30964
|
-
|
|
30965
|
-
|
|
31044
|
+
if (lastProbeFailure) throw lastProbeFailure;
|
|
31045
|
+
ctx.onProgress?.(`Preparing to lint ${absoluteFiles.length} files`);
|
|
31046
|
+
while (true) {
|
|
31047
|
+
try {
|
|
31048
|
+
const instantiateStartMs = Date.now();
|
|
31049
|
+
const eslint = new ESLintClass(eslintOptions);
|
|
31050
|
+
ctx.logger.debug("ESLint instance created", {
|
|
31051
|
+
toolId: TOOL_ID2,
|
|
31052
|
+
durationMs: Date.now() - instantiateStartMs
|
|
31053
|
+
});
|
|
31054
|
+
const lintStartMs = Date.now();
|
|
31055
|
+
if (absoluteFiles.length <= LINT_BATCH_SIZE) {
|
|
31056
|
+
lintResults = await eslint.lintFiles(absoluteFiles);
|
|
31057
|
+
} else {
|
|
31058
|
+
lintResults = [];
|
|
31059
|
+
for (let i = 0; i < absoluteFiles.length; i += LINT_BATCH_SIZE) {
|
|
31060
|
+
const batch = absoluteFiles.slice(i, i + LINT_BATCH_SIZE);
|
|
31061
|
+
const batchResults = await eslint.lintFiles(batch);
|
|
31062
|
+
lintResults.push(...batchResults);
|
|
31063
|
+
const processed = Math.min(i + LINT_BATCH_SIZE, absoluteFiles.length);
|
|
31064
|
+
ctx.onProgress?.(`Linting files ${processed}/${absoluteFiles.length}`);
|
|
31065
|
+
await yieldToEventLoop();
|
|
31066
|
+
}
|
|
31067
|
+
}
|
|
31068
|
+
ctx.logger.debug("lintFiles() complete", {
|
|
31069
|
+
toolId: TOOL_ID2,
|
|
31070
|
+
durationMs: Date.now() - lintStartMs,
|
|
31071
|
+
fileCount: lintResults.length
|
|
31072
|
+
});
|
|
31073
|
+
break;
|
|
31074
|
+
} catch (err) {
|
|
31075
|
+
const rule = err instanceof Error ? extractInvalidRule(err.message) : void 0;
|
|
31076
|
+
if (!rule || attempt >= MAX_CONFIG_RETRIES) throw err;
|
|
31077
|
+
const parserServicesCause = err instanceof Error && isParserServicesError(err.message);
|
|
31078
|
+
const prefix = rulePluginPrefix(rule);
|
|
31079
|
+
if (prefix) {
|
|
31080
|
+
const removedRules = removeRulesByPluginFromFlatConfig(
|
|
31081
|
+
eslintOptions.overrideConfig,
|
|
31082
|
+
prefix
|
|
31083
|
+
);
|
|
31084
|
+
if (removedRules.length > 0) {
|
|
31085
|
+
const message = parserServicesCause ? `Plugin "${prefix}/*" (${removedRules.length} rule${removedRules.length === 1 ? "" : "s"}) skipped: requires typescript-eslint parserServices (no tsconfig.json / tsconfig.base.json / tsconfig.eslint.json / jsconfig.json found at the repository root).` : `Plugin "${prefix}/*" (${removedRules.length} rule${removedRules.length === 1 ? "" : "s"}) skipped after lintFiles failure on "${rule}": ${truncateForError(err instanceof Error ? err.message : String(err))}`;
|
|
31086
|
+
ctx.logger.warn(
|
|
31087
|
+
parserServicesCause ? "Skipping plugin requiring parserServices" : "Skipping plugin that failed during lintFiles",
|
|
31088
|
+
{ toolId: TOOL_ID2, plugin: prefix, count: removedRules.length, rule }
|
|
31089
|
+
);
|
|
31090
|
+
errors.push({
|
|
31091
|
+
toolId: TOOL_ID2,
|
|
31092
|
+
phase: "toolConfig",
|
|
31093
|
+
kind: "InvalidRuleConfig",
|
|
31094
|
+
message,
|
|
31095
|
+
level: "warning"
|
|
31096
|
+
});
|
|
31097
|
+
attempt++;
|
|
31098
|
+
continue;
|
|
31099
|
+
}
|
|
31100
|
+
}
|
|
31101
|
+
const removed = removeRuleFromFlatConfig(eslintOptions.overrideConfig, rule);
|
|
31102
|
+
if (!removed) throw err;
|
|
31103
|
+
ctx.logger.warn("Skipping rule that failed during lintFiles", {
|
|
31104
|
+
toolId: TOOL_ID2,
|
|
31105
|
+
rule
|
|
31106
|
+
});
|
|
30966
31107
|
errors.push({
|
|
30967
31108
|
toolId: TOOL_ID2,
|
|
30968
31109
|
phase: "toolConfig",
|
|
30969
31110
|
kind: "InvalidRuleConfig",
|
|
30970
|
-
message
|
|
31111
|
+
message: `Rule "${rule}" was skipped after lintFiles failure: ${truncateForError(err instanceof Error ? err.message : String(err))}`,
|
|
30971
31112
|
level: "warning"
|
|
30972
31113
|
});
|
|
30973
31114
|
attempt++;
|
|
30974
|
-
continue;
|
|
30975
31115
|
}
|
|
30976
31116
|
}
|
|
30977
|
-
|
|
30978
|
-
|
|
30979
|
-
|
|
30980
|
-
|
|
30981
|
-
toolId: TOOL_ID2,
|
|
30982
|
-
phase: "toolConfig",
|
|
30983
|
-
kind: "InvalidRuleConfig",
|
|
30984
|
-
message: `Rule "${rule}" was skipped after lintFiles failure: ${truncateForError(err instanceof Error ? err.message : String(err))}`,
|
|
30985
|
-
level: "warning"
|
|
30986
|
-
});
|
|
30987
|
-
attempt++;
|
|
31117
|
+
return lintResults;
|
|
31118
|
+
},
|
|
31119
|
+
(msg) => {
|
|
31120
|
+
capturedMessages.push(msg);
|
|
30988
31121
|
}
|
|
31122
|
+
);
|
|
31123
|
+
for (const msg of capturedMessages) {
|
|
31124
|
+
ctx.logger.warn("ESLint plugin output", { toolId: TOOL_ID2, detail: msg });
|
|
30989
31125
|
}
|
|
31126
|
+
ctx.onProgress?.(`Processing results from ${results.length} files`);
|
|
30990
31127
|
for (const fileResult of results) {
|
|
30991
31128
|
if (fileResult.messages.length === 0) continue;
|
|
30992
31129
|
const relPath = import_path3.default.relative(ctx.repositoryRoot, fileResult.filePath);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codacy/tools-eslint-9",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "ESLint 9 adapter — Library-mode JavaScript/TypeScript linter",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"eslint-plugin-wdio": "^9.0.0",
|
|
80
80
|
"eslint-plugin-xss": "^0.1.0",
|
|
81
81
|
"eslint-plugin-yml": "^1.0.0",
|
|
82
|
-
"@codacy/tooling": "0.
|
|
82
|
+
"@codacy/tooling": "0.9.0"
|
|
83
83
|
},
|
|
84
84
|
"license": "MIT",
|
|
85
85
|
"author": "Codacy <support@codacy.com> (https://www.codacy.com)",
|