@emeryld/manager 1.4.6 → 1.4.8

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.
@@ -30,7 +30,7 @@ export function reportViolations(violations, reportingMode) {
30
30
  continue;
31
31
  entries.sort((a, b) => b.severity - a.severity);
32
32
  console.log(colors.bold(`- ${TYPE_LABELS[type]} (${entries.length})`));
33
- for (const entry of entries) {
33
+ for (const [idx, entry] of entries.entries()) {
34
34
  const relativePath = path.relative(rootDir, entry.file) || entry.file;
35
35
  const isDuplicate = entry.type === 'duplicateLine';
36
36
  const locationDescriptor = isDuplicate
@@ -42,6 +42,9 @@ export function reportViolations(violations, reportingMode) {
42
42
  : entry.line
43
43
  ? `${relativePath}:${entry.line}`
44
44
  : relativePath;
45
+ // Split entries with an empty line for readability (but not after the last entry in the group).
46
+ if (idx > 0)
47
+ console.log('');
45
48
  logViolationEntry(entry, isDuplicate ? ' ' : ' ', isDuplicate ? undefined : locationDescriptor);
46
49
  if (isDuplicate && entry.detail) {
47
50
  console.log(` ${colors.dim('Places:')}`);
@@ -72,13 +75,16 @@ export function reportViolations(violations, reportingMode) {
72
75
  const relativePath = path.relative(rootDir, file) || file;
73
76
  console.log(colors.bold(relativePath));
74
77
  const sortedEntries = [...entries].sort((a, b) => (a.line ?? 0) - (b.line ?? 0));
75
- for (const entry of sortedEntries) {
78
+ for (const [idx, entry] of sortedEntries.entries()) {
76
79
  const hasRangeDetail = entry.type !== 'duplicateLine' && Boolean(entry.detail);
77
80
  const locationDescriptor = hasRangeDetail
78
81
  ? `${relativePath}:${entry.detail}`
79
82
  : entry.line
80
83
  ? `${relativePath}:${entry.line}`
81
84
  : relativePath;
85
+ // Split entries with an empty line for readability (but not before the first entry).
86
+ if (idx > 0)
87
+ console.log('');
82
88
  if (entry.type === 'duplicateLine') {
83
89
  const occurrenceDescriptor = entry.line
84
90
  ? `${relativePath}:${entry.line}`
@@ -98,7 +104,6 @@ export function reportViolations(violations, reportingMode) {
98
104
  logViolationEntry(entry, ' ', locationDescriptor);
99
105
  }
100
106
  console.log('');
101
- console.log('');
102
107
  }
103
108
  }
104
109
  return true;
@@ -33,15 +33,14 @@ export function recordDuplicateLines(normalizedLines, filePath, limits, duplicat
33
33
  const slice = normalizedLines.slice(i, i + minLines);
34
34
  if (slice.some((entry) => !entry.normalized))
35
35
  continue;
36
- const key = slice.map((entry) => entry.normalized).join('\n');
37
- // Require at least one non-empty, non-punctuation-only line to consider this a meaningful duplicate.
38
- const meaningfulLineCount = slice.filter((entry) => entry.trimmed.length > 0 && !entry.isPunctuationOnly).length;
39
- if (meaningfulLineCount === 0)
40
- continue;
41
36
  if (slice.some((entry) => entry.isImport))
42
37
  continue;
43
- // Determine the first/last non-empty lines (we still include punctuation-only lines
44
- // inside that non-empty span when building the snippet).
38
+ // Punctuation-only lines should not count as a line for the minDuplicateLines threshold.
39
+ // i.e., we require >= minLines "real" lines (non-empty AND not punctuation-only).
40
+ const realLineCount = slice.filter((entry) => entry.trimmed.length > 0 && !entry.isPunctuationOnly).length;
41
+ if (realLineCount < minLines)
42
+ continue;
43
+ const key = slice.map((entry) => entry.normalized).join('\n');
45
44
  const firstNonEmptyIndex = slice.findIndex((entry) => entry.trimmed.length > 0);
46
45
  let lastNonEmptyIndex = -1;
47
46
  for (let offset = slice.length - 1; offset >= 0; offset -= 1) {
@@ -56,7 +55,7 @@ export function recordDuplicateLines(normalizedLines, filePath, limits, duplicat
56
55
  const endLine = i + 1 + lastNonEmptyIndex;
57
56
  const { startColumn } = getLineColumnRange(slice[firstNonEmptyIndex].raw);
58
57
  const { endColumn } = getLineColumnRange(slice[lastNonEmptyIndex].raw);
59
- // Keep real indentation in the reported snippet; remove trailing whitespace only.
58
+ // Keep punctuation-only lines inside the snippet, but keep indentation.
60
59
  const snippet = slice
61
60
  .slice(firstNonEmptyIndex, lastNonEmptyIndex + 1)
62
61
  .map((entry) => trimRightKeepIndent(entry.raw))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emeryld/manager",
3
- "version": "1.4.6",
3
+ "version": "1.4.8",
4
4
  "description": "Interactive manager for pnpm monorepos (update/test/build/publish).",
5
5
  "license": "MIT",
6
6
  "type": "module",