@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.
@@ -10,7 +10,7 @@ export const DEFAULT_LIMITS = {
10
10
  maxFunctionsPerFile: 25,
11
11
  maxComponentsPerFile: 8,
12
12
  maxFileLength: 500,
13
- maxDuplicateLineOccurrences: 3,
13
+ maxDuplicateLineOccurrences: 1,
14
14
  minDuplicateLines: 3,
15
15
  exportOnly: true,
16
16
  indentationWidth: 2,
@@ -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: expanded?.detail ??
221
- tracker.occurrences
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emeryld/manager",
3
- "version": "1.4.2",
3
+ "version": "1.4.4",
4
4
  "description": "Interactive manager for pnpm monorepos (update/test/build/publish).",
5
5
  "license": "MIT",
6
6
  "type": "module",