@scrymore/scry-sbcov 0.2.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.
Files changed (47) hide show
  1. package/README.md +410 -0
  2. package/bin/scry-sbcov.js +3 -0
  3. package/dist/analyzers/git-analyzer.d.ts +49 -0
  4. package/dist/analyzers/git-analyzer.d.ts.map +1 -0
  5. package/dist/analyzers/git-analyzer.js +265 -0
  6. package/dist/analyzers/git-analyzer.js.map +1 -0
  7. package/dist/cli/config.d.ts +12 -0
  8. package/dist/cli/config.d.ts.map +1 -0
  9. package/dist/cli/config.js +197 -0
  10. package/dist/cli/config.js.map +1 -0
  11. package/dist/cli/index.d.ts +7 -0
  12. package/dist/cli/index.d.ts.map +1 -0
  13. package/dist/cli/index.js +164 -0
  14. package/dist/cli/index.js.map +1 -0
  15. package/dist/core/analyzer.d.ts +19 -0
  16. package/dist/core/analyzer.d.ts.map +1 -0
  17. package/dist/core/analyzer.js +117 -0
  18. package/dist/core/analyzer.js.map +1 -0
  19. package/dist/core/coverage-calculator.d.ts +38 -0
  20. package/dist/core/coverage-calculator.d.ts.map +1 -0
  21. package/dist/core/coverage-calculator.js +335 -0
  22. package/dist/core/coverage-calculator.js.map +1 -0
  23. package/dist/core/report-generator.d.ts +10 -0
  24. package/dist/core/report-generator.d.ts.map +1 -0
  25. package/dist/core/report-generator.js +477 -0
  26. package/dist/core/report-generator.js.map +1 -0
  27. package/dist/core/story-executor.d.ts +22 -0
  28. package/dist/core/story-executor.d.ts.map +1 -0
  29. package/dist/core/story-executor.js +379 -0
  30. package/dist/core/story-executor.js.map +1 -0
  31. package/dist/detectors/component-detector.d.ts +15 -0
  32. package/dist/detectors/component-detector.d.ts.map +1 -0
  33. package/dist/detectors/component-detector.js +632 -0
  34. package/dist/detectors/component-detector.js.map +1 -0
  35. package/dist/index.d.ts +16 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +18 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/parsers/story-parser.d.ts +18 -0
  40. package/dist/parsers/story-parser.d.ts.map +1 -0
  41. package/dist/parsers/story-parser.js +353 -0
  42. package/dist/parsers/story-parser.js.map +1 -0
  43. package/dist/types/index.d.ts +502 -0
  44. package/dist/types/index.d.ts.map +1 -0
  45. package/dist/types/index.js +6 -0
  46. package/dist/types/index.js.map +1 -0
  47. package/package.json +79 -0
package/README.md ADDED
@@ -0,0 +1,410 @@
1
+ # scry-sbcov
2
+
3
+ [![CI](https://github.com/epinnock/scry-sbcov/actions/workflows/ci.yml/badge.svg)](https://github.com/epinnock/scry-sbcov/actions/workflows/ci.yml)
4
+
5
+ A CLI tool that analyzes React component libraries to identify gaps in Storybook story coverage. Generates comprehensive JSON reports suitable for CI integration, quality gates, and coverage tracking.
6
+
7
+ ## Features
8
+
9
+ - **Detect components without stories** - Find React components that have no corresponding Storybook stories
10
+ - **Analyze scenario coverage** - For components with stories, identify missing prop variants and states (loading, error, disabled, etc.)
11
+ - **Track new vs existing code** - SonarQube-style analysis showing coverage metrics separately for new/modified code in PRs
12
+ - **Execute and validate stories** - Run stories to detect broken/failing stories (render errors, play function failures)
13
+ - **Generate actionable reports** - JSON output with suggested story names and args for missing scenarios
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @scrymore/scry-sbcov --save-dev
19
+ ```
20
+
21
+ Or run directly with npx:
22
+
23
+ ```bash
24
+ npx @scrymore/scry-sbcov
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ```bash
30
+ # Basic analysis with output to file
31
+ scry-sbcov --output coverage.json
32
+
33
+ # CI mode with quality gates
34
+ scry-sbcov --ci --base origin/main --threshold-new-code 90
35
+
36
+ # With story execution (requires playwright)
37
+ scry-sbcov --execute --storybook-static ./storybook-static --output report.json
38
+
39
+ # Verbose output
40
+ scry-sbcov -v
41
+ ```
42
+
43
+ ## CLI Options
44
+
45
+ ```
46
+ scry-sbcov [options]
47
+
48
+ Options:
49
+ -c, --config <path> Path to config file (default: scry-sbcov.config.js)
50
+ -o, --output <path> Output JSON report path (default: stdout)
51
+ --include <glob> Component file patterns (comma-separated)
52
+ --exclude <glob> Patterns to exclude (comma-separated)
53
+ --stories <glob> Story file patterns (comma-separated)
54
+ --base <branch> Base branch for new code analysis (default: main)
55
+ --no-git Disable git-based new code analysis
56
+ --execute Run stories and capture failures
57
+ --storybook-url <url> Storybook URL for execution (default: http://localhost:6006)
58
+ --storybook-static <dir> Path to static Storybook build
59
+ --ci CI mode: exit code 1 if quality gate fails
60
+ --threshold-component <n> Component coverage threshold % (default: 80)
61
+ --threshold-new-code <n> New code coverage threshold % (default: 90)
62
+ -v, --verbose Verbose output
63
+ --version Show version
64
+ --help Show help
65
+ ```
66
+
67
+ ## Configuration
68
+
69
+ Create a `scry-sbcov.config.js` file in your project root:
70
+
71
+ ```javascript
72
+ // scry-sbcov.config.js
73
+ module.exports = {
74
+ // Component detection
75
+ include: ['src/components/**/*.tsx'],
76
+ exclude: ['**/*.test.tsx', '**/*.spec.tsx', '**/index.tsx', '**/__mocks__/**'],
77
+
78
+ // Story detection
79
+ storyPatterns: ['**/*.stories.tsx', '**/*.stories.ts'],
80
+
81
+ // Git analysis
82
+ baseBranch: 'main',
83
+ enableGitAnalysis: true,
84
+
85
+ // Story execution
86
+ execute: false,
87
+ storybookUrl: 'http://localhost:6006',
88
+ storybookStaticDir: null,
89
+ executionTimeout: 15000,
90
+
91
+ // Quality gates
92
+ thresholds: {
93
+ componentCoverage: 80,
94
+ propCoverage: 70,
95
+ variantCoverage: 60,
96
+ newCodeCoverage: 90,
97
+ },
98
+
99
+ // Output
100
+ outputPath: './scry-sbcov-report.json',
101
+
102
+ // Scenario detection customization
103
+ scenarioPatterns: {
104
+ loading: ['isLoading', 'loading', 'isProcessing'],
105
+ error: ['isError', 'hasError', 'error', 'errorMessage'],
106
+ empty: ['isEmpty', 'empty', 'noData'],
107
+ disabled: ['disabled', 'isDisabled'],
108
+ },
109
+
110
+ // Component matching overrides
111
+ componentStoryMapping: {
112
+ // Manual overrides for complex cases
113
+ 'src/components/Button/BaseButton.tsx': 'src/components/Button/Button.stories.tsx',
114
+ },
115
+ };
116
+ ```
117
+
118
+ You can also add configuration to `package.json`:
119
+
120
+ ```json
121
+ {
122
+ "scry-sbcov": {
123
+ "include": ["src/components/**/*.tsx"],
124
+ "thresholds": {
125
+ "componentCoverage": 85
126
+ }
127
+ }
128
+ }
129
+ ```
130
+
131
+ ## Report Output
132
+
133
+ The tool generates a comprehensive JSON report with the following structure:
134
+
135
+ ```typescript
136
+ interface StoryCoverageReport {
137
+ version: '1.0.0';
138
+ generatedAt: string;
139
+
140
+ // Git context
141
+ git: {
142
+ commitSha: string;
143
+ branch: string;
144
+ baseBranch: string | null;
145
+ baseCommitSha: string | null;
146
+ };
147
+
148
+ // Summary metrics
149
+ summary: {
150
+ totalComponents: number;
151
+ componentsWithStories: number;
152
+ componentsWithoutStories: number;
153
+ totalStoryFiles: number;
154
+ totalStories: number;
155
+ metrics: {
156
+ componentCoverage: number;
157
+ propCoverage: number;
158
+ variantCoverage: number;
159
+ scenarioCoverage: number;
160
+ };
161
+ health: {
162
+ status: 'healthy' | 'degraded' | 'broken' | 'not_executed';
163
+ passingStories: number;
164
+ failingStories: number;
165
+ passRate: number;
166
+ };
167
+ };
168
+
169
+ // New code analysis
170
+ newCode: {
171
+ enabled: boolean;
172
+ since: string;
173
+ newComponents: { total: number; withStories: number; coverage: number };
174
+ modifiedComponents: { total: number; newPropsAdded: number; coverage: number };
175
+ };
176
+
177
+ // Per-component coverage
178
+ components: ComponentCoverage[];
179
+
180
+ // Actionable recommendations
181
+ missingScenarios: MissingScenario[];
182
+ uncoveredComponents: UncoveredComponent[];
183
+
184
+ // Quality gate results
185
+ qualityGate: {
186
+ passed: boolean;
187
+ checks: QualityCheck[];
188
+ };
189
+ }
190
+ ```
191
+
192
+ ## CI Integration
193
+
194
+ ### GitHub Actions
195
+
196
+ ```yaml
197
+ name: Story Coverage
198
+ on: [pull_request]
199
+
200
+ jobs:
201
+ coverage:
202
+ runs-on: ubuntu-latest
203
+ steps:
204
+ - uses: actions/checkout@v4
205
+ with:
206
+ fetch-depth: 0 # Required for git analysis
207
+
208
+ - uses: actions/setup-node@v4
209
+ with:
210
+ node-version: '20'
211
+ cache: 'npm'
212
+
213
+ - run: npm ci
214
+
215
+ - name: Build Storybook
216
+ run: npm run build-storybook
217
+
218
+ - name: Run scry-sbcov
219
+ run: |
220
+ npx scry-sbcov \
221
+ --base origin/main \
222
+ --execute \
223
+ --storybook-static ./storybook-static \
224
+ --output coverage-report.json \
225
+ --ci
226
+
227
+ - name: Upload Report
228
+ uses: actions/upload-artifact@v4
229
+ with:
230
+ name: story-coverage-report
231
+ path: coverage-report.json
232
+ ```
233
+
234
+ ### GitLab CI
235
+
236
+ ```yaml
237
+ stages:
238
+ - build
239
+ - test
240
+
241
+ build-storybook:
242
+ stage: build
243
+ image: node:20
244
+ script:
245
+ - npm ci
246
+ - npm run build-storybook
247
+ artifacts:
248
+ paths:
249
+ - storybook-static
250
+ expire_in: 1 hour
251
+
252
+ story-coverage:
253
+ stage: test
254
+ image: node:20
255
+ needs:
256
+ - job: build-storybook
257
+ artifacts: true
258
+ variables:
259
+ GIT_DEPTH: 0 # Required for git analysis
260
+ script:
261
+ - npm ci
262
+ - npx scry-sbcov --base origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME --output coverage-report.json --ci
263
+ artifacts:
264
+ paths:
265
+ - coverage-report.json
266
+ ```
267
+
268
+ ## Programmatic Usage
269
+
270
+ ```typescript
271
+ import { analyze, loadConfig } from '@scrymore/scry-sbcov';
272
+
273
+ const config = await loadConfig({
274
+ base: 'main',
275
+ thresholdComponent: 80,
276
+ });
277
+
278
+ const report = await analyze(process.cwd(), config, true);
279
+
280
+ console.log(`Coverage: ${report.summary.metrics.componentCoverage}%`);
281
+ console.log(`Quality Gate: ${report.qualityGate.passed ? 'PASSED' : 'FAILED'}`);
282
+ ```
283
+
284
+ ## Detected Patterns
285
+
286
+ ### Component Types
287
+ - Function components
288
+ - Arrow function components
289
+ - `forwardRef` wrapped components
290
+ - `memo` wrapped components
291
+ - Class components (extending React.Component/PureComponent)
292
+ - HOC-wrapped components
293
+
294
+ ### Scenario Detection
295
+ The tool automatically detects common UI scenarios based on prop naming patterns:
296
+
297
+ | Pattern | Scenario |
298
+ |---------|----------|
299
+ | `isLoading`, `loading`, `isProcessing` | Loading State |
300
+ | `isError`, `hasError`, `error` | Error State |
301
+ | `isEmpty`, `empty`, `noData` | Empty State |
302
+ | `disabled`, `isDisabled` | Disabled State |
303
+ | `isOpen`, `open`, `expanded` | Open State |
304
+ | `isVisible`, `visible`, `hidden` | Visibility State |
305
+ | `isSelected`, `selected`, `checked` | Selection State |
306
+
307
+ ### Variant Coverage
308
+ For props with union literal types (e.g., `variant: 'primary' | 'secondary'`), the tool tracks which specific values are covered by stories.
309
+
310
+ ## Story Execution
311
+
312
+ To detect broken stories at runtime, install Playwright:
313
+
314
+ ```bash
315
+ npm install playwright --save-dev
316
+ ```
317
+
318
+ Then run with the `--execute` flag:
319
+
320
+ ```bash
321
+ scry-sbcov --execute --storybook-url http://localhost:6006
322
+ # or with a static build
323
+ scry-sbcov --execute --storybook-static ./storybook-static
324
+ ```
325
+
326
+ Story execution detects:
327
+ - Render errors
328
+ - Play function failures
329
+ - Console errors
330
+ - Timeouts
331
+
332
+ ## Requirements
333
+
334
+ - Node.js >= 18.0.0
335
+ - TypeScript project (for full prop extraction)
336
+ - Storybook (CSF 3 format recommended)
337
+
338
+ ## Optional Dependencies
339
+
340
+ - `playwright` - Required for story execution
341
+
342
+ ## Development
343
+
344
+ ### Setup
345
+
346
+ ```bash
347
+ git clone https://github.com/epinnock/scry-sbcov.git
348
+ cd scry-sbcov
349
+ npm install
350
+ ```
351
+
352
+ ### Available Scripts
353
+
354
+ ```bash
355
+ npm run build # Build TypeScript to dist/
356
+ npm run dev # Build in watch mode
357
+ npm run test # Run tests in watch mode
358
+ npm run test:run # Run tests once
359
+ npm run test:coverage # Run tests with coverage report
360
+ npm run lint # Run ESLint
361
+ npm run typecheck # Run TypeScript type checking
362
+ ```
363
+
364
+ ### CI Checks
365
+
366
+ Pull requests automatically run the following checks:
367
+
368
+ | Check | Command | Description |
369
+ |-------|---------|-------------|
370
+ | Type Check | `npm run typecheck` | Validates TypeScript types |
371
+ | Lint | `npm run lint` | Checks code style with ESLint |
372
+ | Tests | `npm run test:run` | Runs unit and integration tests |
373
+ | Build | `npm run build` | Ensures project compiles |
374
+ | Dogfood | CLI on fixtures | Runs scry-sbcov on test fixtures |
375
+
376
+ Tests run on Node.js 18, 20, and 22 to ensure compatibility.
377
+
378
+ ### Project Structure
379
+
380
+ ```
381
+ scry-sbcov/
382
+ ├── src/
383
+ │ ├── cli/ # CLI entry point and config loading
384
+ │ ├── core/ # Main analyzer, coverage calc, report gen
385
+ │ ├── detectors/ # Component detection (ts-morph)
386
+ │ ├── parsers/ # Story file parsing
387
+ │ ├── analyzers/ # Git analysis
388
+ │ └── types/ # TypeScript interfaces
389
+ ├── tests/
390
+ │ ├── fixtures/ # Sample React components for testing
391
+ │ └── *.test.ts # Test files
392
+ └── bin/ # CLI executable
393
+ ```
394
+
395
+ ## Contributing
396
+
397
+ 1. Fork the repository
398
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
399
+ 3. Make your changes
400
+ 4. Ensure all CI checks pass locally:
401
+ ```bash
402
+ npm run typecheck && npm run lint && npm run test:run && npm run build
403
+ ```
404
+ 5. Commit your changes (`git commit -m 'Add amazing feature'`)
405
+ 6. Push to the branch (`git push origin feature/amazing-feature`)
406
+ 7. Open a Pull Request
407
+
408
+ ## License
409
+
410
+ MIT
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ import('../dist/cli/index.js');
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Git Analyzer
3
+ * Identifies new and modified files compared to a base branch for "new code" coverage analysis
4
+ */
5
+ import type { GitAnalysis } from '../types/index.js';
6
+ /**
7
+ * Analyze git changes compared to a base branch
8
+ */
9
+ export declare function analyzeGitChanges(projectPath: string, baseBranch: string, verbose?: boolean): Promise<GitAnalysis>;
10
+ /**
11
+ * Check if a file is new
12
+ */
13
+ export declare function isFileNew(filePath: string, gitAnalysis: GitAnalysis): boolean;
14
+ /**
15
+ * Check if a file is modified
16
+ */
17
+ export declare function isFileModified(filePath: string, gitAnalysis: GitAnalysis): boolean;
18
+ /**
19
+ * Check if a file has changed (new or modified)
20
+ */
21
+ export declare function isFileChanged(filePath: string, gitAnalysis: GitAnalysis): boolean;
22
+ /**
23
+ * Get new lines in a file
24
+ */
25
+ export declare function getNewLinesInFile(filePath: string, gitAnalysis: GitAnalysis): number[];
26
+ /**
27
+ * Get the number of added lines in a file
28
+ */
29
+ export declare function getAddedLineCount(filePath: string, gitAnalysis: GitAnalysis): number;
30
+ /**
31
+ * Get the number of modified (changed but not added) lines
32
+ */
33
+ export declare function getModifiedLineCount(filePath: string, gitAnalysis: GitAnalysis): number;
34
+ /**
35
+ * Get change status for a file
36
+ */
37
+ export declare function getFileChangeStatus(filePath: string, gitAnalysis: GitAnalysis): 'new' | 'modified' | 'unchanged';
38
+ /**
39
+ * Check if git analysis detected a shallow clone
40
+ */
41
+ export declare function checkForShallowClone(projectPath: string): Promise<boolean>;
42
+ /**
43
+ * Get information about the git repository
44
+ */
45
+ export declare function getGitInfo(projectPath: string): Promise<{
46
+ commitSha: string;
47
+ branch: string;
48
+ } | null>;
49
+ //# sourceMappingURL=git-analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-analyzer.d.ts","sourceRoot":"","sources":["../../src/analyzers/git-analyzer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAe,MAAM,mBAAmB,CAAC;AAElE;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,OAAO,UAAQ,GACd,OAAO,CAAC,WAAW,CAAC,CAyEtB;AAuED;;GAEG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAO7E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAQlF;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAOjF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,GAAG,MAAM,EAAE,CAgBtF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,GAAG,MAAM,CAGpF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,GAAG,MAAM,CAavF;AAUD;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,WAAW,GACvB,KAAK,GAAG,UAAU,GAAG,WAAW,CAYlC;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAShF;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAmBvD"}