@civicactions/cmsds-open-data-components 4.0.8-alpha.0 → 4.0.8-alpha.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/README.md CHANGED
@@ -62,7 +62,36 @@ This creates `COMPONENTS_INVENTORY.md` in the root directory with:
62
62
 
63
63
  The inventory is automatically updated on every commit via a pre-commit hook.
64
64
 
65
- For more details, see the [Inventory Generator Documentation](scripts/README.md).
65
+ For more details, see the [Scripts Documentation](scripts/README.md).
66
+
67
+ ## Component Usage Report
68
+
69
+ This project includes a script that can be run in projects that use cmsds-open-data-components as a dependency to analyze component usage.
70
+
71
+ ### Running in Dependent Projects
72
+
73
+ From a project that has `@civicactions/cmsds-open-data-components` as a dependency:
74
+
75
+ ```bash
76
+ npx generate-usage-report
77
+ ```
78
+
79
+ This generates `COMPONENT_USAGE_REPORT.md` showing:
80
+ - Which components from the library are being used
81
+ - Where each component is imported in the project
82
+ - Summary statistics and category breakdown
83
+ - GitHub links to component source code
84
+
85
+ ### Generating Sample Report (Library Development)
86
+
87
+ To generate a sample report using Storybook files in this repository:
88
+ ```bash
89
+ npm run generate:usage-report
90
+ ```
91
+
92
+ This creates `SAMPLE_COMPONENT_USAGE_REPORT.md` demonstrating the report format.
93
+
94
+ For more details, see the [Scripts Documentation](scripts/README.md).
66
95
 
67
96
  ## Publishing new versions
68
97
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@civicactions/cmsds-open-data-components",
3
- "version": "4.0.8-alpha.0",
3
+ "version": "4.0.8-alpha.1",
4
4
  "description": "Components for the open data catalog frontend using CMS Design System",
5
5
  "main": "dist/main.js",
6
6
  "source": "src/index.ts",
package/scripts/README.md CHANGED
@@ -1,4 +1,8 @@
1
- # Component Inventory Generator
1
+ # Scripts Documentation
2
+
3
+ This directory contains utility scripts for managing and analyzing the cmsds-open-data-components library.
4
+
5
+ ## Component Inventory Generator
2
6
 
3
7
  This script automatically generates a comprehensive markdown inventory report for the cmsds-open-data-components library.
4
8
 
@@ -92,12 +96,153 @@ To add new special cases, update the scanning functions in `generate-inventory.c
92
96
 
93
97
  ```
94
98
  scripts/
95
- generate-inventory.cjs # Main script file
96
- README.md # This file
99
+ generate-inventory.cjs # Component inventory script
100
+ generate-inventory.test.js # Tests for inventory script
101
+ generate-usage-report.cjs # Component usage report script
102
+ generate-usage-report.test.js # Tests for usage report script
103
+ README.md # This file
104
+
105
+ COMPONENTS_INVENTORY.md # Generated inventory (root directory)
106
+ COMPONENT_USAGE_REPORT.md # Generated usage report (root directory, when run in dependent projects)
107
+ SAMPLE_COMPONENT_USAGE_REPORT.md # Sample usage report (root directory, when run locally)
108
+ ```
109
+
110
+ ---
111
+
112
+ # Component Usage Report Generator
113
+
114
+ This script analyzes projects that use cmsds-open-data-components as a dependency and generates a comprehensive report showing which components are being used and where.
115
+
116
+ ## Usage
97
117
 
98
- COMPONENTS_INVENTORY.md # Generated output file (root directory)
118
+ ### In Projects Using cmsds-open-data-components
119
+
120
+ From a project that has `@civicactions/cmsds-open-data-components` as a dependency:
121
+
122
+ ```bash
123
+ npx generate-usage-report
124
+ ```
125
+
126
+ Or add to your project's scripts in `package.json`:
127
+ ```json
128
+ {
129
+ "scripts": {
130
+ "usage-report": "generate-usage-report"
131
+ }
132
+ }
133
+ ```
134
+
135
+ Then run:
136
+ ```bash
137
+ npm run usage-report
99
138
  ```
100
139
 
140
+ ### In the Library Repository
141
+
142
+ Run the script directly in this repository to generate a sample report:
143
+
144
+ ```bash
145
+ npm run generate:usage-report
146
+ ```
147
+
148
+ Or run it directly:
149
+
150
+ ```bash
151
+ node scripts/generate-usage-report.cjs
152
+ ```
153
+
154
+ When run in the library repository, it generates a sample report (`SAMPLE_COMPONENT_USAGE_REPORT.md`) by analyzing Storybook files.
155
+
156
+ ## Output
157
+
158
+ The script generates a markdown report containing:
159
+
160
+ - **Library Version**: Version of cmsds-open-data-components being analyzed
161
+ - **Summary Statistics**: Total unique components, import statements, and files analyzed
162
+ - **Category Breakdown**: Components grouped by type (Component, Template, Hook, Context, Service, Utility)
163
+ - **Component Usage Details**: Table showing each component with:
164
+ - Component name (linked to GitHub repository)
165
+ - Category/type
166
+ - Number of times imported
167
+ - List of files where it's used
168
+
169
+ ## What It Scans
170
+
171
+ The script scans the following directories in your project:
172
+
173
+ - `src/` - Main source directory
174
+ - `app/` - Next.js app directory
175
+ - `pages/` - Next.js pages directory
176
+ - `components/` - Components directory
177
+ - `templates/` - Templates directory
178
+
179
+ It searches for these file types:
180
+ - `.js`, `.jsx` - JavaScript/React files
181
+ - `.ts`, `.tsx` - TypeScript/React files
182
+
183
+ The script automatically excludes:
184
+ - `node_modules/` - Dependencies
185
+ - `dist/`, `build/` - Build output directories
186
+ - `.next/`, `.cache/` - Framework cache directories
187
+
188
+ ## How It Works
189
+
190
+ 1. **Detects execution context**: Determines if running in the library repo or a dependent project
191
+ 2. **Scans project files**: Recursively searches for JavaScript/TypeScript files
192
+ 3. **Parses imports**: Uses regex to find imports from `@civicactions/cmsds-open-data-components`
193
+ 4. **Tracks usage**: Records each component, where it's imported, and at what line number
194
+ 5. **Categorizes components**: Automatically categorizes by naming patterns:
195
+ - Hooks: Names starting with `use`
196
+ - Contexts: Names ending with `Context`
197
+ - Templates: From `templates/` directory
198
+ - Services: From `services/` directory
199
+ - Utilities: From `utilities/` directory
200
+ - Components: Everything else
201
+ 6. **Generates report**: Creates formatted markdown with statistics and detailed usage tables
202
+ 7. **Adds GitHub links**: Links each component name to its source in the GitHub repository
203
+
204
+ ## Component Categories
205
+
206
+ Components are automatically categorized based on naming conventions and source location:
207
+
208
+ - **Hook**: Components starting with `use` (e.g., `useScrollToTop`, `useDatastore`)
209
+ - **Context**: Components ending with `Context` (e.g., `ACAContext`)
210
+ - **Template**: Components from the `templates/` directory
211
+ - **Service**: Components from the `services/` directory
212
+ - **Utility**: Components from the `utilities/` directory
213
+ - **Component**: All other React components
214
+
215
+ ## Sample vs Real Reports
216
+
217
+ **In the library repository**: Generates `SAMPLE_COMPONENT_USAGE_REPORT.md` by analyzing how components are used in Storybook files. This serves as an example of the report format.
218
+
219
+ **In dependent projects**: Generates `COMPONENT_USAGE_REPORT.md` by analyzing actual component usage throughout the project's codebase.
220
+
221
+ ## Requirements
222
+
223
+ - Node.js v14 or higher
224
+ - No additional dependencies required (uses Node.js built-in `fs` and `path` modules)
225
+
226
+ ## Troubleshooting
227
+
228
+ **Error: "require is not defined"**
229
+ - The script uses `.cjs` extension to work with the ES module package type
230
+ - Make sure the file is named `generate-usage-report.cjs` (not `.js`)
231
+
232
+ **No components found in scan**
233
+ - Verify that `@civicactions/cmsds-open-data-components` is installed as a dependency
234
+ - Check that your import statements use the full package name
235
+ - Ensure source files are in scanned directories (`src/`, `app/`, `pages/`, `components/`, `templates/`)
236
+
237
+ **Missing some component usages**
238
+ - The script only detects standard ES6 import syntax
239
+ - Dynamic imports (e.g., `import()`) are not currently detected
240
+ - Ensure imports use the package name: `from '@civicactions/cmsds-open-data-components'`
241
+
242
+ ---
243
+
244
+ ## File Structure
245
+
101
246
  ## Requirements
102
247
 
103
248
  - Node.js v14 or higher
@@ -125,14 +125,15 @@ function parseFileForImports(filePath) {
125
125
  const content = fs.readFileSync(filePath, 'utf8');
126
126
  const imports = [];
127
127
 
128
- // Match ES6 imports: import { Component1, Component2 } from '@civicactions/cmsds-open-data-components'
128
+ const getLineNumber = (index) => content.substring(0, index).split('\n').length;
129
+
130
+ // Match named imports: import { Component1, Component2 } from 'package'
129
131
  const namedImportRegex = new RegExp(
130
132
  `import\\s+\\{([^}]+)\\}\\s+from\\s+['"]${PACKAGE_NAME}['"]`,
131
133
  'g'
132
134
  );
133
135
 
134
- let match;
135
- while ((match = namedImportRegex.exec(content)) !== null) {
136
+ for (const match of content.matchAll(namedImportRegex)) {
136
137
  const names = match[1]
137
138
  .split(',')
138
139
  .map(n => n.trim())
@@ -142,22 +143,22 @@ function parseFileForImports(filePath) {
142
143
  imports.push({
143
144
  name,
144
145
  type: 'named',
145
- line: content.substring(0, match.index).split('\n').length
146
+ line: getLineNumber(match.index)
146
147
  });
147
148
  });
148
149
  }
149
150
 
150
- // Match default imports: import Component from '@civicactions/cmsds-open-data-components'
151
+ // Match default imports: import Component from 'package'
151
152
  const defaultImportRegex = new RegExp(
152
153
  `import\\s+(\\w+)\\s+from\\s+['"]${PACKAGE_NAME}['"]`,
153
154
  'g'
154
155
  );
155
156
 
156
- while ((match = defaultImportRegex.exec(content)) !== null) {
157
+ for (const match of content.matchAll(defaultImportRegex)) {
157
158
  imports.push({
158
159
  name: match[1],
159
160
  type: 'default',
160
- line: content.substring(0, match.index).split('\n').length
161
+ line: getLineNumber(match.index)
161
162
  });
162
163
  }
163
164
 
@@ -229,16 +230,52 @@ function categorizeComponent(name) {
229
230
  }
230
231
 
231
232
  /**
232
- * Generate markdown table row
233
+ * Generate markdown table row with GitHub link
233
234
  */
234
235
  function generateUsageRow(name, usages, category) {
235
236
  const count = usages.length;
236
237
  const files = [...new Set(usages.map(u => u.file))];
237
- const fileList = files.length <= 3
238
- ? files.map(f => `\`${f}\``).join(', ')
239
- : `${files.slice(0, 3).map(f => `\`${f}\``).join(', ')} and ${files.length - 3} more`;
238
+ const fileList = files.map(f => `\`${f}\``).join('<br>');
239
+
240
+ const githubPath = getGitHubPath(name, category);
241
+ const githubUrl = `https://github.com/GetDKAN/cmsds-open-data-components/tree/main/${githubPath}`;
242
+ const nameLink = `[${name}](${githubUrl})`;
240
243
 
241
- return `| ${name} | ${category} | ${count} | ${fileList} |`;
244
+ return `| ${nameLink} | ${category} | ${count} | ${fileList} |`;
245
+ }
246
+
247
+ /**
248
+ * Determine GitHub path based on component category and name
249
+ */
250
+ function getGitHubPath(name, category) {
251
+ // Standard categories map directly to directories
252
+ const categoryPaths = {
253
+ 'Component': `src/components/${name}`,
254
+ 'Hook': `src/components/${name}`,
255
+ 'Template': `src/templates/${name}`,
256
+ 'Service': `src/services/${name}`,
257
+ 'Utility': `src/utilities/${name}`
258
+ };
259
+
260
+ if (categoryPaths[category]) {
261
+ return categoryPaths[category];
262
+ }
263
+
264
+ // Context locations vary, check by name
265
+ if (category === 'Context') {
266
+ if (name.includes('DataTable')) {
267
+ return `src/components/DatasetTableTab/${name}.tsx`;
268
+ }
269
+ if (name === 'HeaderContext') {
270
+ return `src/templates/Header/${name}.tsx`;
271
+ }
272
+ if (name === 'ACAContext') {
273
+ return `src/utilities/${name}.ts`;
274
+ }
275
+ return `src/templates/Dataset/${name}.tsx`;
276
+ }
277
+
278
+ return `src/components/${name}`;
242
279
  }
243
280
 
244
281
  /**
@@ -246,33 +283,67 @@ function generateUsageRow(name, usages, category) {
246
283
  */
247
284
  function generateReport(usageMap, availableComponents) {
248
285
  const lines = [];
286
+ const projectInfo = getProjectInfo(availableComponents);
287
+
288
+ // Header
289
+ addReportHeader(lines, projectInfo);
290
+
291
+ // Summary statistics
292
+ addSummaryStatistics(lines, usageMap);
293
+
294
+ // Categorize and add category breakdown
295
+ const categorized = categorizeUsages(usageMap);
296
+ addCategoryBreakdown(lines, categorized);
249
297
 
250
- // Get project info
298
+ // Detailed usage table
299
+ addUsageTable(lines, usageMap);
300
+
301
+ // Footer
302
+ addReportFooter(lines);
303
+
304
+ return lines.join('\n');
305
+ }
306
+
307
+ /**
308
+ * Get project information
309
+ */
310
+ function getProjectInfo(availableComponents) {
251
311
  const projectPkgPath = path.join(projectRoot, 'package.json');
252
- let projectName = 'Unknown Project';
253
- let projectVersion = '';
254
312
 
255
- if (fs.existsSync(projectPkgPath)) {
256
- const projectPkg = JSON.parse(fs.readFileSync(projectPkgPath, 'utf8'));
257
- projectName = projectPkg.name || path.basename(projectRoot);
258
-
259
- // Get the installed version
260
- const deps = { ...projectPkg.dependencies, ...projectPkg.devDependencies };
261
- projectVersion = deps[PACKAGE_NAME] || availableComponents.version;
313
+ if (!fs.existsSync(projectPkgPath)) {
314
+ return {
315
+ name: 'Unknown Project',
316
+ version: availableComponents.version
317
+ };
262
318
  }
263
319
 
264
- // Header
265
- lines.push(`# ${projectName} Component Usage Report`);
320
+ const projectPkg = JSON.parse(fs.readFileSync(projectPkgPath, 'utf8'));
321
+ const deps = { ...projectPkg.dependencies, ...projectPkg.devDependencies };
322
+
323
+ return {
324
+ name: projectPkg.name || path.basename(projectRoot),
325
+ version: deps[PACKAGE_NAME] || availableComponents.version
326
+ };
327
+ }
328
+
329
+ /**
330
+ * Add report header section
331
+ */
332
+ function addReportHeader(lines, projectInfo) {
333
+ lines.push(`# ${projectInfo.name} Component Usage Report`);
266
334
  lines.push('');
267
335
  lines.push(`Analysis of \`${PACKAGE_NAME}\` usage in this project.`);
268
336
  lines.push('');
269
- lines.push(`**Library Version**: \`${PACKAGE_NAME}: ${projectVersion}\` `);
270
- lines.push(`**Generated**: ${new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })}`);
337
+ lines.push(`**Library Version**: \`${PACKAGE_NAME}: ${projectInfo.version}\` `);
271
338
  lines.push('');
272
339
  lines.push('---');
273
340
  lines.push('');
274
-
275
- // Summary statistics
341
+ }
342
+
343
+ /**
344
+ * Add summary statistics section
345
+ */
346
+ function addSummaryStatistics(lines, usageMap) {
276
347
  const totalUsages = Array.from(usageMap.values()).reduce((sum, usages) => sum + usages.length, 0);
277
348
  const uniqueComponents = usageMap.size;
278
349
  const filesUsingComponents = new Set();
@@ -287,9 +358,14 @@ function generateReport(usageMap, availableComponents) {
287
358
  lines.push(`- **Total Import Statements**: ${totalUsages}`);
288
359
  lines.push(`- **Files Using Components**: ${filesUsingComponents.size}`);
289
360
  lines.push('');
290
-
291
- // Categorize components
361
+ }
362
+
363
+ /**
364
+ * Categorize components by type
365
+ */
366
+ function categorizeUsages(usageMap) {
292
367
  const categorized = new Map();
368
+
293
369
  usageMap.forEach((usages, name) => {
294
370
  const category = categorizeComponent(name);
295
371
  if (!categorized.has(category)) {
@@ -298,7 +374,13 @@ function generateReport(usageMap, availableComponents) {
298
374
  categorized.get(category).push({ name, usages });
299
375
  });
300
376
 
301
- // Category breakdown
377
+ return categorized;
378
+ }
379
+
380
+ /**
381
+ * Add category breakdown section
382
+ */
383
+ function addCategoryBreakdown(lines, categorized) {
302
384
  lines.push('### By Category');
303
385
  lines.push('');
304
386
  lines.push('| Category | Count |');
@@ -315,8 +397,12 @@ function generateReport(usageMap, availableComponents) {
315
397
  lines.push('');
316
398
  lines.push('---');
317
399
  lines.push('');
318
-
319
- // Detailed usage table
400
+ }
401
+
402
+ /**
403
+ * Add detailed usage table section
404
+ */
405
+ function addUsageTable(lines, usageMap) {
320
406
  lines.push('## Component Usage Details');
321
407
  lines.push('');
322
408
  lines.push('| Component | Type | Usage Count | Used In |');
@@ -334,61 +420,123 @@ function generateReport(usageMap, availableComponents) {
334
420
  lines.push('');
335
421
  lines.push('---');
336
422
  lines.push('');
423
+ }
424
+
425
+ /**
426
+ * Add report footer
427
+ */
428
+ function addReportFooter(lines) {
429
+ const now = new Date();
430
+ const dateStr = now.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
337
431
 
338
- // Most used components
339
- lines.push('## Most Used Components');
432
+ lines.push(`*Last updated: ${dateStr}* `);
433
+ lines.push(`*Generated by ${PACKAGE_NAME} usage report tool*`);
340
434
  lines.push('');
341
- const topComponents = sortedComponents.slice(0, 10);
435
+ }
436
+
437
+ /**
438
+ * Check if running in the library repo itself
439
+ */
440
+ function isLibraryRepo() {
441
+ const pkgJsonPath = path.join(projectRoot, 'package.json');
442
+ if (fs.existsSync(pkgJsonPath)) {
443
+ const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8'));
444
+ return pkgJson.name === PACKAGE_NAME;
445
+ }
446
+ return false;
447
+ }
448
+
449
+ /**
450
+ * Generate sample report for the library repo using Storybook files
451
+ */
452
+ function generateSampleReport() {
453
+ console.log('šŸ“š Detected library repository - generating sample usage report...\n');
342
454
 
343
- topComponents.forEach(([name, usages], index) => {
344
- lines.push(`${index + 1}. **${name}** - ${usages.length} usage${usages.length > 1 ? 's' : ''}`);
345
- });
455
+ const usageMap = scanStoryFiles();
346
456
 
347
- lines.push('');
348
- lines.push('---');
349
- lines.push('');
457
+ console.log(` Found ${usageMap.size} unique components used in stories`);
350
458
 
351
- // Detailed file listings
352
- lines.push('## Detailed File Usage');
353
- lines.push('');
459
+ const pkgJson = JSON.parse(fs.readFileSync(path.join(projectRoot, 'package.json'), 'utf8'));
460
+ const availableComponents = {
461
+ version: pkgJson.version,
462
+ exports: new Set()
463
+ };
354
464
 
355
- categorized.forEach((items, category) => {
356
- if (items.length > 0) {
357
- lines.push(`### ${category}s`);
358
- lines.push('');
359
-
360
- items.sort((a, b) => a.name.localeCompare(b.name));
361
-
362
- items.forEach(({ name, usages }) => {
363
- lines.push(`#### ${name}`);
364
- lines.push('');
365
-
366
- // Group by file
367
- const fileGroups = new Map();
368
- usages.forEach(usage => {
369
- if (!fileGroups.has(usage.file)) {
370
- fileGroups.set(usage.file, []);
371
- }
372
- fileGroups.get(usage.file).push(usage);
373
- });
374
-
375
- fileGroups.forEach((fileUsages, file) => {
376
- const lineNumbers = fileUsages.map(u => u.line).join(', ');
377
- lines.push(`- \`${file}\` (line${fileUsages.length > 1 ? 's' : ''} ${lineNumbers})`);
378
- });
379
-
380
- lines.push('');
381
- });
382
- }
465
+ const report = generateReport(usageMap, availableComponents);
466
+ const sampleNote = createSampleNote();
467
+
468
+ return sampleNote + report;
469
+ }
470
+
471
+ /**
472
+ * Scan Storybook files for component usage
473
+ */
474
+ function scanStoryFiles() {
475
+ const usageMap = new Map();
476
+ const srcPath = path.join(projectRoot, 'src');
477
+ const storyFiles = findFiles(srcPath, ['.stories.js', '.stories.jsx', '.stories.ts', '.stories.tsx']);
478
+
479
+ console.log(` Found ${storyFiles.length} Storybook files to analyze`);
480
+
481
+ storyFiles.forEach(file => {
482
+ const relativePath = path.relative(projectRoot, file);
483
+ const content = fs.readFileSync(file, 'utf8');
484
+
485
+ extractLocalImports(content, relativePath, usageMap);
383
486
  });
384
487
 
385
- lines.push('---');
386
- lines.push('');
387
- lines.push(`*Generated by ${PACKAGE_NAME} usage report tool* `);
388
- lines.push(`*Report generated: ${new Date().toISOString()}*`);
389
- lines.push('');
488
+ return usageMap;
489
+ }
490
+
491
+ /**
492
+ * Extract local imports from file content
493
+ */
494
+ function extractLocalImports(content, relativePath, usageMap) {
495
+ const getLineNumber = (index) => content.substring(0, index).split('\n').length;
390
496
 
391
- return lines.join('\n');
497
+ // Match local imports like: import { Component } from './Component'
498
+ const localImportRegex = /import\s+\{([^}]+)\}\s+from\s+['"]\.\//g;
499
+ const defaultImportRegex = /import\s+(\w+)\s+from\s+['"]\.\//g;
500
+
501
+ for (const match of content.matchAll(localImportRegex)) {
502
+ const names = match[1].split(',').map(n => n.trim()).filter(n => n.length > 0);
503
+ names.forEach(name => {
504
+ if (!usageMap.has(name)) {
505
+ usageMap.set(name, []);
506
+ }
507
+ usageMap.get(name).push({
508
+ file: relativePath,
509
+ line: getLineNumber(match.index),
510
+ type: 'named'
511
+ });
512
+ });
513
+ }
514
+
515
+ for (const match of content.matchAll(defaultImportRegex)) {
516
+ const name = match[1];
517
+ if (!usageMap.has(name)) {
518
+ usageMap.set(name, []);
519
+ }
520
+ usageMap.get(name).push({
521
+ file: relativePath,
522
+ line: getLineNumber(match.index),
523
+ type: 'default'
524
+ });
525
+ }
526
+ }
527
+
528
+ /**
529
+ * Create sample note for library repo reports
530
+ */
531
+ function createSampleNote() {
532
+ return [
533
+ '> **Note**: This is a sample usage report generated from the cmsds-open-data-components library repository.',
534
+ '> It shows how components are used in Storybook files within this repository.',
535
+ '> When run in a project that depends on this library, the report will show actual component usage.',
536
+ '',
537
+ '---',
538
+ ''
539
+ ].join('\n');
392
540
  }
393
541
 
394
542
  /**
@@ -398,6 +546,20 @@ function main() {
398
546
  console.log('šŸ“Š Generating Component Usage Report...\n');
399
547
 
400
548
  try {
549
+ // Check if running in the library repo itself
550
+ if (isLibraryRepo()) {
551
+ const report = generateSampleReport();
552
+ const outputPath = path.join(projectRoot, 'SAMPLE_' + outputFile);
553
+ fs.writeFileSync(outputPath, report, 'utf8');
554
+
555
+ console.log(`\nāœ… Sample usage report generated successfully!`);
556
+ console.log(`šŸ“„ Output: ${outputPath}`);
557
+ console.log(`šŸ“Š File size: ${(Buffer.byteLength(report, 'utf8') / 1024).toFixed(2)} KB`);
558
+ console.log(`\nšŸ’” This sample report shows component usage in Storybook files.`);
559
+ console.log(` To see real usage, run this command in a project that depends on this library.`);
560
+ return;
561
+ }
562
+
401
563
  // Check if package is installed
402
564
  const packagePath = path.join(projectRoot, 'node_modules', PACKAGE_NAME);
403
565
  if (!fs.existsSync(packagePath)) {