@emeryld/manager 1.4.2 → 1.4.4
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.
|
@@ -23,12 +23,18 @@ export function reportViolations(violations, reportingMode) {
|
|
|
23
23
|
return false;
|
|
24
24
|
}
|
|
25
25
|
console.log(colors.bold('Format checker violations:'));
|
|
26
|
+
console.log('');
|
|
26
27
|
if (reportingMode === 'group') {
|
|
28
|
+
let hasPrintedGroupBlock = false;
|
|
27
29
|
for (const type of TYPE_ORDER) {
|
|
28
30
|
const entries = violations.filter((violation) => violation.type === type);
|
|
29
31
|
if (!entries.length)
|
|
30
32
|
continue;
|
|
31
33
|
entries.sort((a, b) => b.severity - a.severity);
|
|
34
|
+
if (hasPrintedGroupBlock) {
|
|
35
|
+
console.log('');
|
|
36
|
+
}
|
|
37
|
+
hasPrintedGroupBlock = true;
|
|
32
38
|
console.log(colors.bold(`- ${TYPE_LABELS[type]} (${entries.length})`));
|
|
33
39
|
for (const entry of entries) {
|
|
34
40
|
const relativePath = path.relative(rootDir, entry.file) || entry.file;
|
|
@@ -53,10 +59,10 @@ export function reportViolations(violations, reportingMode) {
|
|
|
53
59
|
});
|
|
54
60
|
}
|
|
55
61
|
}
|
|
56
|
-
console.log('');
|
|
57
62
|
}
|
|
58
63
|
}
|
|
59
64
|
else {
|
|
65
|
+
let hasPrintedFileBlock = false;
|
|
60
66
|
const violationsByFile = new Map();
|
|
61
67
|
for (const entry of violations) {
|
|
62
68
|
const bucket = violationsByFile.get(entry.file);
|
|
@@ -70,6 +76,10 @@ export function reportViolations(violations, reportingMode) {
|
|
|
70
76
|
const sortedFiles = [...violationsByFile.entries()].sort(([a], [b]) => a.localeCompare(b));
|
|
71
77
|
for (const [file, entries] of sortedFiles) {
|
|
72
78
|
const relativePath = path.relative(rootDir, file) || file;
|
|
79
|
+
if (hasPrintedFileBlock) {
|
|
80
|
+
console.log('');
|
|
81
|
+
}
|
|
82
|
+
hasPrintedFileBlock = true;
|
|
73
83
|
console.log(colors.bold(relativePath));
|
|
74
84
|
const sortedEntries = [...entries].sort((a, b) => (a.line ?? 0) - (b.line ?? 0));
|
|
75
85
|
for (const entry of sortedEntries) {
|
|
@@ -97,7 +107,6 @@ export function reportViolations(violations, reportingMode) {
|
|
|
97
107
|
}
|
|
98
108
|
logViolationEntry(entry, ' ', locationDescriptor);
|
|
99
109
|
}
|
|
100
|
-
console.log('');
|
|
101
110
|
}
|
|
102
111
|
}
|
|
103
112
|
return true;
|
|
@@ -205,26 +205,33 @@ function formatOccurrenceDetail(info) {
|
|
|
205
205
|
}
|
|
206
206
|
export function collectDuplicateViolations(duplicates, limits, fileSnapshots) {
|
|
207
207
|
const violations = [];
|
|
208
|
+
const seenDuplicateKeys = new Set();
|
|
208
209
|
for (const tracker of duplicates.values()) {
|
|
209
210
|
if (tracker.count <= limits.maxDuplicateLineOccurrences)
|
|
210
211
|
continue;
|
|
211
212
|
if (tracker.occurrences.length === 0)
|
|
212
213
|
continue;
|
|
213
214
|
const expanded = expandDuplicateTracker(tracker, fileSnapshots);
|
|
215
|
+
const defaultDetail = tracker.occurrences
|
|
216
|
+
.map((occurrence) => {
|
|
217
|
+
const relativePath = path.relative(process.cwd(), occurrence.file);
|
|
218
|
+
return `${relativePath}:${occurrence.line}:${occurrence.startColumn}/${occurrence.endLine}:${occurrence.endColumn}`;
|
|
219
|
+
})
|
|
220
|
+
.join('\n');
|
|
221
|
+
const detailText = expanded?.detail ?? defaultDetail;
|
|
222
|
+
const snippetText = expanded?.snippet ?? tracker.snippet;
|
|
223
|
+
const dedupKey = `${snippetText}::${detailText}`;
|
|
224
|
+
if (seenDuplicateKeys.has(dedupKey))
|
|
225
|
+
continue;
|
|
226
|
+
seenDuplicateKeys.add(dedupKey);
|
|
214
227
|
violations.push({
|
|
215
228
|
type: 'duplicateLine',
|
|
216
229
|
file: tracker.occurrences[0].file,
|
|
217
230
|
line: tracker.occurrences[0].line,
|
|
218
231
|
severity: tracker.count - limits.maxDuplicateLineOccurrences,
|
|
219
232
|
message: `Repeated ${tracker.count} times (max ${limits.maxDuplicateLineOccurrences})`,
|
|
220
|
-
detail:
|
|
221
|
-
|
|
222
|
-
.map((occurrence) => {
|
|
223
|
-
const relativePath = path.relative(process.cwd(), occurrence.file);
|
|
224
|
-
return `${relativePath}:${occurrence.line}:${occurrence.startColumn}/${occurrence.endLine}:${occurrence.endColumn}`;
|
|
225
|
-
})
|
|
226
|
-
.join('\n'),
|
|
227
|
-
snippet: expanded?.snippet ?? tracker.snippet,
|
|
233
|
+
detail: detailText,
|
|
234
|
+
snippet: snippetText,
|
|
228
235
|
repeatCount: tracker.count,
|
|
229
236
|
requiredVariables: expanded?.requiredVariables ?? tracker.requiredVariables,
|
|
230
237
|
});
|
|
@@ -4,9 +4,9 @@ export function normalizeLine(line) {
|
|
|
4
4
|
const trimmed = line.trim();
|
|
5
5
|
if (!trimmed)
|
|
6
6
|
return undefined;
|
|
7
|
+
if (/^[};()]+$/.test(trimmed))
|
|
8
|
+
return undefined;
|
|
7
9
|
const collapse = trimmed.replace(/\s+/g, ' ');
|
|
8
|
-
const letterCount = (collapse.match(/[A-Za-z]/g) ?? []).length;
|
|
9
|
-
// if (collapse.length < 12 && letterCount < 3) return undefined
|
|
10
10
|
const noNumbers = collapse.replace(/\d+/g, '#');
|
|
11
11
|
return noNumbers.toLowerCase();
|
|
12
12
|
}
|