@georgewrmarshall/design-system-metrics 2.5.0 → 2.6.0

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.
@@ -21,7 +21,8 @@
21
21
  "Bash(yarn upgrade:*)",
22
22
  "Bash(yarn up:*)",
23
23
  "Bash(yarn npm info:*)",
24
- "Bash(yarn remove:*)"
24
+ "Bash(yarn remove:*)",
25
+ "Bash(cat:*)"
25
26
  ],
26
27
  "deny": [],
27
28
  "ask": []
package/CHANGELOG.md CHANGED
@@ -5,6 +5,39 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.6.0] - 2026-02-23
9
+
10
+ ### Added
11
+
12
+ - **Complete MMDS Component List**: MMDS Usage sheet now shows all available MMDS components, including those with 0 instances
13
+ - Previously only showed components that were actively used
14
+ - Now displays the full component list with usage counts, making it easier to identify available but unused components
15
+ - Helps track MMDS component adoption opportunities
16
+
17
+ - **Totals Rows**: All sheets now include totals at the bottom for easy summary analysis
18
+ - Migration Progress: Shows total deprecated instances, total MMDS instances, and overall migration percentage (with accurate deduplication)
19
+ - Intermediate Migrations: Shows total instances awaiting intermediate migration
20
+ - MMDS Usage: Shows total MMDS component instances across all components
21
+ - No Replacement: Shows total instances of components without direct replacements
22
+ - Console output now displays these totals for quick visibility
23
+
24
+ - **Grouped Display with Summary Rows**: Migration Progress sheet now groups deprecated components by their MMDS replacement
25
+ - Components mapping to the same MMDS component are displayed together (e.g., all Icon variants grouped together)
26
+ - Individual rows show deprecated component details with "-" for MMDS instances and percentage to avoid misleading duplicates
27
+ - Summary rows (format: "→ Component Total") show aggregated deprecated count, MMDS instances, and accurate migration percentage for each group
28
+ - Single-mapping components continue to display normally with all columns filled
29
+ - Provides much more accurate and meaningful migration percentages
30
+
31
+ ### Fixed
32
+
33
+ - **Migration Progress Totals**: Fixed duplicate counting when multiple deprecated components map to the same MMDS component
34
+ - Each MMDS component is counted only once in the total, providing accurate migration percentage
35
+ - Individual rows still show correct per-component breakdown
36
+
37
+ - **Test Suite**: Updated tests to work with date-stamped output files
38
+ - Added helper function to dynamically find generated XLSX files
39
+ - All 14 tests passing
40
+
8
41
  ## [2.5.0] - 2026-02-21
9
42
 
10
43
  ### Fixed
@@ -5,7 +5,13 @@ const ExcelJS = require('exceljs');
5
5
 
6
6
  const TEST_CONFIG = path.join(__dirname, 'fixtures/test-config.json');
7
7
  const OUTPUT_DIR = path.join(__dirname, 'output');
8
- const XLSX_OUTPUT = path.join(OUTPUT_DIR, 'test-metrics.xlsx');
8
+ // Helper to get the generated XLSX file (with date stamp)
9
+ const getXLSXOutput = async () => {
10
+ const files = await fs.readdir(OUTPUT_DIR);
11
+ const xlsxFile = files.find(f => f.startsWith('test-metrics-') && f.endsWith('.xlsx'));
12
+ return xlsxFile ? path.join(OUTPUT_DIR, xlsxFile) : null;
13
+ };
14
+ const XLSX_OUTPUT_BASE = 'test-metrics';
9
15
 
10
16
  describe('Design System Metrics', () => {
11
17
  beforeAll(() => {
@@ -50,12 +56,8 @@ describe('Design System Metrics', () => {
50
56
  { stdio: 'pipe' }
51
57
  );
52
58
 
53
- const exists = await fs
54
- .access(XLSX_OUTPUT)
55
- .then(() => true)
56
- .catch(() => false);
57
-
58
- expect(exists).toBe(true);
59
+ const XLSX_OUTPUT = await getXLSXOutput();
60
+ expect(XLSX_OUTPUT).not.toBeNull();
59
61
 
60
62
  const workbook = await readXLSX(XLSX_OUTPUT);
61
63
  const sheetNames = workbook.worksheets.map(ws => ws.name);
@@ -74,6 +76,7 @@ describe('Design System Metrics', () => {
74
76
  { stdio: 'pipe' }
75
77
  );
76
78
 
79
+ const XLSX_OUTPUT = await getXLSXOutput();
77
80
  const workbook = await readXLSX(XLSX_OUTPUT);
78
81
  const data = getSheetData(workbook, 'Migration Progress');
79
82
  const headers = data[0];
@@ -92,6 +95,7 @@ describe('Design System Metrics', () => {
92
95
  { stdio: 'pipe' }
93
96
  );
94
97
 
98
+ const XLSX_OUTPUT = await getXLSXOutput();
95
99
  const workbook = await readXLSX(XLSX_OUTPUT);
96
100
  const data = getSheetData(workbook, 'Migration Progress');
97
101
 
@@ -111,6 +115,7 @@ describe('Design System Metrics', () => {
111
115
  { stdio: 'pipe' }
112
116
  );
113
117
 
118
+ const XLSX_OUTPUT = await getXLSXOutput();
114
119
  const workbook = await readXLSX(XLSX_OUTPUT);
115
120
  const data = getSheetData(workbook, 'Migration Progress');
116
121
 
@@ -128,6 +133,7 @@ describe('Design System Metrics', () => {
128
133
  { stdio: 'pipe' }
129
134
  );
130
135
 
136
+ const XLSX_OUTPUT = await getXLSXOutput();
131
137
  const workbook = await readXLSX(XLSX_OUTPUT);
132
138
  const data = getSheetData(workbook, 'Path-Level Detail');
133
139
  const headers = data[0];
@@ -144,6 +150,7 @@ describe('Design System Metrics', () => {
144
150
  { stdio: 'pipe' }
145
151
  );
146
152
 
153
+ const XLSX_OUTPUT = await getXLSXOutput();
147
154
  const workbook = await readXLSX(XLSX_OUTPUT);
148
155
  const data = getSheetData(workbook, 'Path-Level Detail');
149
156
 
@@ -159,6 +166,7 @@ describe('Design System Metrics', () => {
159
166
  { stdio: 'pipe' }
160
167
  );
161
168
 
169
+ const XLSX_OUTPUT = await getXLSXOutput();
162
170
  const workbook = await readXLSX(XLSX_OUTPUT);
163
171
  const data = getSheetData(workbook, 'Path-Level Detail');
164
172
 
@@ -174,6 +182,7 @@ describe('Design System Metrics', () => {
174
182
  { stdio: 'pipe' }
175
183
  );
176
184
 
185
+ const XLSX_OUTPUT = await getXLSXOutput();
177
186
  const workbook = await readXLSX(XLSX_OUTPUT);
178
187
  const data = getSheetData(workbook, 'Path-Level Detail');
179
188
 
@@ -190,6 +199,7 @@ describe('Design System Metrics', () => {
190
199
  { stdio: 'pipe' }
191
200
  );
192
201
 
202
+ const XLSX_OUTPUT = await getXLSXOutput();
193
203
  const workbook = await readXLSX(XLSX_OUTPUT);
194
204
  const data = getSheetData(workbook, 'MMDS Usage');
195
205
  const headers = data[0];
@@ -205,6 +215,7 @@ describe('Design System Metrics', () => {
205
215
  { stdio: 'pipe' }
206
216
  );
207
217
 
218
+ const XLSX_OUTPUT = await getXLSXOutput();
208
219
  const workbook = await readXLSX(XLSX_OUTPUT);
209
220
  const data = getSheetData(workbook, 'MMDS Usage');
210
221
 
@@ -222,6 +233,7 @@ describe('Design System Metrics', () => {
222
233
  { stdio: 'pipe' }
223
234
  );
224
235
 
236
+ const XLSX_OUTPUT = await getXLSXOutput();
225
237
  const workbook = await readXLSX(XLSX_OUTPUT);
226
238
  const data = getSheetData(workbook, 'MMDS Usage');
227
239
 
@@ -237,6 +249,7 @@ describe('Design System Metrics', () => {
237
249
  { stdio: 'pipe' }
238
250
  );
239
251
 
252
+ const XLSX_OUTPUT = await getXLSXOutput();
240
253
  const workbook = await readXLSX(XLSX_OUTPUT);
241
254
  const data = getSheetData(workbook, 'MMDS Usage');
242
255
 
@@ -253,6 +266,7 @@ describe('Design System Metrics', () => {
253
266
  { stdio: 'pipe' }
254
267
  );
255
268
 
269
+ const XLSX_OUTPUT = await getXLSXOutput();
256
270
  const workbook = await readXLSX(XLSX_OUTPUT);
257
271
  const data = getSheetData(workbook, 'No Replacement');
258
272
  const headers = data[0];
@@ -269,6 +283,7 @@ describe('Design System Metrics', () => {
269
283
  { stdio: 'pipe' }
270
284
  );
271
285
 
286
+ const XLSX_OUTPUT = await getXLSXOutput();
272
287
  const workbook = await readXLSX(XLSX_OUTPUT);
273
288
  const data = getSheetData(workbook, 'No Replacement');
274
289
 
package/index.js CHANGED
@@ -46,7 +46,7 @@ const validateConfig = (cfg) => {
46
46
 
47
47
  // Define CLI options using Commander
48
48
  program
49
- .version("2.5.0")
49
+ .version("2.6.0")
50
50
  .description("Design System Metrics CLI Tool - Track component usage and migration progress")
51
51
  .requiredOption(
52
52
  "-p, --project <name>",
@@ -369,27 +369,99 @@ const main = async () => {
369
369
  (metrics.replacement.package.includes("@metamask/design-system"))
370
370
  );
371
371
 
372
+ // Group deprecated components by their MMDS replacement component
373
+ const groupedByMMDS = new Map();
372
374
  componentsWithMMDSReplacement.forEach(([componentName, metrics]) => {
373
375
  const mmdsComp = metrics.replacement.component;
374
- const deprecatedCount = metrics.totalCount;
376
+ if (!groupedByMMDS.has(mmdsComp)) {
377
+ groupedByMMDS.set(mmdsComp, []);
378
+ }
379
+ groupedByMMDS.get(mmdsComp).push([componentName, metrics]);
380
+ });
381
+
382
+ let totalDeprecated = 0;
383
+ let totalMMDS = 0;
384
+
385
+ // Process each MMDS component group
386
+ for (const [mmdsComp, deprecatedComponents] of groupedByMMDS.entries()) {
375
387
  const mmdsCount = currentMetrics.get(mmdsComp)?.count || 0;
376
- const total = deprecatedCount + mmdsCount;
377
- const percentage = total > 0 ? (mmdsCount / total) * 100 : 0;
378
- const sourcePaths = deprecatedComponents[componentName].paths.join(", ");
379
388
 
380
- migrationSheet.addRow([
381
- componentName,
382
- sourcePaths,
383
- mmdsComp,
384
- deprecatedCount,
385
- mmdsCount,
386
- `${percentage.toFixed(2)}%`,
387
- ]);
388
- });
389
+ if (deprecatedComponents.length === 1) {
390
+ // Single component mapping - show normally
391
+ const [componentName, metrics] = deprecatedComponents[0];
392
+ const deprecatedCount = metrics.totalCount;
393
+ const total = deprecatedCount + mmdsCount;
394
+ const percentage = total > 0 ? (mmdsCount / total) * 100 : 0;
395
+ const sourcePaths = config.projects[projectName].deprecatedComponents[componentName].paths.join(", ");
396
+
397
+ totalDeprecated += deprecatedCount;
398
+ totalMMDS += mmdsCount;
399
+
400
+ migrationSheet.addRow([
401
+ componentName,
402
+ sourcePaths,
403
+ mmdsComp,
404
+ deprecatedCount,
405
+ mmdsCount,
406
+ `${percentage.toFixed(2)}%`,
407
+ ]);
408
+ } else {
409
+ // Multiple components mapping to same MMDS component
410
+ let groupDeprecatedTotal = 0;
411
+
412
+ // Add individual rows (without MMDS count and percentage)
413
+ deprecatedComponents.forEach(([componentName, metrics]) => {
414
+ const deprecatedCount = metrics.totalCount;
415
+ const sourcePaths = config.projects[projectName].deprecatedComponents[componentName].paths.join(", ");
416
+
417
+ groupDeprecatedTotal += deprecatedCount;
418
+
419
+ migrationSheet.addRow([
420
+ componentName,
421
+ sourcePaths,
422
+ mmdsComp,
423
+ deprecatedCount,
424
+ "-",
425
+ "-",
426
+ ]);
427
+ });
428
+
429
+ // Add summary row for the group
430
+ const total = groupDeprecatedTotal + mmdsCount;
431
+ const percentage = total > 0 ? (mmdsCount / total) * 100 : 0;
432
+
433
+ migrationSheet.addRow([
434
+ `→ ${mmdsComp} Total`,
435
+ "",
436
+ mmdsComp,
437
+ groupDeprecatedTotal,
438
+ mmdsCount,
439
+ `${percentage.toFixed(2)}%`,
440
+ ]);
441
+
442
+ totalDeprecated += groupDeprecatedTotal;
443
+ totalMMDS += mmdsCount;
444
+ }
445
+ }
446
+
447
+ // Add totals row
448
+ const totalAll = totalDeprecated + totalMMDS;
449
+ const totalPercentage = totalAll > 0 ? (totalMMDS / totalAll) * 100 : 0;
450
+ migrationSheet.addRow([
451
+ "TOTAL",
452
+ "",
453
+ "",
454
+ totalDeprecated,
455
+ totalMMDS,
456
+ `${totalPercentage.toFixed(2)}%`,
457
+ ]);
389
458
 
390
459
  console.log(
391
460
  chalk.blue(`Migration Progress: ${componentsWithMMDSReplacement.length} components tracked`)
392
461
  );
462
+ console.log(
463
+ chalk.blue(`Total Migration: ${totalMMDS}/${totalAll} (${totalPercentage.toFixed(2)}%)`)
464
+ );
393
465
 
394
466
  // Sheet 2: Intermediate Migrations (components migrating to component-library)
395
467
  const intermediateSheet = workbook.addWorksheet("Intermediate Migrations");
@@ -407,11 +479,15 @@ const main = async () => {
407
479
  metrics.replacement.package === "component-library"
408
480
  );
409
481
 
482
+ let totalIntermediate = 0;
483
+
410
484
  componentsWithIntermediateReplacement.forEach(([componentName, metrics]) => {
411
485
  const oldPaths = deprecatedComponents[componentName].paths.join(", ");
412
486
  const newComponent = metrics.replacement.component;
413
487
  const newPath = metrics.replacement.path || metrics.replacement.package;
414
488
 
489
+ totalIntermediate += metrics.totalCount;
490
+
415
491
  intermediateSheet.addRow([
416
492
  componentName,
417
493
  oldPaths,
@@ -421,9 +497,21 @@ const main = async () => {
421
497
  ]);
422
498
  });
423
499
 
500
+ // Add totals row
501
+ intermediateSheet.addRow([
502
+ "TOTAL",
503
+ "",
504
+ "",
505
+ "",
506
+ totalIntermediate,
507
+ ]);
508
+
424
509
  console.log(
425
510
  chalk.blue(`Intermediate Migrations: ${componentsWithIntermediateReplacement.length} components tracked`)
426
511
  );
512
+ console.log(
513
+ chalk.blue(`Total Intermediate Instances: ${totalIntermediate}`)
514
+ );
427
515
 
428
516
  // Sheet 3: Path-Level Detail
429
517
  const pathDetailSheet = workbook.addWorksheet("Path-Level Detail");
@@ -453,15 +541,35 @@ const main = async () => {
453
541
  const mmdsSheet = workbook.addWorksheet("MMDS Usage");
454
542
  mmdsSheet.addRow(["Component", "Instances", "File Paths"]);
455
543
 
456
- currentMetrics.forEach((metrics, componentName) => {
457
- console.log(`${chalk.cyan(componentName)}: ${metrics.count} (MMDS)`);
544
+ // Include all MMDS components, even those with 0 instances
545
+ let totalMMDSUsage = 0;
546
+
547
+ currentComponentsSet.forEach((componentName) => {
548
+ const metrics = currentMetrics.get(componentName);
549
+ const count = metrics ? metrics.count : 0;
550
+ const files = metrics ? metrics.files.join(", ") : "";
551
+
552
+ totalMMDSUsage += count;
553
+
554
+ console.log(`${chalk.cyan(componentName)}: ${count} (MMDS)`);
458
555
  mmdsSheet.addRow([
459
556
  componentName,
460
- metrics.count,
461
- metrics.files.join(", "),
557
+ count,
558
+ files,
462
559
  ]);
463
560
  });
464
561
 
562
+ // Add totals row
563
+ mmdsSheet.addRow([
564
+ "TOTAL",
565
+ totalMMDSUsage,
566
+ "",
567
+ ]);
568
+
569
+ console.log(
570
+ chalk.blue(`Total MMDS Usage: ${totalMMDSUsage} instances`)
571
+ );
572
+
465
573
  // Sheet 5: No Replacement Components
466
574
  const noReplacementSheet = workbook.addWorksheet("No Replacement");
467
575
  noReplacementSheet.addRow(["Component", "Path", "Instances", "File Paths"]);
@@ -469,8 +577,12 @@ const main = async () => {
469
577
  const componentsWithNoReplacement = Array.from(deprecatedMetrics.entries())
470
578
  .filter(([, metrics]) => !metrics.replacement);
471
579
 
580
+ let totalNoReplacement = 0;
581
+
472
582
  componentsWithNoReplacement.forEach(([componentName, metrics]) => {
473
583
  const paths = deprecatedComponents[componentName].paths.join(", ");
584
+ totalNoReplacement += metrics.totalCount;
585
+
474
586
  noReplacementSheet.addRow([
475
587
  componentName,
476
588
  paths,
@@ -479,9 +591,20 @@ const main = async () => {
479
591
  ]);
480
592
  });
481
593
 
594
+ // Add totals row
595
+ noReplacementSheet.addRow([
596
+ "TOTAL",
597
+ "",
598
+ totalNoReplacement,
599
+ "",
600
+ ]);
601
+
482
602
  console.log(
483
603
  chalk.blue(`No Replacement: ${componentsWithNoReplacement.length} components`)
484
604
  );
605
+ console.log(
606
+ chalk.blue(`Total No Replacement Instances: ${totalNoReplacement}`)
607
+ );
485
608
 
486
609
  // Create output directory if it doesn't exist
487
610
  const outputDir = path.dirname(outputFile);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@georgewrmarshall/design-system-metrics",
3
- "version": "2.5.0",
3
+ "version": "2.6.0",
4
4
  "description": "A CLI tool to audit design system component usage from local libraries, NPM packages, and track deprecated components across MetaMask codebases",
5
5
  "main": "index.js",
6
6
  "packageManager": "yarn@4.3.1",