@catchdrift/cli 0.1.13 → 0.1.15

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@catchdrift/cli",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "CLI for Drift — install, check, and manage design system coverage for any React app.",
5
5
  "keywords": [
6
6
  "design-system",
@@ -26,6 +26,7 @@ import { chromium } from 'playwright'
26
26
  import { readFileSync, existsSync } from 'fs'
27
27
  import { resolve, dirname } from 'path'
28
28
  import { fileURLToPath } from 'url'
29
+ import { execSync } from 'child_process'
29
30
 
30
31
  const __dirname = dirname(fileURLToPath(import.meta.url))
31
32
  const ROOT = resolve(__dirname, '..')
@@ -63,17 +64,39 @@ const JSON_OUT = has('--json')
63
64
 
64
65
  let DS_COMPONENTS_LIST = []
65
66
 
66
- // Try to load from built manifest (ts-node free approach: read config.ts as text)
67
- const configPath = resolve(ROOT, 'src/ds-coverage/config.ts')
68
- if (existsSync(configPath)) {
67
+ // Check drift.config.ts (created by npx catchdrift init) first,
68
+ // then fall back to the legacy src/ds-coverage/config.ts path.
69
+ const cwd = process.cwd()
70
+ const configCandidates = [
71
+ resolve(cwd, 'drift.config.ts'),
72
+ resolve(cwd, 'src/ds-coverage/config.ts'),
73
+ resolve(ROOT, 'src/ds-coverage/config.ts'),
74
+ ]
75
+ const configPath = configCandidates.find(p => existsSync(p))
76
+
77
+ if (configPath) {
69
78
  const src = readFileSync(configPath, 'utf8')
70
- // Extract component names from the object keys simple regex, no AST needed
71
- const matches = src.match(/^\s{4}(\w+):\s*\{/gm) ?? []
72
- DS_COMPONENTS_LIST = matches.map(m => m.trim().replace(/:\s*\{.*/, ''))
79
+ // Find the components: { ... } block by tracking brace depth
80
+ const compStart = src.indexOf('components:')
81
+ if (compStart !== -1) {
82
+ const braceOpen = src.indexOf('{', compStart)
83
+ let depth = 0
84
+ let end = braceOpen
85
+ for (let i = braceOpen; i < src.length; i++) {
86
+ if (src[i] === '{') depth++
87
+ else if (src[i] === '}') { depth--; if (depth === 0) { end = i; break } }
88
+ }
89
+ const block = src.slice(braceOpen + 1, end)
90
+ // Match PascalCase keys at any indent level: " Button:" or " Button:"
91
+ const matches = block.match(/^\s+([A-Z]\w*)\s*:/gm) ?? []
92
+ DS_COMPONENTS_LIST = matches.map(m => m.trim().replace(/\s*:.*/, ''))
93
+ }
73
94
  }
74
95
 
75
96
  if (DS_COMPONENTS_LIST.length === 0) {
76
- console.warn('⚠ Could not read component list from src/ds-coverage/config.ts — using empty set')
97
+ console.warn('⚠ No components found in drift.config.ts — coverage will show 0%.')
98
+ console.warn(' Run: npx catchdrift sync to auto-populate from your DS package.')
99
+ console.warn()
77
100
  }
78
101
 
79
102
  // ─── Serialisable scanner (injected into the page via page.evaluate) ──────────
@@ -237,8 +260,26 @@ function formatReport(route, result) {
237
260
  // ─── Main ────────────────────────────────────────────────────────────────────
238
261
 
239
262
  async function run() {
240
- const browser = await chromium.launch({ headless: true })
241
- const page = await browser.newPage()
263
+ // Auto-install Playwright's chromium browser if not present
264
+ let browser
265
+ try {
266
+ browser = await chromium.launch({ headless: true })
267
+ } catch (err) {
268
+ if (err.message.includes("Executable doesn't exist") || err.message.includes('browserType.launch')) {
269
+ console.log('Installing Playwright browser (one-time setup)...')
270
+ try {
271
+ execSync('npx playwright install chromium', { stdio: 'inherit' })
272
+ browser = await chromium.launch({ headless: true })
273
+ } catch {
274
+ console.error('Failed to install Playwright browser.')
275
+ console.error('Run manually: npx playwright install chromium')
276
+ process.exit(1)
277
+ }
278
+ } else {
279
+ throw err
280
+ }
281
+ }
282
+ const page = await browser.newPage()
242
283
 
243
284
  const allResults = []
244
285
  let passed = true
@@ -21,7 +21,7 @@ import pc from 'picocolors'
21
21
  const __dirname = dirname(fileURLToPath(import.meta.url))
22
22
 
23
23
  // drift-check.mjs ships in the CLI package under scripts/
24
- const CHECKER = resolve(__dirname, '../../../scripts/drift-check.mjs')
24
+ const CHECKER = resolve(__dirname, '../../scripts/drift-check.mjs')
25
25
 
26
26
  export async function check(argv) {
27
27
  // Read threshold from drift.config.ts if not passed as flag
@@ -15,7 +15,7 @@ import { spawn } from 'child_process'
15
15
  import pc from 'picocolors'
16
16
 
17
17
  const __dirname = dirname(fileURLToPath(import.meta.url))
18
- const SYNCER = resolve(__dirname, '../../../scripts/drift-sync.mjs')
18
+ const SYNCER = resolve(__dirname, '../../scripts/drift-sync.mjs')
19
19
 
20
20
  export async function sync(_argv) {
21
21
  if (!existsSync(SYNCER)) {