@eslint-config-snapshot/cli 1.3.0 โ†’ 1.3.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @eslint-config-snapshot/cli
2
2
 
3
+ ## 1.3.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Improve catalog check/update summaries and dedupe baseline totals across groups.
8
+ - Updated dependencies
9
+ - @eslint-config-snapshot/api@1.3.1
10
+
3
11
  ## 1.3.0
4
12
 
5
13
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -102,7 +102,7 @@ function summarizeChanges(changes) {
102
102
  return { introduced, removed, severity, options, workspace };
103
103
  }
104
104
  function summarizeSnapshots(snapshots) {
105
- const { rules, error, warn, off } = countRuleSeverities([...snapshots.values()].map((snapshot) => snapshot.rules));
105
+ const { rules, error, warn, off } = countUniqueRuleSeverities([...snapshots.values()].map((snapshot) => snapshot.rules));
106
106
  return { groups: snapshots.size, rules, error, warn, off };
107
107
  }
108
108
  function countUniqueWorkspaces(snapshots) {
@@ -276,25 +276,34 @@ function formatBaselineSummaryLines(summary, workspaceCount) {
276
276
  - \u{1F39A}\uFE0F severity mix: ${summary.error} errors, ${summary.warn} warnings, ${summary.off} off
277
277
  `;
278
278
  }
279
- function countRuleSeverities(ruleObjects) {
280
- let rules = 0;
279
+ function countUniqueRuleSeverities(ruleObjects) {
280
+ const severityRank = { off: 0, warn: 1, error: 2 };
281
+ const severityByRule = /* @__PURE__ */ new Map();
282
+ for (const rulesObject of ruleObjects) {
283
+ for (const [ruleName, entry] of Object.entries(rulesObject)) {
284
+ const nextSeverity = getPrimarySeverity(entry);
285
+ if (!nextSeverity) {
286
+ continue;
287
+ }
288
+ const currentSeverity = severityByRule.get(ruleName);
289
+ if (!currentSeverity || severityRank[nextSeverity] > severityRank[currentSeverity]) {
290
+ severityByRule.set(ruleName, nextSeverity);
291
+ }
292
+ }
293
+ }
281
294
  let error = 0;
282
295
  let warn = 0;
283
296
  let off = 0;
284
- for (const rulesObject of ruleObjects) {
285
- for (const entry of Object.values(rulesObject)) {
286
- rules += 1;
287
- const severity = getPrimarySeverity(entry);
288
- if (severity === "error") {
289
- error += 1;
290
- } else if (severity === "warn") {
291
- warn += 1;
292
- } else {
293
- off += 1;
294
- }
297
+ for (const severity of severityByRule.values()) {
298
+ if (severity === "error") {
299
+ error += 1;
300
+ } else if (severity === "warn") {
301
+ warn += 1;
302
+ } else {
303
+ off += 1;
295
304
  }
296
305
  }
297
- return { rules, error, warn, off };
306
+ return { rules: severityByRule.size, error, warn, off };
298
307
  }
299
308
  function getPrimarySeverity(entry) {
300
309
  if (!entry) {
@@ -871,10 +880,12 @@ async function executeCatalogUpdate(cwd, terminal, snapshotDir) {
871
880
  const rows = await computeCatalogRows(cwd, terminal, snapshotDir, "catalog:update", false);
872
881
  await writeCatalogBaselineFiles(cwd, snapshotDir, rows);
873
882
  const groups = rows.length;
874
- const available = rows.reduce((sum, row) => sum + row.totalStats.totalAvailable, 0);
875
- const inUse = rows.reduce((sum, row) => sum + row.totalStats.inUse, 0);
883
+ const available = countUniqueRules(rows.map((row) => row.availableRules));
884
+ const inUse = countUniqueRules(rows.map((row) => row.observedRules.filter((ruleName) => row.availableRules.includes(ruleName))));
876
885
  terminal.write(`\u{1F9EA} Catalog baseline updated: ${groups} groups, ${available} available rules, ${inUse} currently in use.
877
886
  `);
887
+ terminal.section("\u{1F4CA} Catalog summary");
888
+ terminal.write(formatShortCatalog(rows, false));
878
889
  return 0;
879
890
  }
880
891
  async function executeCatalogCheck(cwd, terminal, snapshotDir) {
@@ -889,8 +900,12 @@ async function executeCatalogCheck(cwd, terminal, snapshotDir) {
889
900
  const diffs = compareCatalogBaselines(stored, current);
890
901
  if (diffs.length === 0) {
891
902
  terminal.write("Great news: no catalog drift detected.\n");
903
+ terminal.section("\u{1F4CA} Catalog summary");
904
+ terminal.write(formatShortCatalog(rows, false));
892
905
  return 0;
893
906
  }
907
+ terminal.section("\u{1F4CA} Catalog summary");
908
+ terminal.write(formatShortCatalog(rows, false));
894
909
  terminal.write(`\u26A0\uFE0F Heads up: catalog drift detected in ${diffs.length} groups.
895
910
  `);
896
911
  for (const diff of diffs) {
@@ -1131,6 +1146,15 @@ function toPercent(value, total) {
1131
1146
  }
1132
1147
  return Number((value / total * 100).toFixed(1));
1133
1148
  }
1149
+ function countUniqueRules(ruleLists) {
1150
+ const unique = /* @__PURE__ */ new Set();
1151
+ for (const rules of ruleLists) {
1152
+ for (const rule of rules) {
1153
+ unique.add(rule);
1154
+ }
1155
+ }
1156
+ return unique.size;
1157
+ }
1134
1158
 
1135
1159
  // src/commands/check.ts
1136
1160
  var UPDATE_HINT = "Tip: when you intentionally accept changes, run `eslint-config-snapshot --update` to refresh the baseline.\n";
package/dist/index.js CHANGED
@@ -67,7 +67,7 @@ function summarizeChanges(changes) {
67
67
  return { introduced, removed, severity, options, workspace };
68
68
  }
69
69
  function summarizeSnapshots(snapshots) {
70
- const { rules, error, warn, off } = countRuleSeverities([...snapshots.values()].map((snapshot) => snapshot.rules));
70
+ const { rules, error, warn, off } = countUniqueRuleSeverities([...snapshots.values()].map((snapshot) => snapshot.rules));
71
71
  return { groups: snapshots.size, rules, error, warn, off };
72
72
  }
73
73
  function countUniqueWorkspaces(snapshots) {
@@ -241,25 +241,34 @@ function formatBaselineSummaryLines(summary, workspaceCount) {
241
241
  - \u{1F39A}\uFE0F severity mix: ${summary.error} errors, ${summary.warn} warnings, ${summary.off} off
242
242
  `;
243
243
  }
244
- function countRuleSeverities(ruleObjects) {
245
- let rules = 0;
244
+ function countUniqueRuleSeverities(ruleObjects) {
245
+ const severityRank = { off: 0, warn: 1, error: 2 };
246
+ const severityByRule = /* @__PURE__ */ new Map();
247
+ for (const rulesObject of ruleObjects) {
248
+ for (const [ruleName, entry] of Object.entries(rulesObject)) {
249
+ const nextSeverity = getPrimarySeverity(entry);
250
+ if (!nextSeverity) {
251
+ continue;
252
+ }
253
+ const currentSeverity = severityByRule.get(ruleName);
254
+ if (!currentSeverity || severityRank[nextSeverity] > severityRank[currentSeverity]) {
255
+ severityByRule.set(ruleName, nextSeverity);
256
+ }
257
+ }
258
+ }
246
259
  let error = 0;
247
260
  let warn = 0;
248
261
  let off = 0;
249
- for (const rulesObject of ruleObjects) {
250
- for (const entry of Object.values(rulesObject)) {
251
- rules += 1;
252
- const severity = getPrimarySeverity(entry);
253
- if (severity === "error") {
254
- error += 1;
255
- } else if (severity === "warn") {
256
- warn += 1;
257
- } else {
258
- off += 1;
259
- }
262
+ for (const severity of severityByRule.values()) {
263
+ if (severity === "error") {
264
+ error += 1;
265
+ } else if (severity === "warn") {
266
+ warn += 1;
267
+ } else {
268
+ off += 1;
260
269
  }
261
270
  }
262
- return { rules, error, warn, off };
271
+ return { rules: severityByRule.size, error, warn, off };
263
272
  }
264
273
  function getPrimarySeverity(entry) {
265
274
  if (!entry) {
@@ -850,10 +859,12 @@ async function executeCatalogUpdate(cwd, terminal, snapshotDir) {
850
859
  const rows = await computeCatalogRows(cwd, terminal, snapshotDir, "catalog:update", false);
851
860
  await writeCatalogBaselineFiles(cwd, snapshotDir, rows);
852
861
  const groups = rows.length;
853
- const available = rows.reduce((sum, row) => sum + row.totalStats.totalAvailable, 0);
854
- const inUse = rows.reduce((sum, row) => sum + row.totalStats.inUse, 0);
862
+ const available = countUniqueRules(rows.map((row) => row.availableRules));
863
+ const inUse = countUniqueRules(rows.map((row) => row.observedRules.filter((ruleName) => row.availableRules.includes(ruleName))));
855
864
  terminal.write(`\u{1F9EA} Catalog baseline updated: ${groups} groups, ${available} available rules, ${inUse} currently in use.
856
865
  `);
866
+ terminal.section("\u{1F4CA} Catalog summary");
867
+ terminal.write(formatShortCatalog(rows, false));
857
868
  return 0;
858
869
  }
859
870
  async function executeCatalogCheck(cwd, terminal, snapshotDir) {
@@ -868,8 +879,12 @@ async function executeCatalogCheck(cwd, terminal, snapshotDir) {
868
879
  const diffs = compareCatalogBaselines(stored, current);
869
880
  if (diffs.length === 0) {
870
881
  terminal.write("Great news: no catalog drift detected.\n");
882
+ terminal.section("\u{1F4CA} Catalog summary");
883
+ terminal.write(formatShortCatalog(rows, false));
871
884
  return 0;
872
885
  }
886
+ terminal.section("\u{1F4CA} Catalog summary");
887
+ terminal.write(formatShortCatalog(rows, false));
873
888
  terminal.write(`\u26A0\uFE0F Heads up: catalog drift detected in ${diffs.length} groups.
874
889
  `);
875
890
  for (const diff of diffs) {
@@ -1110,6 +1125,15 @@ function toPercent(value, total) {
1110
1125
  }
1111
1126
  return Number((value / total * 100).toFixed(1));
1112
1127
  }
1128
+ function countUniqueRules(ruleLists) {
1129
+ const unique = /* @__PURE__ */ new Set();
1130
+ for (const rules of ruleLists) {
1131
+ for (const rule of rules) {
1132
+ unique.add(rule);
1133
+ }
1134
+ }
1135
+ return unique.size;
1136
+ }
1113
1137
 
1114
1138
  // src/commands/check.ts
1115
1139
  var UPDATE_HINT = "Tip: when you intentionally accept changes, run `eslint-config-snapshot --update` to refresh the baseline.\n";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eslint-config-snapshot/cli",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -31,6 +31,6 @@
31
31
  "commander": "^14.0.3",
32
32
  "debug": "^4.4.3",
33
33
  "fast-glob": "^3.3.3",
34
- "@eslint-config-snapshot/api": "1.3.0"
34
+ "@eslint-config-snapshot/api": "1.3.1"
35
35
  }
36
36
  }
@@ -87,9 +87,11 @@ export async function executeCatalogUpdate(cwd: string, terminal: TerminalIO, sn
87
87
  await writeCatalogBaselineFiles(cwd, snapshotDir, rows)
88
88
 
89
89
  const groups = rows.length
90
- const available = rows.reduce((sum, row) => sum + row.totalStats.totalAvailable, 0)
91
- const inUse = rows.reduce((sum, row) => sum + row.totalStats.inUse, 0)
90
+ const available = countUniqueRules(rows.map((row) => row.availableRules))
91
+ const inUse = countUniqueRules(rows.map((row) => row.observedRules.filter((ruleName) => row.availableRules.includes(ruleName))))
92
92
  terminal.write(`๐Ÿงช Catalog baseline updated: ${groups} groups, ${available} available rules, ${inUse} currently in use.\n`)
93
+ terminal.section('๐Ÿ“Š Catalog summary')
94
+ terminal.write(formatShortCatalog(rows, false))
93
95
  return 0
94
96
  }
95
97
 
@@ -107,9 +109,13 @@ export async function executeCatalogCheck(cwd: string, terminal: TerminalIO, sna
107
109
  const diffs = compareCatalogBaselines(stored, current)
108
110
  if (diffs.length === 0) {
109
111
  terminal.write('Great news: no catalog drift detected.\n')
112
+ terminal.section('๐Ÿ“Š Catalog summary')
113
+ terminal.write(formatShortCatalog(rows, false))
110
114
  return 0
111
115
  }
112
116
 
117
+ terminal.section('๐Ÿ“Š Catalog summary')
118
+ terminal.write(formatShortCatalog(rows, false))
113
119
  terminal.write(`โš ๏ธ Heads up: catalog drift detected in ${diffs.length} groups.\n`)
114
120
  for (const diff of diffs) {
115
121
  terminal.write(
@@ -392,3 +398,13 @@ function toPercent(value: number, total: number): number {
392
398
  }
393
399
  return Number(((value / total) * 100).toFixed(1))
394
400
  }
401
+
402
+ function countUniqueRules(ruleLists: string[][]): number {
403
+ const unique = new Set<string>()
404
+ for (const rules of ruleLists) {
405
+ for (const rule of rules) {
406
+ unique.add(rule)
407
+ }
408
+ }
409
+ return unique.size
410
+ }
package/src/formatters.ts CHANGED
@@ -101,7 +101,7 @@ export function summarizeChanges(changes: Array<{ groupId: string; diff: Snapsho
101
101
  }
102
102
 
103
103
  export function summarizeSnapshots(snapshots: Map<string, SnapshotLike>) {
104
- const { rules, error, warn, off } = countRuleSeverities([...snapshots.values()].map((snapshot) => snapshot.rules))
104
+ const { rules, error, warn, off } = countUniqueRuleSeverities([...snapshots.values()].map((snapshot) => snapshot.rules))
105
105
  return { groups: snapshots.size, rules, error, warn, off }
106
106
  }
107
107
 
@@ -331,6 +331,39 @@ export function countRuleSeverities(ruleObjects: RuleObject[]) {
331
331
  return { rules, error, warn, off }
332
332
  }
333
333
 
334
+ export function countUniqueRuleSeverities(ruleObjects: RuleObject[]) {
335
+ const severityRank: Record<'off' | 'warn' | 'error', number> = { off: 0, warn: 1, error: 2 }
336
+ const severityByRule = new Map<string, 'off' | 'warn' | 'error'>()
337
+
338
+ for (const rulesObject of ruleObjects) {
339
+ for (const [ruleName, entry] of Object.entries(rulesObject)) {
340
+ const nextSeverity = getPrimarySeverity(entry)
341
+ if (!nextSeverity) {
342
+ continue
343
+ }
344
+ const currentSeverity = severityByRule.get(ruleName)
345
+ if (!currentSeverity || severityRank[nextSeverity] > severityRank[currentSeverity]) {
346
+ severityByRule.set(ruleName, nextSeverity)
347
+ }
348
+ }
349
+ }
350
+
351
+ let error = 0
352
+ let warn = 0
353
+ let off = 0
354
+ for (const severity of severityByRule.values()) {
355
+ if (severity === 'error') {
356
+ error += 1
357
+ } else if (severity === 'warn') {
358
+ warn += 1
359
+ } else {
360
+ off += 1
361
+ }
362
+ }
363
+
364
+ return { rules: severityByRule.size, error, warn, off }
365
+ }
366
+
334
367
  function getPrimarySeverity(entry: SnapshotRuleEntry | undefined): 'off' | 'warn' | 'error' | undefined {
335
368
  if (!entry) {
336
369
  return undefined
@@ -266,11 +266,15 @@ no-debugger: off
266
266
  const update = run(['catalog-update'])
267
267
  expect(update.status).toBe(0)
268
268
  expect(update.stdout).toContain('Catalog baseline updated:')
269
+ expect(update.stdout).toContain('๐Ÿ“ฆ total:')
270
+ expect(update.stdout).toContain('๐Ÿ”Œ plugins tracked:')
269
271
  expect(update.stderr).toBe('')
270
272
 
271
273
  const check = run(['catalog-check'])
272
274
  expect(check.status).toBe(0)
273
- expect(check.stdout).toBe('Great news: no catalog drift detected.\n')
275
+ expect(check.stdout).toContain('Great news: no catalog drift detected.')
276
+ expect(check.stdout).toContain('๐Ÿ“ฆ total:')
277
+ expect(check.stdout).toContain('๐Ÿ”Œ plugins tracked:')
274
278
  expect(check.stderr).toBe('')
275
279
  })
276
280
 
@@ -44,4 +44,35 @@ describe('output helpers', () => {
44
44
  )
45
45
  expect(summary).toEqual({ groups: 1, rules: 3, error: 1, warn: 1, off: 1 })
46
46
  })
47
+
48
+ it('deduplicates rules across groups in summary', () => {
49
+ const summary = summarizeSnapshots(
50
+ new Map([
51
+ [
52
+ 'group-a',
53
+ {
54
+ groupId: 'group-a',
55
+ workspaces: ['packages/a'],
56
+ rules: {
57
+ shared: ['warn'],
58
+ onlyA: ['off']
59
+ }
60
+ }
61
+ ],
62
+ [
63
+ 'group-b',
64
+ {
65
+ groupId: 'group-b',
66
+ workspaces: ['packages/b'],
67
+ rules: {
68
+ shared: ['error'],
69
+ onlyB: ['warn']
70
+ }
71
+ }
72
+ ]
73
+ ])
74
+ )
75
+
76
+ expect(summary).toEqual({ groups: 2, rules: 3, error: 1, warn: 1, off: 1 })
77
+ })
47
78
  })