UNPKG

@vizzly-testing/cli

Version:

Visual review platform for UI developers and designers

228 lines (212 loc) 6.43 kB
/** * Dynamic context detection for CLI commands * * Detects the current state of Vizzly in the working directory: * - TDD server status * - Project configuration * - Authentication status * - Baseline counts */ import { existsSync, readFileSync } from 'node:fs'; import { homedir } from 'node:os'; import { dirname, join } from 'node:path'; /** * Get dynamic context about the current Vizzly state * Returns an array of context items with type, label, and value * * @returns {Array<{type: 'success'|'warning'|'info', label: string, value: string}>} */ export function getContext() { let items = []; try { let cwd = process.cwd(); let globalConfigPath = join(process.env.VIZZLY_HOME || join(homedir(), '.vizzly'), 'config.json'); // Load global config once let globalConfig = {}; try { if (existsSync(globalConfigPath)) { globalConfig = JSON.parse(readFileSync(globalConfigPath, 'utf8')); } } catch { // Ignore } // Check for vizzly.config.js (project config) let hasProjectConfig = existsSync(join(cwd, 'vizzly.config.js')); // Check for .vizzly directory (TDD baselines) let baselineCount = 0; try { let metaPath = join(cwd, '.vizzly', 'baselines', 'metadata.json'); if (existsSync(metaPath)) { let meta = JSON.parse(readFileSync(metaPath, 'utf8')); baselineCount = meta.screenshots?.length || 0; } } catch { // Ignore } // Check for TDD server running let serverRunning = false; let serverPort = null; try { let serverFile = join(cwd, '.vizzly', 'server.json'); if (existsSync(serverFile)) { let serverInfo = JSON.parse(readFileSync(serverFile, 'utf8')); serverPort = serverInfo.port; serverRunning = true; } } catch { // Ignore } // Check for project mapping (from vizzly project:select) // Traverse up to find project config, with bounds check for Windows compatibility let projectMapping = null; let checkPath = cwd; let prevPath = null; while (checkPath && checkPath !== prevPath) { if (globalConfig.projects?.[checkPath]) { projectMapping = globalConfig.projects[checkPath]; break; } prevPath = checkPath; checkPath = dirname(checkPath); } // Check for OAuth login (from vizzly login) let isLoggedIn = !!globalConfig.auth?.accessToken; let userName = globalConfig.auth?.user?.name || globalConfig.auth?.user?.email; // Check for env token let hasEnvToken = !!process.env.VIZZLY_TOKEN; // Build context items - prioritize most useful info if (serverRunning) { items.push({ type: 'success', label: 'TDD Server', value: `running on :${serverPort}` }); } if (projectMapping) { items.push({ type: 'success', label: 'Project', value: `${projectMapping.projectName} (${projectMapping.organizationSlug})` }); } else if (isLoggedIn && userName) { items.push({ type: 'success', label: 'Logged in', value: userName }); } else if (hasEnvToken) { items.push({ type: 'success', label: 'API Token', value: 'via VIZZLY_TOKEN' }); } else { items.push({ type: 'info', label: 'Not connected', value: 'run vizzly login or project:select' }); } if (baselineCount > 0) { items.push({ type: 'success', label: 'Baselines', value: `${baselineCount} screenshots` }); } if (!hasProjectConfig && !serverRunning && baselineCount === 0) { // Only show "no config" hint if there's nothing else useful items.push({ type: 'info', label: 'Get started', value: 'run vizzly init' }); } } catch { // If anything fails, just return empty - context is optional } return items; } /** * Get detailed context with raw values (for doctor command) * Returns more detailed information suitable for diagnostics * * @returns {Object} Detailed context object */ export function getDetailedContext() { let cwd = process.cwd(); let globalConfigPath = join(process.env.VIZZLY_HOME || join(homedir(), '.vizzly'), 'config.json'); let context = { tddServer: { running: false, port: null }, project: { hasConfig: false, mapping: null }, auth: { loggedIn: false, userName: null, hasEnvToken: false }, baselines: { count: 0, path: null } }; try { // Load global config let globalConfig = {}; try { if (existsSync(globalConfigPath)) { globalConfig = JSON.parse(readFileSync(globalConfigPath, 'utf8')); } } catch { // Ignore } // Check for vizzly.config.js context.project.hasConfig = existsSync(join(cwd, 'vizzly.config.js')); // Check for baselines try { let metaPath = join(cwd, '.vizzly', 'baselines', 'metadata.json'); if (existsSync(metaPath)) { let meta = JSON.parse(readFileSync(metaPath, 'utf8')); context.baselines.count = meta.screenshots?.length || 0; context.baselines.path = join(cwd, '.vizzly', 'baselines'); } } catch { // Ignore } // Check for TDD server try { let serverFile = join(cwd, '.vizzly', 'server.json'); if (existsSync(serverFile)) { let serverInfo = JSON.parse(readFileSync(serverFile, 'utf8')); context.tddServer.running = true; context.tddServer.port = serverInfo.port; } } catch { // Ignore } // Check for project mapping // Traverse up to find project config, with bounds check for Windows compatibility let checkPath = cwd; let prevPath = null; while (checkPath && checkPath !== prevPath) { if (globalConfig.projects?.[checkPath]) { context.project.mapping = globalConfig.projects[checkPath]; break; } prevPath = checkPath; checkPath = dirname(checkPath); } // Check auth status context.auth.loggedIn = !!globalConfig.auth?.accessToken; context.auth.userName = globalConfig.auth?.user?.name || globalConfig.auth?.user?.email; context.auth.hasEnvToken = !!process.env.VIZZLY_TOKEN; } catch { // If anything fails, return defaults } return context; }