-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathtransform.ts
More file actions
104 lines (96 loc) · 3 KB
/
Copy pathtransform.ts
File metadata and controls
104 lines (96 loc) · 3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import type { Linter } from 'eslint';
import type { AuditOutput, Issue, IssueSeverity } from '@code-pushup/models';
import {
compareIssueSeverity,
countOccurrences,
logger,
objectToEntries,
pluralizeToken,
truncateIssueMessage,
} from '@code-pushup/utils';
import { ruleIdToSlug } from '../meta/index.js';
import type { LinterOutput } from './types.js';
type LintIssue = Linter.LintMessage & {
filePath: string;
};
export function mergeLinterOutputs(outputs: LinterOutput[]): LinterOutput {
return outputs.reduce<LinterOutput>(
(acc, { results, ruleOptionsPerFile }) => ({
results: [...acc.results, ...results],
ruleOptionsPerFile: { ...acc.ruleOptionsPerFile, ...ruleOptionsPerFile },
}),
{ results: [], ruleOptionsPerFile: {} },
);
}
export function lintResultsToAudits({
results,
ruleOptionsPerFile,
}: LinterOutput): AuditOutput[] {
const issuesPerAudit = results
.flatMap(({ messages, filePath }) =>
messages.map((message): LintIssue => ({ ...message, filePath })),
)
.reduce<Record<string, LintIssue[]>>((acc, issue) => {
const { ruleId, message, filePath } = issue;
if (!ruleId) {
logger.warn(`ESLint core error - ${message} (file: ${filePath})`);
return acc;
}
const options = ruleOptionsPerFile[filePath]?.[ruleId] ?? [];
const auditSlug = ruleIdToSlug(ruleId, options);
return { ...acc, [auditSlug]: [...(acc[auditSlug] ?? []), issue] };
}, {});
return Object.entries(issuesPerAudit).map(entry => toAudit(...entry));
}
function toAudit(slug: string, issues: LintIssue[]): AuditOutput {
const auditIssues = issues.map(convertIssue);
const severityCounts = countOccurrences(
auditIssues.map(({ severity }) => severity),
);
const severities = objectToEntries(severityCounts);
const summaryText = severities
.toSorted((a, b) => -compareIssueSeverity(a[0], b[0]))
.map(([severity, count = 0]) => pluralizeToken(severity, count))
.join(', ');
return {
slug,
score: Number(auditIssues.length === 0),
value: auditIssues.length,
displayValue: summaryText,
details: {
issues: auditIssues,
},
};
}
function convertIssue(issue: LintIssue): Issue {
return {
message: truncateIssueMessage(issue.message),
severity: convertSeverity(issue.severity),
source: {
file: issue.filePath,
...(issue.line > 0 && {
position: {
startLine: issue.line,
...(issue.column > 0 && { startColumn: issue.column }),
...(issue.endLine &&
issue.endLine > 0 && {
endLine: issue.endLine,
}),
...(issue.endColumn &&
issue.endColumn > 0 && { endColumn: issue.endColumn }),
},
}),
},
};
}
function convertSeverity(severity: Linter.Severity): IssueSeverity {
switch (severity) {
case 2:
return 'error';
case 1:
return 'warning';
case 0:
// shouldn't happen
throw new Error(`Unexpected severity ${severity} in ESLint results`);
}
}