vibertest 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts","../src/scanner/orchestrator.ts","../src/config/index.ts","../src/config/schema.ts","../src/scanner/file-collector.ts","../src/scanner/parser.ts","../src/rules/base-rule.ts","../src/rules/oversized-files.ts","../src/rules/dead-code.ts","../src/rules/hardcoded-secrets.ts","../src/rules/unused-deps.ts","../src/rules/analysis-helpers.ts","../src/rules/missing-tests.ts","../src/rules/pattern-inconsistency.ts","../src/rules/poor-maintainability.ts","../src/rules/missing-error-handling.ts","../src/rules/abandoned-todo.ts","../src/rules/bloated-barrel.ts","../src/rules/style-inconsistency.ts","../src/rules/duplicate-deps.ts","../src/rules/god-file.ts","../src/rules/separation-of-concerns.ts","../src/rules/obsolete-patterns.ts","../src/rules/ai-smell.ts","../src/rules/code-duplication-helpers.ts","../src/rules/code-duplication.ts","../src/rules/circular-deps.ts","../src/rules/security-antipatterns.ts","../src/rules/react-performance.ts","../src/rules/missing-project-standards.ts","../src/rules/missing-compliance.ts","../src/rules/accessibility.ts","../src/rules/missing-production-basics.ts","../src/rules/index.ts","../src/scorer/index.ts","../src/reporter/terminal.ts","../src/reporter/theme.ts","../src/reporter/summary.ts","../src/reporter/json.ts","../src/cloud/auth.ts","../src/cloud/credentials.ts","../src/cloud/api.ts","../src/index.ts"],"sourcesContent":["import { Command, Option } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport { RULE_ID } from '@vibertest/shared';\nimport type { RuleId, ScanOptions, ViberTestReport } from '@vibertest/shared';\nimport { scan } from './scanner/orchestrator.js';\nimport type { ScanProgress } from './scanner/orchestrator.js';\nimport { renderTerminalReport, renderBanner } from './reporter/terminal.js';\nimport { writeJsonReport } from './reporter/json.js';\nimport { login, logout, whoami } from './cloud/auth.js';\nimport { loadCredentials } from './cloud/credentials.js';\nimport { uploadScan, CloudApiError } from './cloud/api.js';\nimport type { GitContext } from './cloud/api.js';\n\nconst VERSION = '0.1.0';\n\n/**\n * Creates and configures the CLI program.\n * Separated from execution for testability.\n */\nexport function createProgram(): Command {\n const program = new Command();\n\n program\n .name('vibertest')\n .description(\"Your AI writes code. ViberTest makes sure it doesn't suck.\")\n .version(VERSION, '-v, --version');\n\n // Default command: scan\n program\n .command('scan [path]', { isDefault: true })\n .description('Scan a project for vibecoding issues')\n .option('-r, --rules <rules>', 'Comma-separated list of rules to run')\n .option('-f, --format <format>', 'Output format: terminal, json', 'terminal')\n .option('-o, --output <path>', 'Output file path for json/html reports')\n .option('-s, --silent', 'Suppress terminal output (useful with --format json)')\n .addOption(new Option('-u, --upload', 'Upload scan results to ViberTest Cloud').default(false).hideHelp())\n .addOption(new Option('--branch <branch>', 'Git branch name (for --upload)').hideHelp())\n .addOption(new Option('--commit <sha>', 'Git commit SHA (for --upload)').hideHelp())\n .addOption(new Option('--pr <number>', 'Pull request number (for --upload)').hideHelp())\n .action(async (path: string | undefined, options: ScanCommandOptions) => {\n await handleScan(path ?? '.', options);\n });\n\n // Report command (Cloud — hidden until ready)\n program\n .command('report [path]', { hidden: true })\n .option('-f, --format <format>', 'Report format: json, html', 'json')\n .option('-o, --output <path>', 'Output file path')\n .action(async (path: string | undefined, options: ReportCommandOptions) => {\n await handleScan(path ?? '.', {\n format: options.format ?? 'json',\n output: options.output,\n silent: false,\n });\n });\n\n // Init command\n program\n .command('init')\n .description('Create a .vibertestrc.json config file')\n .action(async () => {\n await handleInit();\n });\n\n // Cloud: login (hidden until ready)\n program\n .command('login', { hidden: true })\n .option('--cloud-url <url>', 'Cloud API URL (default: http://localhost:3000)')\n .action(async (options: LoginCommandOptions) => {\n await login(options.cloudUrl);\n });\n\n // Cloud: logout (hidden until ready)\n program\n .command('logout', { hidden: true })\n .action(async () => {\n await logout();\n });\n\n // Cloud: whoami (hidden until ready)\n program\n .command('whoami', { hidden: true })\n .action(async () => {\n await whoami();\n });\n\n // Handle unknown commands\n program.on('command:*', () => {\n console.error(chalk.red('Unknown command:'), program.args.join(' '));\n console.error('Run', chalk.cyan('vibertest --help'), 'for usage');\n process.exit(1);\n });\n\n return program;\n}\n\n// ---------------------------------------------------------------------------\n// Command Option Types\n// ---------------------------------------------------------------------------\n\ninterface ScanCommandOptions {\n rules?: string;\n format?: string;\n output?: string;\n silent?: boolean;\n upload?: boolean;\n branch?: string;\n commit?: string;\n pr?: string;\n}\n\ninterface ReportCommandOptions {\n format?: string;\n output?: string;\n}\n\ninterface LoginCommandOptions {\n cloudUrl?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Command Handlers\n// ---------------------------------------------------------------------------\n\nasync function handleScan(targetPath: string, options: ScanCommandOptions): Promise<void> {\n const isSilent = options.silent ?? false;\n\n // Show banner ONCE at the start\n if (!isSilent) {\n console.log(renderBanner(VERSION));\n }\n\n // Parse rule IDs if provided\n const ruleIds = options.rules ? parseRuleIds(options.rules) : undefined;\n\n const scanOptions: ScanOptions = {\n targetPath,\n rules: ruleIds,\n };\n\n // Create progress reporter with tree-style output\n const progress = isSilent ? undefined : createTreeProgress();\n\n try {\n const report = await scan(scanOptions, progress);\n\n // Render results (score + issues + summary, NO banner)\n if (!isSilent) {\n console.log(renderTerminalReport(report));\n }\n\n // JSON output\n if (options.format === 'json') {\n const outputPath = await writeJsonReport(report, options.output);\n if (!isSilent) {\n console.log(chalk.dim(` 📄 Report saved: ${outputPath}\\n`));\n }\n }\n\n // Upload to Cloud if requested\n if (options.upload) {\n await handleUpload(report, options, isSilent);\n }\n\n // Exit with code 1 if issues found (useful for CI)\n if (report.summary.totalIssues > 0) {\n process.exitCode = 1;\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n console.error(chalk.red('\\n ✗ Scan failed:'), message);\n process.exit(2);\n }\n}\n\nasync function handleUpload(\n report: ViberTestReport,\n options: ScanCommandOptions,\n isSilent: boolean,\n): Promise<void> {\n const credentials = await loadCredentials();\n\n if (!credentials) {\n if (!isSilent) {\n console.log(chalk.yellow(' ⚠ Not logged in — skipping upload.'));\n console.log(chalk.dim(' Run'), chalk.cyan('vibertest login'), chalk.dim('to authenticate.\\n'));\n }\n return;\n }\n\n const spinner = isSilent ? null : ora({ color: 'magenta', indent: 2 });\n\n try {\n spinner?.start('Uploading to ViberTest Cloud...');\n\n const gitContext: GitContext = {\n branch: options.branch ?? tryDetectGitBranch(),\n commitSha: options.commit ?? tryDetectGitCommit(),\n prNumber: options.pr,\n };\n\n const result = await uploadScan(\n credentials.cloudUrl,\n credentials.apiKey,\n report,\n gitContext,\n );\n\n spinner?.succeed('Uploaded to ViberTest Cloud');\n\n if (!isSilent) {\n console.log(\n chalk.dim(' View at:'),\n chalk.cyan(`${credentials.cloudUrl}${result.url}`),\n '\\n',\n );\n }\n } catch (error) {\n spinner?.fail('Upload failed');\n\n if (error instanceof CloudApiError) {\n if (!isSilent) {\n console.error(chalk.red(` ✗ ${error.apiError}`));\n\n if (error.statusCode === 401) {\n console.error(chalk.dim(' Your API key may be invalid. Run'), chalk.cyan('vibertest login'), chalk.dim('to re-authenticate.\\n'));\n }\n }\n } else {\n const message = error instanceof Error ? error.message : String(error);\n if (!isSilent) {\n console.error(chalk.red(` ✗ ${message}\\n`));\n }\n }\n\n // Upload failure should NOT fail the scan — just warn\n }\n}\n\nasync function handleInit(): Promise<void> {\n try {\n const { writeFile } = await import('node:fs/promises');\n const { resolve } = await import('node:path');\n const { DEFAULT_CONFIG } = await import('./config/defaults.js');\n\n const configPath = resolve('.vibertestrc.json');\n const content = JSON.stringify(DEFAULT_CONFIG, null, 2);\n\n await writeFile(configPath, content, 'utf-8');\n console.log(chalk.green(' ✓ Created'), chalk.cyan(configPath));\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.error(chalk.red(' ✗ Failed to create config:'), message);\n process.exit(2);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Tree-style Progress\n// ---------------------------------------------------------------------------\n\nfunction createTreeProgress(): ScanProgress {\n const spinner = ora({\n color: 'magenta',\n indent: 2,\n });\n\n return {\n onPhase(phase: string) {\n spinner.start(phase);\n },\n onFileCount(count: number) {\n spinner.succeed(chalk.dim(`${count} files collected`));\n },\n onRuleStart(ruleName: string) {\n spinner.start(chalk.dim(`Analyzing: ${ruleName}`));\n },\n onRuleComplete(ruleName: string) {\n spinner.succeed(chalk.dim(ruleName));\n },\n onComplete() {\n spinner.stop();\n console.log(chalk.green(' ✓') + chalk.dim(' Scan complete\\n'));\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Git Detection Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Try to detect the current git branch from the environment or git command.\n * Returns undefined if detection fails (non-fatal).\n */\nfunction tryDetectGitBranch(): string | undefined {\n // CI environment variables (GitHub Actions, GitLab CI, etc.)\n const envBranch =\n process.env['GITHUB_HEAD_REF'] ??\n process.env['GITHUB_REF_NAME'] ??\n process.env['CI_COMMIT_BRANCH'] ??\n process.env['BRANCH_NAME'];\n\n if (envBranch) return envBranch;\n\n try {\n const { execSync } = require('node:child_process') as typeof import('node:child_process');\n const branch = execSync('git rev-parse --abbrev-ref HEAD', {\n encoding: 'utf-8',\n timeout: 3000,\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n return branch === 'HEAD' ? undefined : branch;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Try to detect the current git commit SHA.\n * Returns undefined if detection fails (non-fatal).\n */\nfunction tryDetectGitCommit(): string | undefined {\n const envCommit =\n process.env['GITHUB_SHA'] ??\n process.env['CI_COMMIT_SHA'] ??\n process.env['GIT_COMMIT'];\n\n if (envCommit) return envCommit;\n\n try {\n const { execSync } = require('node:child_process') as typeof import('node:child_process');\n return execSync('git rev-parse --short HEAD', {\n encoding: 'utf-8',\n timeout: 3000,\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n } catch {\n return undefined;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Rule ID Parser\n// ---------------------------------------------------------------------------\n\nfunction parseRuleIds(input: string): RuleId[] {\n const validIds = new Set(Object.values(RULE_ID));\n const ids = input.split(',').map((s) => s.trim());\n\n const parsed: RuleId[] = [];\n for (const id of ids) {\n if (validIds.has(id as RuleId)) {\n parsed.push(id as RuleId);\n } else {\n console.warn(chalk.yellow(` ⚠ Unknown rule \"${id}\", skipping`));\n }\n }\n\n return parsed;\n}\n","import { readFile } from 'node:fs/promises';\nimport { resolve, join } from 'node:path';\nimport type {\n ViberTestReport,\n ViberTestConfig,\n PackageJson,\n ProjectFile,\n ScanOptions,\n ReportSummary,\n SeverityBreakdown,\n Issue,\n} from '@vibertest/shared';\nimport { loadConfig } from '../config/index.js';\nimport { collectFiles } from './file-collector.js';\nimport { clearParserCache } from './parser.js';\nimport { runRules } from '../rules/index.js';\nimport { calculateScore } from '../scorer/index.js';\n\n/** ViberTest version - injected at build time or read from package.json */\nconst VERSION = '0.1.0';\n\n/**\n * Progress callback for reporting scan phases to the terminal.\n */\nexport interface ScanProgress {\n onPhase(phase: string): void;\n onFileCount(count: number): void;\n onRuleStart(ruleName: string): void;\n onRuleComplete(ruleName: string): void;\n onComplete(): void;\n}\n\n/** No-op progress for silent mode */\nconst silentProgress: ScanProgress = {\n onPhase: () => {},\n onFileCount: () => {},\n onRuleStart: () => {},\n onRuleComplete: () => {},\n onComplete: () => {},\n};\n\n/**\n * The main scan orchestrator.\n * Wires together: Config → FileCollector → RuleEngine → ScoreEngine → Report\n */\nexport async function scan(\n options: ScanOptions,\n progress: ScanProgress = silentProgress,\n): Promise<ViberTestReport> {\n try {\n const startTime = performance.now();\n const targetPath = resolve(options.targetPath);\n\n const { config, files, packageJson } = await collectScanInputs(targetPath, progress);\n\n // Run rules\n progress.onPhase('Running rules...');\n const issues = await runRules({ files, config, packageJson, projectRoot: targetPath }, options.rules, {\n onRuleStart: (name) => progress.onRuleStart(name),\n onRuleComplete: (name) => progress.onRuleComplete(name),\n });\n\n // Calculate score & build report\n progress.onPhase('Calculating score...');\n const score = calculateScore(issues);\n const scanDuration = Number(((performance.now() - startTime) / 1000).toFixed(3));\n\n clearParserCache();\n progress.onComplete();\n\n return buildReport({ targetPath, packageJson, scanDuration, score, issues, files });\n } catch (error) {\n throw new Error(`Scan failed: ${error instanceof Error ? error.message : String(error)}`);\n }\n}\n\n/** Collects config, files, and package.json for the scan */\nasync function collectScanInputs(\n targetPath: string,\n progress: ScanProgress,\n): Promise<{ config: ViberTestConfig; files: ProjectFile[]; packageJson: PackageJson | null }> {\n progress.onPhase('Loading configuration...');\n const config = await loadConfig(targetPath);\n\n progress.onPhase('Collecting files...');\n const files = await collectFiles({ rootDir: targetPath, ignore: config.ignore });\n progress.onFileCount(files.length);\n\n const packageJson = await loadPackageJson(targetPath);\n\n return { config, files, packageJson };\n}\n\n/** Assembles the final report object */\nfunction buildReport(params: {\n targetPath: string;\n packageJson: PackageJson | null;\n scanDuration: number;\n score: ReturnType<typeof calculateScore>;\n issues: Issue[];\n files: ProjectFile[];\n}): ViberTestReport {\n const { targetPath, packageJson, scanDuration, score, issues, files } = params;\n\n return {\n version: VERSION,\n timestamp: new Date().toISOString(),\n projectName: packageJson?.name ?? targetPath.split('/').pop() ?? 'unknown',\n projectPath: targetPath,\n scanDuration,\n score,\n summary: buildSummary(files.length, issues),\n issues,\n metadata: {\n nodeVersion: process.version,\n platform: process.platform,\n configUsed: false,\n },\n };\n}\n\n/** Attempts to load package.json from the target directory */\nasync function loadPackageJson(targetPath: string): Promise<PackageJson | null> {\n try {\n const content = await readFile(join(targetPath, 'package.json'), 'utf-8');\n return JSON.parse(content) as PackageJson;\n } catch {\n return null;\n }\n}\n\n/** Builds the report summary from issues */\nfunction buildSummary(totalFiles: number, issues: readonly Issue[]): ReportSummary {\n const issuesBySeverity: SeverityBreakdown = {\n critical: 0,\n high: 0,\n medium: 0,\n low: 0,\n info: 0,\n };\n\n const issuesByRule: Record<string, number> = {};\n\n for (const issue of issues) {\n const severityKey = issue.severity as keyof SeverityBreakdown;\n issuesBySeverity[severityKey] = (issuesBySeverity[severityKey] ?? 0) + 1;\n issuesByRule[issue.ruleId] = (issuesByRule[issue.ruleId] ?? 0) + 1;\n }\n\n return {\n totalFiles,\n totalIssues: issues.length,\n issuesBySeverity,\n issuesByRule,\n skippedFiles: [],\n };\n}\n","import { cosmiconfig } from 'cosmiconfig';\nimport type { ViberTestConfig, RuleId } from '@vibertest/shared';\nimport { DEFAULT_CONFIG } from './defaults.js';\nimport { configSchema } from './schema.js';\n\nconst MODULE_NAME = 'vibertest';\n\n/**\n * Loads and merges user configuration with defaults.\n * Searches for: .vibertestrc.json, .vibertestrc.yaml, vibertest.config.js, etc.\n */\nexport async function loadConfig(searchFrom?: string): Promise<ViberTestConfig> {\n try {\n const explorer = cosmiconfig(MODULE_NAME, {\n searchPlaces: [\n `.${MODULE_NAME}rc.json`,\n `.${MODULE_NAME}rc.yaml`,\n `.${MODULE_NAME}rc.yml`,\n `${MODULE_NAME}.config.js`,\n `${MODULE_NAME}.config.ts`,\n ],\n });\n\n const searchResult = await explorer.search(searchFrom);\n\n if (!searchResult || searchResult.isEmpty) {\n return DEFAULT_CONFIG;\n }\n\n const parsed = configSchema.safeParse(searchResult.config);\n\n if (!parsed.success) {\n const errors = parsed.error.issues\n .map((issue) => ` - ${issue.path.join('.')}: ${issue.message}`)\n .join('\\n');\n\n throw new Error(`Invalid ViberTest config at ${searchResult.filepath}:\\n${errors}`);\n }\n\n return mergeConfig(DEFAULT_CONFIG, parsed.data);\n } catch (error) {\n if (error instanceof Error && error.message.startsWith('Invalid ViberTest config')) {\n throw error;\n }\n throw new Error(`Failed to load config: ${error instanceof Error ? error.message : String(error)}`);\n }\n}\n\n/**\n * Deep merges user config with defaults.\n * User values override defaults; missing values use defaults.\n */\nfunction mergeConfig(\n defaults: ViberTestConfig,\n userConfig: Partial<Record<string, unknown>>,\n): ViberTestConfig {\n const userRules = (userConfig.rules ?? {}) as Record<string, Record<string, unknown>>;\n const userIgnore = userConfig.ignore as string[] | undefined;\n const userThresholds = (userConfig.thresholds ?? {}) as Record<string, unknown>;\n\n const mergedRules = { ...defaults.rules };\n for (const [ruleId, ruleConfig] of Object.entries(userRules)) {\n const key = ruleId as RuleId;\n if (mergedRules[key]) {\n mergedRules[key] = { ...mergedRules[key], ...ruleConfig };\n }\n }\n\n return {\n rules: mergedRules,\n ignore: userIgnore ?? defaults.ignore,\n thresholds: {\n ...defaults.thresholds,\n ...userThresholds,\n },\n };\n}\n\nexport { DEFAULT_CONFIG } from './defaults.js';\nexport { configSchema } from './schema.js';\n","import { z } from 'zod';\nimport { RULE_ID } from '@vibertest/shared';\n\n/**\n * Zod schema for validating .vibertestrc.json configuration.\n * Uses Zod 3 syntax (project uses zod ^3.24).\n */\n\nconst ruleConfigSchema = z.object({\n enabled: z.boolean().default(true),\n}).passthrough();\n\nconst ruleIds = Object.values(RULE_ID);\n\nconst rulesSchema = z.record(\n z.enum(ruleIds as [string, ...string[]]),\n ruleConfigSchema,\n).optional();\n\nconst thresholdsSchema = z.object({\n maxFileLines: z.number().int().positive().default(500),\n maxFunctionLines: z.number().int().positive().default(50),\n maxFunctionParams: z.number().int().positive().default(4),\n maxImports: z.number().int().positive().default(15),\n minTestRatio: z.number().min(0).max(1).default(0.2),\n}).partial();\n\nexport const configSchema = z.object({\n rules: rulesSchema,\n ignore: z.array(z.string()).optional(),\n thresholds: thresholdsSchema.optional(),\n}).strict();\n\n","import fg from 'fast-glob';\nimport { readFile } from 'node:fs/promises';\nimport { resolve, relative, extname } from 'node:path';\nimport type { ProjectFile } from '@vibertest/shared';\nimport { SOURCE_EXTENSIONS, DEFAULT_IGNORE_PATTERNS } from '../config/defaults.js';\n\ninterface CollectorOptions {\n readonly rootDir: string;\n readonly ignore: readonly string[];\n}\n\n/**\n * Collects all JS/TS source files from a project directory.\n * Respects ignore patterns and .gitignore.\n */\nexport async function collectFiles(options: CollectorOptions): Promise<ProjectFile[]> {\n try {\n const { rootDir, ignore } = options;\n const absoluteRoot = resolve(rootDir);\n\n const extensions = SOURCE_EXTENSIONS.map((ext) => ext.slice(1)).join(',');\n const pattern = `**/*.{${extensions}}`;\n\n const ignorePatterns = [\n ...DEFAULT_IGNORE_PATTERNS,\n ...ignore.map((p) => (p.includes('*') ? p : `**/${p}/**`)),\n ];\n\n const filePaths = await fg(pattern, {\n cwd: absoluteRoot,\n ignore: [...ignorePatterns],\n absolute: true,\n dot: false,\n onlyFiles: true,\n });\n\n const files = await Promise.all(\n filePaths.map(async (absolutePath): Promise<ProjectFile> => {\n const content = await readFile(absolutePath, 'utf-8');\n const lines = content.split('\\n').length;\n\n return {\n path: relative(absoluteRoot, absolutePath),\n absolutePath,\n content,\n lines,\n extension: extname(absolutePath),\n };\n }),\n );\n\n return files.sort((a, b) => a.path.localeCompare(b.path));\n } catch (error) {\n throw new Error(`Failed to collect files: ${error instanceof Error ? error.message : String(error)}`);\n }\n}\n","/**\n * Parser module — AST cache management.\n * Individual rules handle their own parsing via regex.\n * This module provides cache lifecycle hooks for the orchestrator.\n */\n\n/**\n * Clears the AST cache and project instance.\n * Call after scan completes to free memory.\n */\nexport function clearParserCache(): void {\n // Reserved for future AST-based rule implementations.\n // Currently rules use regex-based analysis, so no cache to clear.\n}\n","import type { AnalysisRule, Issue, RuleContext, RuleId, Severity } from '@vibertest/shared';\n\n/**\n * Abstract base class for all analysis rules.\n * Every rule MUST extend this class and implement the `analyze` method.\n *\n * The `run` method handles the enabled/disabled check automatically.\n * Subclasses only need to focus on their analysis logic.\n */\nexport abstract class BaseRule implements AnalysisRule {\n abstract readonly id: RuleId;\n abstract readonly name: string;\n abstract readonly description: string;\n abstract readonly defaultSeverity: Severity;\n\n /**\n * Implement this in each rule subclass.\n * Receives the full context and returns found issues.\n */\n protected abstract analyze(context: RuleContext): Promise<readonly Issue[]>;\n\n /**\n * Runs the rule if enabled in config.\n * This is the public API called by the rule engine.\n */\n async run(context: RuleContext): Promise<readonly Issue[]> {\n const ruleConfig = context.config.rules[this.id];\n\n if (!ruleConfig?.enabled) {\n return [];\n }\n\n return this.analyze(context);\n }\n\n /**\n * Helper to create an Issue with this rule's metadata pre-filled.\n */\n protected createIssue(\n params: Omit<Issue, 'ruleId' | 'ruleName' | 'severity'> & {\n severity?: Severity;\n },\n ): Issue {\n return {\n ruleId: this.id,\n ruleName: this.name,\n severity: params.severity ?? this.defaultSeverity,\n message: params.message,\n filePath: params.filePath,\n line: params.line,\n column: params.column,\n codeSnippet: params.codeSnippet,\n suggestion: params.suggestion,\n learnMoreUrl: params.learnMoreUrl,\n };\n }\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\n\n/**\n * RULE-001: Oversized Files\n *\n * Detects files that exceed a reasonable line count,\n * indicating lack of component decomposition.\n *\n * WHY: AI tools generate everything in one file because they lack\n * architectural context. This creates unmaintainable monoliths.\n *\n * CALIBRATION (v0.3):\n * - Default maxFileLines: 500 (was 300)\n * - Warning at 80% of max (400 lines for default 500)\n * - Warning severity: LOW — a 410-line file is not a problem\n * - Over-max severity: MEDIUM (was HIGH) — code smell, not a bug or security risk\n */\nexport class OversizedFilesRule extends BaseRule {\n readonly id = RULE_ID.OVERSIZED_FILES;\n readonly name = 'Oversized Files';\n readonly description = 'Detects files exceeding recommended line count';\n readonly defaultSeverity = SEVERITY.MEDIUM;\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n const maxLines = context.config.thresholds.maxFileLines;\n const warningThreshold = Math.round(maxLines * 0.80);\n const issues: Issue[] = [];\n\n for (const file of context.files) {\n if (file.lines > maxLines) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: `File has ${file.lines} lines (max: ${maxLines})`,\n filePath: file.path,\n suggestion: this.getSuggestion(file.extension, file.lines),\n learnMoreUrl: 'https://refactoring.guru/smells/large-class',\n }),\n );\n } else if (file.lines > warningThreshold) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.LOW,\n message: `File has ${file.lines} lines (warning threshold: ${warningThreshold})`,\n filePath: file.path,\n suggestion: `This file is getting large. Consider splitting before it becomes unmanageable.`,\n learnMoreUrl: 'https://refactoring.guru/smells/large-class',\n }),\n );\n }\n }\n\n return issues;\n }\n\n private getSuggestion(extension: string, lines: number): string {\n const isReact = extension === '.tsx' || extension === '.jsx';\n\n if (isReact) {\n return [\n `This component has ${lines} lines. Split it up:`,\n ' - Extract custom hooks into separate files (useXxx.ts)',\n ' - Extract sub-components into their own files',\n ' - Move utility functions to a utils/ folder',\n ' - Move types/interfaces to a types.ts file',\n ].join('\\n');\n }\n\n return [\n `This file has ${lines} lines. Split it up:`,\n ' - Extract related functions into focused modules',\n ' - Group by responsibility (one module = one concern)',\n ' - Move types/interfaces to dedicated type files',\n ' - Consider the Single Responsibility Principle',\n ].join('\\n');\n }\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext, ProjectFile } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\n\n/**\n * RULE-002: Dead Code & Unused Exports\n *\n * Detects exported functions, variables, types, and components\n * that are never imported anywhere else in the project.\n *\n * WHY: Vibecoders iterate through multiple AI prompts, leaving behind\n * artifacts from previous generations that bloat the codebase.\n *\n * CALIBRATION: Severity is MEDIUM (not HIGH) because static analysis\n * cannot fully resolve dynamic imports, lazy loading, framework conventions,\n * or external consumers. False positives are expected — this rule flags\n * candidates for review, not confirmed dead code.\n */\nexport class DeadCodeRule extends BaseRule {\n readonly id = RULE_ID.DEAD_CODE;\n readonly name = 'Dead Code & Unused Exports';\n readonly description = 'Detects exports that are never imported elsewhere';\n readonly defaultSeverity = SEVERITY.MEDIUM;\n\n /** Files that are typically entry points and should be excluded */\n private static readonly ENTRY_POINT_PATTERNS = [\n /^index\\.[jt]sx?$/,\n /^main\\.[jt]sx?$/,\n /^app\\.[jt]sx?$/,\n /^layout\\.[jt]sx?$/,\n /^page\\.[jt]sx?$/,\n /^route\\.[jt]sx?$/,\n /^middleware\\.[jt]sx?$/,\n /\\.config\\.[jt]sx?$/,\n /\\.d\\.ts$/,\n // Next.js special files\n /^loading\\.[jt]sx?$/,\n /^error\\.[jt]sx?$/,\n /^not-found\\.[jt]sx?$/,\n /^template\\.[jt]sx?$/,\n /^default\\.[jt]sx?$/,\n /^global-error\\.[jt]sx?$/,\n /^opengraph-image\\.[jt]sx?$/,\n /^sitemap\\.[jt]sx?$/,\n /^robots\\.[jt]sx?$/,\n /^manifest\\.[jt]sx?$/,\n // Storybook\n /\\.stories\\.[jt]sx?$/,\n ];\n\n /** Regex to find all export statements (must be at start of line or after whitespace) */\n private static readonly EXPORT_PATTERNS = [\n // export function foo() / export async function foo()\n /^export\\s+(?:async\\s+)?function\\s+(\\w+)/gm,\n // export const/let/var foo\n /^export\\s+(?:const|let|var)\\s+(\\w+)/gm,\n // export class Foo\n /^export\\s+class\\s+(\\w+)/gm,\n // export interface Foo / export type Foo\n /^export\\s+(?:interface|type)\\s+(\\w+)/gm,\n // export enum Foo\n /^export\\s+enum\\s+(\\w+)/gm,\n ];\n\n /** Regex to find all import references */\n private static readonly IMPORT_PATTERN =\n /import\\s+(?:type\\s+)?(?:\\{([^}]+)\\}|(\\w+))\\s+from\\s+['\"][^'\"]+['\"]/g;\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n const { files } = context;\n\n // Step 1: Collect all exports from all files\n const allExports = this.collectExports(files);\n\n // Step 2: Collect all imports from all files\n const allImports = this.collectImports(files);\n\n // Step 3: Build a map of internal usages (exports used within the same file)\n const internalUsages = this.collectInternalUsages(files, allExports);\n\n // Step 4: Find exports that are never imported AND never used internally\n const issues: Issue[] = [];\n\n for (const [filePath, exports] of allExports) {\n for (const exportName of exports) {\n const isImported = allImports.has(exportName);\n const isUsedInternally = internalUsages.get(filePath)?.has(exportName) ?? false;\n\n if (!isImported && !isUsedInternally) {\n issues.push(\n this.createIssue({\n message: `\"${exportName}\" is exported but never imported anywhere`,\n filePath,\n suggestion: `Remove this export if it's no longer needed, or verify it's used externally (e.g., by a consumer package).`,\n learnMoreUrl: 'https://refactoring.guru/smells/dead-code',\n }),\n );\n }\n }\n }\n\n return issues;\n }\n\n /**\n * Collects all named exports from non-entry-point files.\n * Returns Map<filePath, Set<exportName>>\n */\n private collectExports(files: readonly ProjectFile[]): Map<string, Set<string>> {\n const exports = new Map<string, Set<string>>();\n\n for (const file of files) {\n // Skip entry points\n const fileName = file.path.split('/').pop() ?? '';\n if (this.isEntryPoint(fileName)) {\n continue;\n }\n\n // Skip test files\n if (this.isTestFile(file.path)) {\n continue;\n }\n\n const fileExports = new Set<string>();\n\n for (const pattern of DeadCodeRule.EXPORT_PATTERNS) {\n // Reset regex lastIndex for each file\n const regex = new RegExp(pattern.source, pattern.flags);\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(file.content)) !== null) {\n const name = match[1];\n if (name) {\n fileExports.add(name);\n }\n }\n }\n\n // Also check for: export { foo, bar } — only at start of line (not in comments)\n const reExportRegex = /^export\\s+\\{([^}]+)\\}/gm;\n let reMatch: RegExpExecArray | null;\n while ((reMatch = reExportRegex.exec(file.content)) !== null) {\n const names = reMatch[1];\n if (names) {\n for (const name of names.split(',')) {\n const cleaned = name.trim().split(/\\s+as\\s+/).pop()?.trim();\n if (cleaned) {\n fileExports.add(cleaned);\n }\n }\n }\n }\n\n if (fileExports.size > 0) {\n exports.set(file.path, fileExports);\n }\n }\n\n return exports;\n }\n\n /**\n * Collects all imported identifiers across the project.\n * Also resolves dynamic imports and barrel file re-exports\n * to reduce false positives from lazy loading and Next.js patterns.\n *\n * Returns Set<importedName>\n */\n private collectImports(files: readonly ProjectFile[]): Set<string> {\n const imports = new Set<string>();\n\n // Phase 1: Collect all static named imports\n for (const file of files) {\n const regex = new RegExp(DeadCodeRule.IMPORT_PATTERN.source, DeadCodeRule.IMPORT_PATTERN.flags);\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(file.content)) !== null) {\n // Named imports: { foo, bar as baz }\n const namedImports = match[1];\n if (namedImports) {\n for (const name of namedImports.split(',')) {\n // Handle \"foo as bar\" → we care about \"foo\" (the original export name)\n const original = name.trim().split(/\\s+as\\s+/)[0]?.trim();\n if (original) {\n imports.add(original);\n }\n }\n }\n\n // Default import: import Foo from '...'\n const defaultImport = match[2];\n if (defaultImport) {\n imports.add(defaultImport);\n }\n }\n }\n\n // Phase 2: Resolve dynamic imports — mark ALL exports from dynamically\n // imported modules as \"used\" since we can't know which specific exports\n // are consumed at runtime.\n //\n // Patterns detected:\n // - import('./path')\n // - require('./path')\n // - dynamic(() => import('./path')) (Next.js)\n // - lazy(() => import('./path')) (React)\n const dynamicModules = this.collectDynamicImportTargets(files);\n for (const file of files) {\n const isDynamic = [...dynamicModules].some((target) =>\n this.pathMatchesImport(file.path, target),\n );\n\n if (isDynamic) {\n // Mark all exports from this file as \"used\"\n for (const pattern of DeadCodeRule.EXPORT_PATTERNS) {\n const regex = new RegExp(pattern.source, pattern.flags);\n let match: RegExpExecArray | null;\n while ((match = regex.exec(file.content)) !== null) {\n const name = match[1];\n if (name) imports.add(name);\n }\n }\n }\n }\n\n // Phase 3: Resolve barrel file re-exports.\n // If an index.ts does `export { Foo } from './foo'` or `export * from './foo'`,\n // then Foo is considered \"used\" because the barrel is the public API.\n this.collectBarrelReExports(files, imports);\n\n return imports;\n }\n\n /**\n * Finds all modules referenced by dynamic import() or require() calls.\n * Returns a Set of approximate file paths that are dynamically loaded.\n */\n private collectDynamicImportTargets(files: readonly ProjectFile[]): Set<string> {\n const targets = new Set<string>();\n\n // Match: import('./path'), import(\"./path\"), require('./path')\n const dynamicRegex = /(?:import|require)\\s*\\(\\s*['\"](\\.[^'\"]+)['\"]\\s*\\)/g;\n\n for (const file of files) {\n const regex = new RegExp(dynamicRegex.source, dynamicRegex.flags);\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(file.content)) !== null) {\n const importPath = match[1];\n if (!importPath) continue;\n\n const resolved = this.resolveRelativePath(file.path, importPath);\n if (resolved) {\n targets.add(resolved);\n }\n }\n }\n\n return targets;\n }\n\n /**\n * Scans barrel files (index.ts) for re-exports and marks those\n * identifiers as \"used\" in the imports set.\n *\n * Patterns:\n * export { Foo, Bar } from './module'\n * export * from './module'\n * export { default as Foo } from './module'\n */\n private collectBarrelReExports(files: readonly ProjectFile[], imports: Set<string>): void {\n for (const file of files) {\n const fileName = file.path.split('/').pop() ?? '';\n if (!fileName.startsWith('index.')) continue;\n\n // Named re-exports: export { Foo, Bar } from './module'\n const namedReExport = /export\\s+\\{([^}]+)\\}\\s+from\\s+['\"][^'\"]+['\"]/g;\n let match: RegExpExecArray | null;\n\n while ((match = namedReExport.exec(file.content)) !== null) {\n const names = match[1];\n if (names) {\n for (const name of names.split(',')) {\n // Handle \"Foo as Bar\" → original is \"Foo\"\n const original = name.trim().split(/\\s+as\\s+/)[0]?.trim();\n // Handle \"default as Foo\" → skip, it's a default re-export\n if (original && original !== 'default') {\n imports.add(original);\n }\n }\n }\n }\n\n // Wildcard re-exports: export * from './module'\n // All exports from the target module are considered \"used\"\n const wildcardReExport = /export\\s+\\*\\s+from\\s+['\"](\\.[^'\"]+)['\"]/g;\n let wildcardMatch: RegExpExecArray | null;\n\n while ((wildcardMatch = wildcardReExport.exec(file.content)) !== null) {\n const importPath = wildcardMatch[1];\n if (!importPath) continue;\n\n const resolved = this.resolveRelativePath(file.path, importPath);\n if (!resolved) continue;\n\n // Find the target file and mark all its exports as used\n for (const targetFile of files) {\n if (this.pathMatchesImport(targetFile.path, resolved)) {\n for (const pattern of DeadCodeRule.EXPORT_PATTERNS) {\n const regex = new RegExp(pattern.source, pattern.flags);\n let expMatch: RegExpExecArray | null;\n while ((expMatch = regex.exec(targetFile.content)) !== null) {\n const name = expMatch[1];\n if (name) imports.add(name);\n }\n }\n }\n }\n }\n }\n }\n\n /**\n * Resolves a relative import path against the importing file's directory.\n * Returns the approximate target path (without extension).\n */\n private resolveRelativePath(fromPath: string, importPath: string): string | null {\n const dir = fromPath.split('/').slice(0, -1).join('/');\n const parts = [...dir.split('/'), ...importPath.split('/')].filter(Boolean);\n\n const resolved: string[] = [];\n for (const part of parts) {\n if (part === '.') continue;\n else if (part === '..') resolved.pop();\n else resolved.push(part);\n }\n\n return resolved.join('/') || null;\n }\n\n /**\n * Checks if a file path matches a resolved import path.\n * Handles extension resolution (.ts, .tsx, .js, .jsx) and index files.\n */\n private pathMatchesImport(filePath: string, resolvedImport: string): boolean {\n // Direct match (with any extension)\n const withoutExt = filePath.replace(/\\.[jt]sx?$/, '');\n if (withoutExt === resolvedImport) return true;\n\n // Index file match: import './foo' → foo/index.ts\n const asIndex = filePath.replace(/\\/index\\.[jt]sx?$/, '');\n if (asIndex === resolvedImport) return true;\n\n return false;\n }\n\n /**\n * Checks if exported identifiers are used elsewhere in the same file.\n * This prevents false positives for helper functions called internally.\n */\n private collectInternalUsages(\n files: readonly ProjectFile[],\n allExports: Map<string, Set<string>>,\n ): Map<string, Set<string>> {\n const usages = new Map<string, Set<string>>();\n\n for (const file of files) {\n const fileExports = allExports.get(file.path);\n if (!fileExports) continue;\n\n const usedInternally = new Set<string>();\n\n for (const exportName of fileExports) {\n // Count occurrences of the identifier in the file\n // Must appear more than once (the export declaration itself is one)\n const regex = new RegExp(`\\\\b${exportName}\\\\b`, 'g');\n const matches = file.content.match(regex);\n\n if (matches && matches.length > 1) {\n usedInternally.add(exportName);\n }\n }\n\n if (usedInternally.size > 0) {\n usages.set(file.path, usedInternally);\n }\n }\n\n return usages;\n }\n\n private isEntryPoint(fileName: string): boolean {\n return DeadCodeRule.ENTRY_POINT_PATTERNS.some((pattern) => pattern.test(fileName));\n }\n\n private isTestFile(filePath: string): boolean {\n return /\\.(test|spec)\\.[jt]sx?$/.test(filePath) || filePath.includes('__tests__');\n }\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\n\n/**\n * RULE-003: Hardcoded Secrets\n *\n * Detects API keys, tokens, passwords, and other secrets\n * hardcoded in source files.\n *\n * WHY: Vibecoders often paste API keys directly into code because\n * AI tools don't enforce security practices. This is the #1 security risk.\n */\nexport class HardcodedSecretsRule extends BaseRule {\n readonly id = RULE_ID.HARDCODED_SECRETS;\n readonly name = 'Hardcoded Secrets';\n readonly description = 'Detects API keys, tokens, and passwords in source code';\n readonly defaultSeverity = SEVERITY.CRITICAL;\n\n /** Secret detection patterns with descriptive names */\n private static readonly SECRET_PATTERNS: readonly SecretPattern[] = [\n // AWS\n {\n name: 'AWS Access Key',\n pattern: /(?:^|['\"`\\s=])(?:AKIA[0-9A-Z]{16})/,\n suggestion: 'Use AWS IAM roles or environment variables instead of hardcoding access keys.',\n },\n {\n name: 'AWS Secret Key',\n pattern: /aws_secret_access_key\\s*[:=]\\s*['\"][A-Za-z0-9/+=]{40}['\"]/i,\n suggestion: 'Store AWS credentials in ~/.aws/credentials or use environment variables.',\n },\n // GitHub\n {\n name: 'GitHub Token',\n pattern: /(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{36,}/,\n suggestion: 'Use GITHUB_TOKEN environment variable or GitHub Actions secrets.',\n },\n {\n name: 'GitHub PAT',\n pattern: /github_pat_[A-Za-z0-9_]{22,}/,\n suggestion: 'Store GitHub PATs in environment variables, never in code.',\n },\n // OpenAI / AI Services\n {\n name: 'OpenAI API Key',\n pattern: /sk-[A-Za-z0-9]{20,}/,\n suggestion: 'Use OPENAI_API_KEY environment variable. Never commit API keys.',\n },\n // Stripe\n {\n name: 'Stripe Key',\n pattern: /(?:sk|pk)_(?:test|live)_[A-Za-z0-9]{24,}/,\n suggestion: 'Use STRIPE_SECRET_KEY / STRIPE_PUBLISHABLE_KEY environment variables.',\n },\n // Slack\n {\n name: 'Slack Token',\n pattern: /xox[bpors]-[A-Za-z0-9-]{10,}/,\n suggestion: 'Store Slack tokens in environment variables.',\n },\n // Generic API keys\n {\n name: 'Generic API Key Assignment',\n pattern: /(?:api[_-]?key|apikey|api[_-]?secret)\\s*[:=]\\s*['\"][A-Za-z0-9_\\-]{16,}['\"]/i,\n suggestion: 'Move API keys to .env file and access via process.env.YOUR_API_KEY',\n },\n // Passwords\n {\n name: 'Hardcoded Password',\n pattern: /(?:password|passwd|pwd)\\s*[:=]\\s*['\"][^'\"]{8,}['\"]/i,\n suggestion: 'Never hardcode passwords. Use environment variables or a secrets manager.',\n },\n // Connection strings with credentials\n {\n name: 'Database Connection String',\n pattern: /(?:mongodb|postgres|mysql|redis):\\/\\/[^:]+:[^@]+@/i,\n suggestion: 'Use DATABASE_URL environment variable for connection strings.',\n },\n // Private keys\n {\n name: 'Private Key',\n pattern: /-----BEGIN\\s+(?:RSA|EC|DSA|OPENSSH)?\\s*PRIVATE\\s+KEY-----/,\n suggestion: 'Never commit private keys. Use a secrets manager or environment variables.',\n },\n // JWT secrets\n {\n name: 'JWT Secret',\n pattern: /(?:jwt[_-]?secret|jwt[_-]?key)\\s*[:=]\\s*['\"][^'\"]{8,}['\"]/i,\n suggestion: 'Store JWT secrets in environment variables (JWT_SECRET).',\n },\n // Generic secrets/tokens\n {\n name: 'Generic Secret Assignment',\n pattern: /(?:secret|token|credential)[_-]?(?:key)?\\s*[:=]\\s*['\"][A-Za-z0-9_\\-/+=]{16,}['\"]/i,\n suggestion: 'Move secrets to .env file. Use dotenv to load them at runtime.',\n },\n ];\n\n /** Files/patterns to exclude from secret scanning */\n private static readonly EXCLUDE_PATTERNS = [\n /\\.test\\.[jt]sx?$/,\n /\\.spec\\.[jt]sx?$/,\n /__tests__\\//,\n /\\.mock\\.[jt]sx?$/,\n /fixtures?\\//,\n /\\.example$/,\n /\\.sample$/,\n /\\.d\\.ts$/,\n /lock\\.json$/,\n ];\n\n /** Patterns that indicate example/placeholder values, not real secrets */\n private static readonly EXAMPLE_INDICATORS = [\n /\\.{3}['\"]/, // Ends with ... (truncated example)\n /['\"]sk-proj-abc/, // Common example prefix\n /['\"]sk-xxx/, // Placeholder\n /['\"]your[_-]?(?:api[_-]?)?key/i, // \"your-api-key\", \"your_key\"\n /['\"](?:example|sample|test|fake|dummy|placeholder)/i,\n /['\"]xxx+/i, // \"xxxx\"\n /['\"]0{8,}/, // \"00000000\"\n /['\"]1{8,}/, // \"11111111\"\n /['\"]abc123/, // Common example\n /['\"]changeme/i,\n /['\"]replace[_-]?me/i,\n /['\"]insert[_-]?(?:your|here)/i,\n /<[A-Z_]+>/, // <YOUR_API_KEY> placeholder style\n ];\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n const issues: Issue[] = [];\n\n for (const file of context.files) {\n // Skip test/mock/fixture files\n if (this.shouldSkipFile(file.path)) {\n continue;\n }\n\n const lines = file.content.split('\\n');\n\n for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {\n const line = lines[lineIndex]!;\n\n // Skip comments\n if (this.isComment(line)) {\n continue;\n }\n\n // Skip lines that reference env vars (they're doing it right)\n if (this.referencesEnvVar(line)) {\n continue;\n }\n\n // Skip example/placeholder values\n if (this.isExampleValue(line)) {\n continue;\n }\n\n // Skip JSX string props that contain code examples\n if (this.isJsxCodeExample(line)) {\n continue;\n }\n\n for (const secretPattern of HardcodedSecretsRule.SECRET_PATTERNS) {\n if (secretPattern.pattern.test(line)) {\n const truncatedLine = this.truncateSecret(line.trim());\n\n issues.push(\n this.createIssue({\n message: `${secretPattern.name} detected`,\n filePath: file.path,\n line: lineIndex + 1,\n codeSnippet: truncatedLine,\n suggestion: secretPattern.suggestion,\n learnMoreUrl: 'https://owasp.org/www-community/vulnerabilities/Use_of_hard-coded_password',\n }),\n );\n\n // Only report one secret per line to avoid duplicates\n break;\n }\n }\n }\n }\n\n return issues;\n }\n\n private shouldSkipFile(filePath: string): boolean {\n return HardcodedSecretsRule.EXCLUDE_PATTERNS.some((pattern) => pattern.test(filePath));\n }\n\n private isComment(line: string): boolean {\n const trimmed = line.trim();\n return trimmed.startsWith('//') || trimmed.startsWith('*') || trimmed.startsWith('/*');\n }\n\n private referencesEnvVar(line: string): boolean {\n return /process\\.env\\.|import\\.meta\\.env\\.|Deno\\.env\\.|Bun\\.env\\./.test(line);\n }\n\n /**\n * Checks if the line contains example/placeholder values, not real secrets\n */\n private isExampleValue(line: string): boolean {\n return HardcodedSecretsRule.EXAMPLE_INDICATORS.some((pattern) => pattern.test(line));\n }\n\n /**\n * Checks if the line is a JSX prop containing a code example\n * e.g., <CodeLine text='export const API_KEY = \"sk-...\"' />\n */\n private isJsxCodeExample(line: string): boolean {\n // JSX props like text=\"...\", code=\"...\", example=\"...\", snippet=\"...\"\n const jsxCodePropPattern = /(?:text|code|example|snippet|content|value)=\\{?['\"`]/i;\n if (jsxCodePropPattern.test(line)) {\n return true;\n }\n \n // Template literals or strings that look like code demonstrations\n if (/['\"`]export\\s+const\\s+\\w+\\s*=/.test(line)) {\n return true;\n }\n \n return false;\n }\n\n /**\n * Truncates detected secrets to show only first 4 chars + ***\n * Security: Never show full secrets in reports.\n */\n private truncateSecret(line: string): string {\n // Replace long strings that look like secrets\n return line.replace(\n /(['\"])[A-Za-z0-9_\\-/+=]{8,}\\1/g,\n (match) => {\n const quote = match[0];\n const inner = match.slice(1, -1);\n const preview = inner.slice(0, 4);\n return `${quote}${preview}****${quote}`;\n },\n );\n }\n}\n\ninterface SecretPattern {\n readonly name: string;\n readonly pattern: RegExp;\n readonly suggestion: string;\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\n\n/**\n * RULE-004: Unused Dependencies\n *\n * Detects packages in package.json that are never imported in source code.\n *\n * WHY: Each AI prompt might suggest \"npm install something-new\" without\n * checking if existing deps already solve the problem. This bloats\n * bundle size and attack surface.\n */\nexport class UnusedDepsRule extends BaseRule {\n readonly id = RULE_ID.UNUSED_DEPS;\n readonly name = 'Unused Dependencies';\n readonly description = 'Detects packages in package.json never imported in source code';\n readonly defaultSeverity = SEVERITY.HIGH;\n\n /**\n * Packages that are used via config files, CLI, or implicit references.\n * These should NOT be flagged as unused even if never imported.\n */\n private static readonly IMPLICIT_PACKAGES = new Set([\n // Build tools & compilers\n 'typescript', 'tsup', 'esbuild', 'webpack', 'vite', 'rollup', 'swc',\n 'turbo', '@swc/core', 'babel', '@babel/core',\n // Linters & formatters\n 'eslint', 'prettier', 'biome', '@biomejs/biome', 'stylelint',\n 'oxlint', '@oxlint/core',\n // Testing frameworks (used via CLI, not imported)\n 'vitest', 'jest', 'mocha', 'cypress', 'playwright',\n '@playwright/test', '@testing-library/jest-dom',\n // Type definitions\n '@types/node', '@types/react', '@types/react-dom',\n // React ecosystem (peer deps, used implicitly by frameworks)\n 'react-dom', 'react-is', 'scheduler',\n // Git hooks\n 'husky', 'lint-staged', 'simple-git-hooks', 'lefthook',\n // PostCSS & Tailwind (used via config)\n 'postcss', 'autoprefixer', 'tailwindcss', '@tailwindcss/vite',\n // Next.js internals\n 'sharp', '@next/font', '@next/mdx',\n // Env\n 'dotenv', 'cross-env',\n ]);\n\n /** Regex patterns to find import/require statements */\n private static readonly IMPORT_PATTERNS = [\n // import ... from 'package'\n /import\\s+(?:type\\s+)?(?:[\\s\\S]*?)\\s+from\\s+['\"]([^'\"./][^'\"]*)['\"]/g,\n // import 'package' (side-effect)\n /import\\s+['\"]([^'\"./][^'\"]*)['\"]/g,\n // require('package')\n /require\\s*\\(\\s*['\"]([^'\"./][^'\"]*)['\"]\\s*\\)/g,\n // dynamic import('package')\n /import\\s*\\(\\s*['\"]([^'\"./][^'\"]*)['\"]\\s*\\)/g,\n ];\n\n /** Config files that may reference packages */\n private static readonly CONFIG_FILE_PATTERNS = [\n /\\.config\\.[jt]sx?$/,\n /rc\\.[jt]sx?$/,\n /rc\\.json$/,\n /rc\\.ya?ml$/,\n ];\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n const { files, packageJson } = context;\n\n if (!packageJson) {\n return [];\n }\n\n const allDeps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n if (Object.keys(allDeps).length === 0) {\n return [];\n }\n\n // Collect all imported package names from source files\n const importedPackages = this.collectImportedPackages(files);\n\n // Also check config files for package references\n const configReferencedPackages = this.collectConfigReferences(files);\n\n // Find unused deps\n const issues: Issue[] = [];\n\n for (const depName of Object.keys(allDeps)) {\n // Skip implicit packages (build tools, linters, etc.)\n if (UnusedDepsRule.IMPLICIT_PACKAGES.has(depName)) {\n continue;\n }\n\n // Skip @types packages (they're type-only)\n // Skip @types/ packages — they're used by TypeScript compiler, not imported directly\n if (depName.startsWith('@types/')) {\n continue;\n }\n\n if (importedPackages.has(depName)) {\n continue;\n }\n\n // Scoped packages may be imported via their base (e.g., @foo/bar → @foo/bar)\n if (this.isScopedPackageImported(depName, importedPackages)) {\n continue;\n }\n\n // Packages referenced in config files (e.g., plugins, presets)\n if (configReferencedPackages.has(depName)) {\n continue;\n }\n\n const isDevDep = depName in (packageJson.devDependencies ?? {});\n\n issues.push(\n this.createIssue({\n severity: isDevDep ? SEVERITY.MEDIUM : SEVERITY.HIGH,\n message: `\"${depName}\" is listed in ${isDevDep ? 'devDependencies' : 'dependencies'} but never imported`,\n filePath: 'package.json',\n suggestion: `Remove with: npm uninstall ${depName}`,\n learnMoreUrl: 'https://docs.npmjs.com/cli/v10/commands/npm-prune',\n }),\n );\n }\n\n return issues;\n }\n\n /** Collects all package names imported across source files */\n private collectImportedPackages(files: readonly import('@vibertest/shared').ProjectFile[]): Set<string> {\n const packages = new Set<string>();\n\n for (const file of files) {\n for (const pattern of UnusedDepsRule.IMPORT_PATTERNS) {\n const regex = new RegExp(pattern.source, pattern.flags);\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(file.content)) !== null) {\n const packageName = match[1];\n if (packageName) {\n // Normalize: @scope/package/sub → @scope/package\n const normalized = this.normalizePackageName(packageName);\n packages.add(normalized);\n }\n }\n }\n }\n\n return packages;\n }\n\n /** Checks config files for package name references */\n private collectConfigReferences(files: readonly import('@vibertest/shared').ProjectFile[]): Set<string> {\n const referenced = new Set<string>();\n\n for (const file of files) {\n const isConfig = UnusedDepsRule.CONFIG_FILE_PATTERNS.some((p) => p.test(file.path));\n if (!isConfig) continue;\n\n // Simple string matching in config files\n // This catches things like: plugins: ['@tailwindcss/forms']\n const stringLiterals = file.content.match(/['\"](@?[a-z0-9][\\w./-]*)['\"]/g);\n if (stringLiterals) {\n for (const literal of stringLiterals) {\n const name = literal.slice(1, -1);\n const normalized = this.normalizePackageName(name);\n referenced.add(normalized);\n }\n }\n }\n\n return referenced;\n }\n\n /**\n * Normalizes a package name from an import path.\n * @example \"lodash/debounce\" → \"lodash\"\n * @example \"@scope/pkg/sub\" → \"@scope/pkg\"\n */\n private normalizePackageName(importPath: string): string {\n if (importPath.startsWith('@')) {\n // Scoped: @scope/package/sub → @scope/package\n const parts = importPath.split('/');\n return parts.slice(0, 2).join('/');\n }\n // Unscoped: package/sub → package\n return importPath.split('/')[0] ?? importPath;\n }\n\n /** Checks if a scoped package is imported via any of its sub-paths */\n private isScopedPackageImported(depName: string, imported: Set<string>): boolean {\n if (!depName.startsWith('@')) return false;\n return imported.has(depName);\n }\n}\n","/**\n * Shared helpers for regex-based source code analysis.\n * Used by rules that parse file content without AST.\n */\n\nimport type { RuleContext, ProjectFile } from '@vibertest/shared';\n\n// -----------------------------------------------------------------------------\n// Web Framework Detection\n// -----------------------------------------------------------------------------\n\nexport type WebFramework =\n | 'nextjs-app' // Next.js App Router\n | 'nextjs-pages' // Next.js Pages Router\n | 'remix'\n | 'sveltekit'\n | 'nuxt'\n | 'astro'\n | 'vite-react' // Vite + React (SPA)\n | 'vite-vue' // Vite + Vue (SPA)\n | 'cra' // Create React App\n | 'express' // Express (backend-only)\n | 'unknown';\n\n/**\n * Detects the web framework used in the project.\n * Used by ship-readiness rules (022, 023, 024).\n */\nexport function detectWebFramework(context: RuleContext): WebFramework {\n const { packageJson, files } = context;\n\n if (!packageJson) return 'unknown';\n\n const deps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n // Check for specific frameworks\n if ('next' in deps) {\n // Detect App Router vs Pages Router\n const hasAppDir = files.some(f => f.path.startsWith('app/') || f.path.includes('/app/'));\n const hasPagesDir = files.some(f => f.path.startsWith('pages/') || f.path.includes('/pages/'));\n \n if (hasAppDir) return 'nextjs-app';\n if (hasPagesDir) return 'nextjs-pages';\n return 'nextjs-app'; // Default to App Router for newer projects\n }\n\n if ('@remix-run/react' in deps || '@remix-run/node' in deps) {\n return 'remix';\n }\n\n if ('@sveltejs/kit' in deps) {\n return 'sveltekit';\n }\n\n if ('nuxt' in deps || 'nuxt3' in deps) {\n return 'nuxt';\n }\n\n if ('astro' in deps) {\n return 'astro';\n }\n\n // Vite-based SPAs\n if ('vite' in deps) {\n if ('react' in deps) return 'vite-react';\n if ('vue' in deps) return 'vite-vue';\n }\n\n // Create React App\n if ('react-scripts' in deps) {\n return 'cra';\n }\n\n // Express (backend-only)\n if ('express' in deps && !('react' in deps) && !('vue' in deps)) {\n return 'express';\n }\n\n return 'unknown';\n}\n\n/**\n * Checks if the project is a web application (not a library or CLI tool).\n */\nexport function isWebApplication(context: RuleContext): boolean {\n const framework = detectWebFramework(context);\n \n // Express alone is backend-only, not a web app for our purposes\n if (framework === 'express') return false;\n if (framework === 'unknown') {\n // Check if it looks like a library/package\n const pkg = context.packageJson;\n if (pkg) {\n // Libraries typically have main/exports/bin and are not private\n const isLibrary = ('main' in pkg || 'exports' in pkg || 'bin' in pkg) && \n !('private' in pkg && pkg.private === true);\n if (isLibrary) return false;\n }\n return false;\n }\n \n return true;\n}\n\n/**\n * Gets the layout/entry files for the detected framework.\n */\nexport function getLayoutFiles(context: RuleContext): ProjectFile[] {\n const framework = detectWebFramework(context);\n const { files } = context;\n\n const layoutPatterns: RegExp[] = [];\n\n switch (framework) {\n case 'nextjs-app':\n layoutPatterns.push(\n /^app\\/layout\\.[jt]sx?$/,\n /^src\\/app\\/layout\\.[jt]sx?$/,\n /app\\/\\([^)]+\\)\\/layout\\.[jt]sx?$/,\n );\n break;\n case 'nextjs-pages':\n layoutPatterns.push(\n /^pages\\/_app\\.[jt]sx?$/,\n /^pages\\/_document\\.[jt]sx?$/,\n /^src\\/pages\\/_app\\.[jt]sx?$/,\n );\n break;\n case 'remix':\n layoutPatterns.push(\n /^app\\/root\\.[jt]sx?$/,\n );\n break;\n case 'sveltekit':\n layoutPatterns.push(\n /^src\\/routes\\/\\+layout\\.svelte$/,\n /^src\\/app\\.html$/,\n );\n break;\n case 'nuxt':\n layoutPatterns.push(\n /^layouts\\/default\\.vue$/,\n /^app\\.vue$/,\n );\n break;\n case 'astro':\n layoutPatterns.push(\n /^src\\/layouts\\/.+\\.astro$/,\n );\n break;\n case 'vite-react':\n case 'cra':\n layoutPatterns.push(\n /^src\\/App\\.[jt]sx?$/,\n /^src\\/main\\.[jt]sx?$/,\n /^index\\.html$/,\n );\n break;\n case 'vite-vue':\n layoutPatterns.push(\n /^src\\/App\\.vue$/,\n /^src\\/main\\.[jt]s$/,\n /^index\\.html$/,\n );\n break;\n }\n\n return files.filter(f => layoutPatterns.some(p => p.test(f.path)));\n}\n\n// -----------------------------------------------------------------------------\n// File Path Helpers\n// -----------------------------------------------------------------------------\n\n/** Checks if a file path is a test file */\nexport function isTestFile(filePath: string): boolean {\n return /\\.(test|spec)\\.[jt]sx?$/.test(filePath) || filePath.includes('__tests__');\n}\n\n/** Checks if a file is a Storybook story */\nexport function isStoryFile(filePath: string): boolean {\n return /\\.stories\\.[jt]sx?$/.test(filePath);\n}\n\n/** Gets the 1-based line number for a character index in content */\nexport function getLineNumber(content: string, index: number): number {\n return content.slice(0, index).split('\\n').length;\n}\n\n// -----------------------------------------------------------------------------\n// Code Analysis Helpers\n// -----------------------------------------------------------------------------\n\n/** Checks if a code string contains a try block */\nexport function hasTryCatch(code: string): boolean {\n return /\\btry\\s*\\{/.test(code);\n}\n\n/** Checks if a code string contains an await expression */\nexport function hasAwait(code: string): boolean {\n return /\\bawait\\s+/.test(code);\n}\n\n/**\n * Checks if a position in source is inside a string literal,\n * regex literal, or comment. Prevents false positives from code\n * that references promise chains in non-executable contexts.\n */\nexport function isInsideStringOrComment(content: string, index: number): boolean {\n const lineStart = content.lastIndexOf('\\n', index) + 1;\n const lineContent = content.slice(lineStart, index);\n\n // Inside a single-line comment\n if (/\\/\\//.test(lineContent)) return true;\n\n // Inside a multi-line comment (/* ... */ or /** ... */)\n const lastBlockOpen = content.lastIndexOf('/*', index);\n if (lastBlockOpen !== -1) {\n const lastBlockClose = content.lastIndexOf('*/', index);\n if (lastBlockClose < lastBlockOpen) return true;\n }\n\n // Inside a string literal (unmatched quotes before the index on same line)\n const singleQuotes = (lineContent.match(/'/g) ?? []).length;\n const doubleQuotes = (lineContent.match(/\"/g) ?? []).length;\n const backticks = (lineContent.match(/`/g) ?? []).length;\n\n if (singleQuotes % 2 === 1 || doubleQuotes % 2 === 1 || backticks % 2 === 1) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Extracts the body of a function starting at the given index.\n * Uses brace counting to find the matching closing brace.\n */\nexport function extractFunctionBody(content: string, startIndex: number): string | null {\n let braceCount = 0;\n let foundOpen = false;\n let bodyStart = startIndex;\n\n for (let i = startIndex; i < content.length; i++) {\n const char = content[i];\n if (char === '{') {\n if (!foundOpen) bodyStart = i;\n braceCount++;\n foundOpen = true;\n } else if (char === '}') {\n braceCount--;\n if (foundOpen && braceCount === 0) {\n return content.slice(bodyStart, i + 1);\n }\n }\n }\n\n return null;\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext, ProjectFile } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\nimport { getLineNumber } from './analysis-helpers.js';\n\n/**\n * RULE-005: Missing Tests & Test Quality\n *\n * Detects projects with no tests, low test coverage, and low-quality tests.\n *\n * WHY: Vibecoders almost NEVER write tests because \"the AI already\n * tested it in the chat.\" When they do write tests, they're often\n * trivial, empty, or just snapshots without real assertions.\n */\nexport class MissingTestsRule extends BaseRule {\n readonly id = RULE_ID.MISSING_TESTS;\n readonly name = 'Missing Tests';\n readonly description = 'Detects projects with no tests, low coverage, or low-quality tests';\n readonly defaultSeverity = SEVERITY.CRITICAL;\n\n /** Patterns that identify test files */\n private static readonly TEST_FILE_PATTERNS = [\n /\\.test\\.[jt]sx?$/,\n /\\.spec\\.[jt]sx?$/,\n /__tests__\\/.+\\.[jt]sx?$/,\n /\\.stories\\.[jt]sx?$/, // Storybook counts as visual testing\n ];\n\n /** Patterns for source files (non-test, non-config) */\n private static readonly SOURCE_EXCLUSIONS = [\n /\\.test\\.[jt]sx?$/,\n /\\.spec\\.[jt]sx?$/,\n /__tests__\\//,\n /\\.stories\\.[jt]sx?$/,\n /\\.config\\.[jt]sx?$/,\n /\\.d\\.ts$/,\n /\\/types?\\//,\n /\\/constants?\\//,\n ];\n\n /** Known testing frameworks to detect */\n private static readonly TESTING_FRAMEWORKS = [\n 'vitest', 'jest', 'mocha', 'ava', 'tap',\n 'cypress', 'playwright', '@playwright/test',\n '@testing-library/react', '@testing-library/vue',\n '@testing-library/svelte',\n ] as const;\n\n /** Generic test names that indicate low effort */\n private static readonly GENERIC_TEST_NAMES = [\n /^test\\s*\\d*$/i,\n /^it\\s+works$/i,\n /^should\\s+work$/i,\n /^test\\s+case$/i,\n /^basic\\s+test$/i,\n /^simple\\s+test$/i,\n /^todo$/i,\n /^fixme$/i,\n /^placeholder$/i,\n /^example$/i,\n /^sample$/i,\n ];\n\n /** Trivial assertion patterns */\n private static readonly TRIVIAL_ASSERTIONS = [\n /expect\\s*\\(\\s*true\\s*\\)\\s*\\.\\s*toBe\\s*\\(\\s*true\\s*\\)/,\n /expect\\s*\\(\\s*false\\s*\\)\\s*\\.\\s*toBe\\s*\\(\\s*false\\s*\\)/,\n /expect\\s*\\(\\s*1\\s*\\)\\s*\\.\\s*toBe\\s*\\(\\s*1\\s*\\)/,\n /expect\\s*\\(\\s*['\"`].*['\"`]\\s*\\)\\s*\\.\\s*toBe\\s*\\(\\s*['\"`].*['\"`]\\s*\\)/,\n /expect\\s*\\(\\s*\\d+\\s*\\+\\s*\\d+\\s*\\)\\s*\\.\\s*toBe\\s*\\(\\s*\\d+\\s*\\)/,\n /assert\\s*\\.\\s*ok\\s*\\(\\s*true\\s*\\)/,\n /assert\\s*\\.\\s*equal\\s*\\(\\s*1\\s*,\\s*1\\s*\\)/,\n ];\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n const { files, packageJson, config } = context;\n const minTestRatio = config.thresholds.minTestRatio;\n const issues: Issue[] = [];\n\n // Count test files and source files\n const testFiles = files.filter((f) => this.isTestFile(f.path));\n const sourceFiles = files.filter((f) => this.isSourceFile(f.path));\n\n // Detect testing framework\n const detectedFramework = this.detectTestingFramework(packageJson);\n\n // Case 1: ZERO test files\n // Note: This is HIGH, not CRITICAL. Missing tests is bad practice but not a security emergency.\n // CRITICAL should be reserved for security risks (exposed secrets, SQL injection, etc.)\n if (testFiles.length === 0) {\n const frameworkSuggestion = detectedFramework\n ? `You have \"${detectedFramework}\" installed but no test files. Create your first test!`\n : this.getTestingSetupGuide(packageJson);\n\n issues.push(\n this.createIssue({\n severity: SEVERITY.HIGH,\n message: `No test files found in the project (0 out of ${sourceFiles.length} source files)`,\n filePath: 'project',\n suggestion: frameworkSuggestion,\n learnMoreUrl: 'https://vitest.dev/guide/',\n }),\n );\n\n return issues;\n }\n\n // Case 2: Low test ratio\n if (sourceFiles.length > 0) {\n const ratio = testFiles.length / sourceFiles.length;\n\n if (ratio < minTestRatio) {\n const percentage = Math.round(ratio * 100);\n const targetPercentage = Math.round(minTestRatio * 100);\n\n issues.push(\n this.createIssue({\n severity: SEVERITY.HIGH,\n message: `Low test coverage: ${testFiles.length} test files for ${sourceFiles.length} source files (${percentage}%, minimum: ${targetPercentage}%)`,\n filePath: 'project',\n suggestion: [\n `You need at least ${Math.ceil(sourceFiles.length * minTestRatio)} test files.`,\n 'Priority files to test:',\n ' - Business logic and utility functions',\n ' - API route handlers',\n ' - Complex components with user interactions',\n ' - Data transformation functions',\n ].join('\\n'),\n learnMoreUrl: 'https://vitest.dev/guide/',\n }),\n );\n }\n }\n\n // Case 3: No testing framework installed\n if (!detectedFramework && testFiles.length > 0) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: 'Test files found but no testing framework detected in dependencies',\n filePath: 'package.json',\n suggestion: 'Install a testing framework: npm install -D vitest',\n }),\n );\n }\n\n // Case 4: Test quality analysis (only if we have test files)\n if (testFiles.length > 0) {\n for (const testFile of testFiles) {\n // Skip storybook files for quality analysis\n if (/\\.stories\\.[jt]sx?$/.test(testFile.path)) continue;\n\n issues.push(...this.checkTestQuality(testFile));\n }\n }\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // Test Quality Checks\n // ---------------------------------------------------------------------------\n\n private checkTestQuality(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n\n issues.push(...this.checkEmptyTests(file));\n issues.push(...this.checkTrivialAssertions(file));\n issues.push(...this.checkGenericTestNames(file));\n issues.push(...this.checkSkippedTests(file));\n issues.push(...this.checkTestsWithoutAssertions(file));\n\n return issues;\n }\n\n /**\n * Detects empty test blocks\n */\n private checkEmptyTests(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n\n // Match test/it blocks with empty bodies\n const emptyTestPattern = /(?:test|it)\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]\\s*,\\s*(?:async\\s*)?\\(\\s*\\)\\s*=>\\s*\\{\\s*\\}\\s*\\)/g;\n let match: RegExpExecArray | null;\n\n while ((match = emptyTestPattern.exec(file.content)) !== null) {\n const testName = match[1] ?? 'unnamed';\n const line = getLineNumber(file.content, match.index);\n\n issues.push(\n this.createIssue({\n severity: SEVERITY.HIGH,\n message: `Empty test: \"${testName}\" has no implementation`,\n filePath: file.path,\n line,\n suggestion: 'Add assertions to this test or remove it. Empty tests give false confidence.',\n learnMoreUrl: 'https://vitest.dev/guide/',\n }),\n );\n }\n\n return issues;\n }\n\n /**\n * Detects trivial assertions like expect(true).toBe(true)\n */\n private checkTrivialAssertions(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n\n for (const pattern of MissingTestsRule.TRIVIAL_ASSERTIONS) {\n const regex = new RegExp(pattern.source, 'g');\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(file.content)) !== null) {\n const line = getLineNumber(file.content, match.index);\n\n issues.push(\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: 'Trivial assertion that tests nothing meaningful',\n filePath: file.path,\n line,\n codeSnippet: match[0].slice(0, 50),\n suggestion: 'Replace with assertions that test actual behavior. This assertion will always pass.',\n learnMoreUrl: 'https://vitest.dev/guide/',\n }),\n );\n }\n }\n\n return issues;\n }\n\n /**\n * Detects generic/placeholder test names\n */\n private checkGenericTestNames(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n\n // Match test/it/describe names\n const testNamePattern = /(?:test|it|describe)\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g;\n let match: RegExpExecArray | null;\n\n while ((match = testNamePattern.exec(file.content)) !== null) {\n const testName = match[1] ?? '';\n const line = getLineNumber(file.content, match.index);\n\n for (const genericPattern of MissingTestsRule.GENERIC_TEST_NAMES) {\n if (genericPattern.test(testName.trim())) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.LOW,\n message: `Generic test name: \"${testName}\" doesn't describe what's being tested`,\n filePath: file.path,\n line,\n suggestion: 'Use descriptive test names that explain the expected behavior, e.g., \"should return user data when authenticated\"',\n learnMoreUrl: 'https://vitest.dev/guide/',\n }),\n );\n break;\n }\n }\n }\n\n return issues;\n }\n\n /**\n * Detects skipped or todo tests that were never implemented\n */\n private checkSkippedTests(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n\n // Match skipped tests\n const skippedPatterns = [\n /(?:test|it|describe)\\.skip\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n /(?:test|it|describe)\\.todo\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n /x(?:test|it|describe)\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g, // xtest, xit, xdescribe\n ];\n\n for (const pattern of skippedPatterns) {\n const regex = new RegExp(pattern.source, 'g');\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(file.content)) !== null) {\n const testName = match[1] ?? 'unnamed';\n const line = getLineNumber(file.content, match.index);\n const isSkip = pattern.source.includes('skip');\n const isTodo = pattern.source.includes('todo');\n\n issues.push(\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: `${isTodo ? 'TODO' : 'Skipped'} test: \"${testName}\" was never ${isTodo ? 'implemented' : 'fixed'}`,\n filePath: file.path,\n line,\n suggestion: isTodo\n ? 'Implement this test or remove the TODO. Unimplemented tests are technical debt.'\n : 'Fix and unskip this test, or remove it if no longer needed.',\n learnMoreUrl: 'https://vitest.dev/guide/',\n }),\n );\n }\n }\n\n return issues;\n }\n\n /**\n * Detects test blocks without any assertions\n */\n private checkTestsWithoutAssertions(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n\n // This is a heuristic - find test blocks and check if they have expect/assert\n const testBlockPattern = /(?:test|it)\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]\\s*,\\s*(?:async\\s*)?\\([^)]*\\)\\s*=>\\s*\\{([^}]+)\\}/g;\n let match: RegExpExecArray | null;\n\n while ((match = testBlockPattern.exec(file.content)) !== null) {\n const testName = match[1] ?? 'unnamed';\n const testBody = match[2] ?? '';\n const line = getLineNumber(file.content, match.index);\n\n // Check if body has any assertions\n const hasAssertion =\n /expect\\s*\\(/.test(testBody) ||\n /assert\\s*[.(]/.test(testBody) ||\n /\\.toHaveBeenCalled/.test(testBody) ||\n /\\.toMatchSnapshot/.test(testBody) ||\n /\\.toMatchInlineSnapshot/.test(testBody) ||\n /\\.rejects\\./.test(testBody) ||\n /\\.resolves\\./.test(testBody);\n\n // Skip if body is just comments or very short (likely a false positive)\n const strippedBody = testBody.replace(/\\/\\/.*$/gm, '').replace(/\\/\\*[\\s\\S]*?\\*\\//g, '').trim();\n if (strippedBody.length < 10) continue; // Too short, probably caught by empty test check\n\n if (!hasAssertion && strippedBody.length > 20) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: `Test \"${testName}\" has no assertions`,\n filePath: file.path,\n line,\n suggestion: 'Add expect() or assert() calls to verify behavior. Tests without assertions don\\'t test anything.',\n learnMoreUrl: 'https://vitest.dev/guide/',\n }),\n );\n }\n }\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n private isTestFile(filePath: string): boolean {\n return MissingTestsRule.TEST_FILE_PATTERNS.some((p) => p.test(filePath));\n }\n\n private isSourceFile(filePath: string): boolean {\n return !MissingTestsRule.SOURCE_EXCLUSIONS.some((p) => p.test(filePath));\n }\n\n private detectTestingFramework(\n packageJson: import('@vibertest/shared').PackageJson | null,\n ): string | null {\n if (!packageJson) return null;\n\n const allDeps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n for (const framework of MissingTestsRule.TESTING_FRAMEWORKS) {\n if (framework in allDeps) {\n return framework;\n }\n }\n\n return null;\n }\n\n private getTestingSetupGuide(\n packageJson: import('@vibertest/shared').PackageJson | null,\n ): string {\n const allDeps = {\n ...packageJson?.dependencies,\n ...packageJson?.devDependencies,\n };\n\n // Detect framework to suggest appropriate testing tool\n const isNext = 'next' in allDeps;\n const isReact = 'react' in allDeps;\n const isVue = 'vue' in allDeps;\n\n if (isNext || isReact) {\n return [\n 'No tests found! Set up testing:',\n ' 1. npm install -D vitest @testing-library/react jsdom',\n ' 2. Create vitest.config.ts with environment: \"jsdom\"',\n ' 3. Create your first test: src/components/Button.test.tsx',\n '',\n 'Example test:',\n ' import { render, screen } from \"@testing-library/react\"',\n ' import { Button } from \"./Button\"',\n ' test(\"renders button\", () => {',\n ' render(<Button>Click me</Button>)',\n ' expect(screen.getByText(\"Click me\")).toBeDefined()',\n ' })',\n ].join('\\n');\n }\n\n if (isVue) {\n return [\n 'No tests found! Set up testing:',\n ' 1. npm install -D vitest @testing-library/vue',\n ' 2. Create vitest.config.ts',\n ' 3. Create your first test file',\n ].join('\\n');\n }\n\n return [\n 'No tests found! Set up testing:',\n ' 1. npm install -D vitest',\n ' 2. Create vitest.config.ts',\n ' 3. Add \"test\": \"vitest run\" to package.json scripts',\n ' 4. Create your first test: src/utils.test.ts',\n ].join('\\n');\n }\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext, ProjectFile } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\n\n/**\n * RULE-006: Pattern Inconsistency\n *\n * Detects mixed coding patterns within the same project that indicate\n * multiple AI generation sessions without coherence.\n *\n * WHY: Each AI prompt generates code in isolation. Without a style guide,\n * the project becomes a Frankenstein of different patterns.\n */\nexport class PatternInconsistencyRule extends BaseRule {\n readonly id = RULE_ID.PATTERN_INCONSISTENCY;\n readonly name = 'Pattern Inconsistency';\n readonly description = 'Detects mixed coding patterns indicating incoherent AI generation';\n readonly defaultSeverity = SEVERITY.MEDIUM;\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n const { files } = context;\n const issues: Issue[] = [];\n\n issues.push(...this.checkAsyncPatterns(files));\n issues.push(...this.checkStylingPatterns(files));\n issues.push(...this.checkExportPatterns(files));\n issues.push(...this.checkStateManagement(files, context));\n issues.push(...this.checkImportPaths(files));\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // Async Patterns: async/await vs .then()/.catch()\n // ---------------------------------------------------------------------------\n\n private checkAsyncPatterns(files: readonly ProjectFile[]): Issue[] {\n let awaitCount = 0;\n let thenCount = 0;\n\n for (const file of files) {\n const awaitMatches = file.content.match(/\\bawait\\s+/g);\n const thenMatches = file.content.match(/\\.then\\s*\\(/g);\n\n awaitCount += awaitMatches?.length ?? 0;\n thenCount += thenMatches?.length ?? 0;\n }\n\n const total = awaitCount + thenCount;\n if (total < 4) return []; // Not enough data\n\n const minorRatio = Math.min(awaitCount, thenCount) / total;\n\n // Flag if both patterns have significant usage (>20%)\n if (minorRatio > 0.2) {\n const dominant = awaitCount > thenCount ? 'async/await' : '.then()/.catch()';\n const minor = awaitCount > thenCount ? '.then()/.catch()' : 'async/await';\n\n return [\n this.createIssue({\n message: `Mixed async patterns: ${awaitCount} uses of async/await and ${thenCount} uses of .then()/.catch()`,\n filePath: 'project',\n suggestion: `Standardize on ${dominant} (your dominant pattern). Convert the ${thenCount > awaitCount ? awaitCount : thenCount} uses of ${minor} for consistency.`,\n learnMoreUrl: 'https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Promises',\n }),\n ];\n }\n\n return [];\n }\n\n // ---------------------------------------------------------------------------\n // Styling Patterns: CSS Modules vs inline vs Tailwind vs CSS-in-JS\n // ---------------------------------------------------------------------------\n\n private checkStylingPatterns(files: readonly ProjectFile[]): Issue[] {\n const patterns: Record<string, number> = {};\n\n for (const file of files) {\n // Tailwind: className=\"flex items-center ...\"\n if (/className=[\"'][^\"']*(?:flex|grid|p-|m-|text-|bg-|w-|h-)\\b/.test(file.content)) {\n patterns['Tailwind CSS'] = (patterns['Tailwind CSS'] ?? 0) + 1;\n }\n\n // CSS Modules: styles.container, styles['header']\n if (/\\bstyles\\.\\w+|\\bstyles\\[['\"]/.test(file.content)) {\n patterns['CSS Modules'] = (patterns['CSS Modules'] ?? 0) + 1;\n }\n\n // Inline styles: style={{ ... }}\n if (/style=\\{\\{/.test(file.content)) {\n patterns['Inline Styles'] = (patterns['Inline Styles'] ?? 0) + 1;\n }\n\n // styled-components / emotion: styled.div`...` or css`...`\n if (/styled\\.\\w+`|css`/.test(file.content)) {\n patterns['CSS-in-JS'] = (patterns['CSS-in-JS'] ?? 0) + 1;\n }\n }\n\n const usedPatterns = Object.entries(patterns).filter(([, count]) => count >= 2);\n\n if (usedPatterns.length > 1) {\n const patternList = usedPatterns\n .map(([name, count]) => `${name} (${count} files)`)\n .join(', ');\n\n return [\n this.createIssue({\n message: `Mixed styling approaches: ${patternList}`,\n filePath: 'project',\n suggestion: `Pick ONE styling approach and use it consistently. Having ${usedPatterns.length} different styling methods makes the codebase confusing.`,\n learnMoreUrl: 'https://2024.stateofcss.com/en-US/css-frameworks/',\n }),\n ];\n }\n\n return [];\n }\n\n // ---------------------------------------------------------------------------\n // Export Patterns: default vs named exports\n // ---------------------------------------------------------------------------\n\n private checkExportPatterns(files: readonly ProjectFile[]): Issue[] {\n let defaultExports = 0;\n let namedExports = 0;\n\n for (const file of files) {\n if (/^export\\s+default\\b/m.test(file.content)) {\n defaultExports++;\n }\n if (/^export\\s+(?:const|function|class|interface|type|enum)\\b/m.test(file.content)) {\n namedExports++;\n }\n }\n\n const total = defaultExports + namedExports;\n if (total < 6) return [];\n\n const minorRatio = Math.min(defaultExports, namedExports) / total;\n\n if (minorRatio > 0.25) {\n const dominant = namedExports > defaultExports ? 'named exports' : 'default exports';\n\n return [\n this.createIssue({\n message: `Mixed export patterns: ${defaultExports} files use default exports, ${namedExports} files use named exports`,\n filePath: 'project',\n suggestion: `Standardize on ${dominant}. Named exports are generally preferred for better tree-shaking and IDE autocomplete.`,\n learnMoreUrl: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export',\n }),\n ];\n }\n\n return [];\n }\n\n // ---------------------------------------------------------------------------\n // State Management: useState vs Redux vs Zustand vs Context\n // ---------------------------------------------------------------------------\n\n private checkStateManagement(files: readonly ProjectFile[], context: RuleContext): Issue[] {\n const patterns: Record<string, number> = {};\n const deps = {\n ...context.packageJson?.dependencies,\n ...context.packageJson?.devDependencies,\n };\n\n // Check for state management libraries in deps\n if ('redux' in deps || '@reduxjs/toolkit' in deps) patterns['Redux'] = 1;\n if ('zustand' in deps) patterns['Zustand'] = 1;\n if ('jotai' in deps) patterns['Jotai'] = 1;\n if ('recoil' in deps) patterns['Recoil'] = 1;\n if ('mobx' in deps) patterns['MobX'] = 1;\n\n // Check for Context API usage\n let contextCount = 0;\n for (const file of files) {\n if (/\\bcreateContext\\b|\\buseContext\\b/.test(file.content)) {\n contextCount++;\n }\n }\n if (contextCount >= 3) patterns['React Context'] = contextCount;\n\n const usedPatterns = Object.keys(patterns);\n\n if (usedPatterns.length > 1) {\n return [\n this.createIssue({\n message: `Multiple state management approaches: ${usedPatterns.join(', ')}`,\n filePath: 'project',\n suggestion: `Consolidate to one state management solution. Having ${usedPatterns.length} different approaches creates confusion about where state lives.`,\n learnMoreUrl: 'https://2024.stateofjs.com/en-US/libraries/state-management/',\n }),\n ];\n }\n\n return [];\n }\n\n // ---------------------------------------------------------------------------\n // Import Paths: relative (../../) vs aliases (@/)\n // ---------------------------------------------------------------------------\n\n private checkImportPaths(files: readonly ProjectFile[]): Issue[] {\n let relativeDeep = 0; // ../../ or deeper\n let aliasImports = 0;\n\n for (const file of files) {\n const deepRelative = file.content.match(/from\\s+['\"]\\.\\.\\/\\.\\.\\//g);\n const aliases = file.content.match(/from\\s+['\"]@\\//g);\n\n relativeDeep += deepRelative?.length ?? 0;\n aliasImports += aliases?.length ?? 0;\n }\n\n // Only flag if there are deep relative imports AND aliases mixed\n if (relativeDeep >= 3 && aliasImports >= 3) {\n return [\n this.createIssue({\n message: `Mixed import paths: ${relativeDeep} deep relative imports (../../) and ${aliasImports} alias imports (@/)`,\n filePath: 'project',\n suggestion: `Configure path aliases (e.g., @/ → src/) in tsconfig.json and convert deep relative imports. This makes imports cleaner and refactoring easier.`,\n learnMoreUrl: 'https://www.typescriptlang.org/tsconfig/#paths',\n }),\n ];\n }\n\n return [];\n }\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext, ProjectFile } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\n\n/** Max characters to include in a code snippet for issue reports */\nconst MAX_SNIPPET_LENGTH = 80;\n\n/**\n * RULE-007: Poor Maintainability\n *\n * Detects code patterns that make the project difficult for other\n * developers (or future-self) to understand and maintain.\n *\n * WHY: AI-generated code often \"works\" but is written for the machine,\n * not for humans. The next developer won't understand it.\n */\nexport class PoorMaintainabilityRule extends BaseRule {\n readonly id = RULE_ID.POOR_MAINTAINABILITY;\n readonly name = 'Poor Maintainability';\n readonly description = 'Detects code patterns that hurt readability and maintenance';\n readonly defaultSeverity = SEVERITY.MEDIUM;\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n const { files, config } = context;\n const issues: Issue[] = [];\n\n for (const file of files) {\n if (this.isTestFile(file.path)) continue;\n\n issues.push(...this.checkFunctionParams(file, config.thresholds.maxFunctionParams));\n issues.push(...this.checkFunctionLength(file, config.thresholds.maxFunctionLines));\n issues.push(...this.checkTooManyImports(file, config.thresholds.maxImports));\n issues.push(...this.checkMagicNumbers(file));\n issues.push(...this.checkPoorNaming(file));\n }\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // Too Many Parameters\n // ---------------------------------------------------------------------------\n\n private checkFunctionParams(file: ProjectFile, maxParams: number): Issue[] {\n const issues: Issue[] = [];\n\n // Match function declarations and arrow functions with params\n const patterns = [\n // function foo(a, b, c, d, e) or async function foo(...)\n /(?:async\\s+)?function\\s+(\\w+)\\s*\\(([^)]*)\\)/g,\n // const foo = (a, b, c, d, e) =>\n /(?:const|let|var)\\s+(\\w+)\\s*=\\s*(?:async\\s+)?\\(([^)]*)\\)\\s*(?::\\s*\\w+\\s*)?=>/g,\n // method(a, b, c, d, e) { in classes\n /^\\s+(?:async\\s+)?(\\w+)\\s*\\(([^)]*)\\)\\s*(?::\\s*\\w+\\s*)?{/gm,\n ];\n\n const lines = file.content.split('\\n');\n\n for (const pattern of patterns) {\n const regex = new RegExp(pattern.source, pattern.flags);\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(file.content)) !== null) {\n // Skip matches inside comments (the line at match.index starts with //)\n const matchLine = lines[this.getLineNumber(file.content, match.index) - 1] ?? '';\n if (matchLine.trimStart().startsWith('//')) continue;\n\n const funcName = match[1] ?? 'anonymous';\n const params = match[2] ?? '';\n\n // Count params (split by comma, filter empty)\n const paramList = params\n .split(',')\n .map((p) => p.trim())\n .filter((p) => p.length > 0 && !p.startsWith('//'));\n\n if (paramList.length > maxParams) {\n const line = this.getLineNumber(file.content, match.index);\n\n issues.push(\n this.createIssue({\n message: `[params] \"${funcName}\" has ${paramList.length} parameters (max: ${maxParams})`,\n filePath: file.path,\n line,\n suggestion: `Use an options/config object pattern instead:\\n function ${funcName}(options: ${capitalize(funcName)}Options) { ... }`,\n learnMoreUrl: 'https://refactoring.guru/smells/long-parameter-list',\n }),\n );\n }\n }\n }\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // Function Too Long\n // ---------------------------------------------------------------------------\n\n private checkFunctionLength(file: ProjectFile, maxLines: number): Issue[] {\n const issues: Issue[] = [];\n const lines = file.content.split('\\n');\n\n // Simple brace-counting approach for function bodies\n const funcStartPattern = /^(\\s*)(?:export\\s+)?(?:async\\s+)?(?:function\\s+(\\w+)|(?:const|let|var)\\s+(\\w+)\\s*=\\s*(?:async\\s+)?(?:\\([^)]*\\)|[^=])\\s*=>)/;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const funcMatch = funcStartPattern.exec(line);\n\n if (!funcMatch) continue;\n\n const funcName = funcMatch[2] ?? funcMatch[3] ?? 'anonymous';\n const bodyStart = i;\n\n // Find the end of the function by counting braces\n let braceCount = 0;\n let foundOpen = false;\n let bodyEnd = i;\n\n for (let j = i; j < lines.length; j++) {\n const currentLine = lines[j]!;\n for (const char of currentLine) {\n if (char === '{') {\n braceCount++;\n foundOpen = true;\n } else if (char === '}') {\n braceCount--;\n }\n }\n\n if (foundOpen && braceCount === 0) {\n bodyEnd = j;\n break;\n }\n }\n\n const bodyLength = bodyEnd - bodyStart;\n\n if (bodyLength > maxLines) {\n issues.push(\n this.createIssue({\n message: `[long-function] \"${funcName}\" is ${bodyLength} lines long (max: ${maxLines})`,\n filePath: file.path,\n line: bodyStart + 1,\n suggestion: `Extract sub-functions with clear, descriptive names. Each function should do ONE thing.`,\n learnMoreUrl: 'https://refactoring.guru/smells/long-method',\n }),\n );\n }\n }\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // Too Many Imports\n // ---------------------------------------------------------------------------\n\n private checkTooManyImports(file: ProjectFile, maxImports: number): Issue[] {\n const importLines = file.content.match(/^import\\s+/gm);\n const importCount = importLines?.length ?? 0;\n\n if (importCount > maxImports) {\n return [\n this.createIssue({\n message: `[imports] File has ${importCount} imports (max: ${maxImports})`,\n filePath: file.path,\n line: 1,\n suggestion: `This file may have too many responsibilities. Consider splitting it into smaller, focused modules.`,\n learnMoreUrl: 'https://refactoring.guru/smells/feature-envy',\n }),\n ];\n }\n\n return [];\n }\n\n // ---------------------------------------------------------------------------\n // Magic Numbers\n // ---------------------------------------------------------------------------\n\n private checkMagicNumbers(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n const lines = file.content.split('\\n');\n\n // Allowed magic numbers (common, conventional values)\n // Time: hours, minutes, days, months\n // Percentages: common thresholds\n // Layout: common grid/flex values\n const allowed = new Set([\n 0, 1, -1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, // Basic numbers, months, hours\n 15, 20, 24, 25, 30, 31, 45, 50, 60, 90, // Time units, percentages\n 100, 180, 200, 250, 255, 300, 360, 365, // Common values\n 500, 750, 1000, 1024, 2000, 2048, 3000, // Sizes, delays\n ]);\n\n // Skip files that are likely configuration or constants\n if (this.isConfigOrConstantsFile(file.path)) {\n return [];\n }\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const trimmed = line.trim();\n\n // Skip comments, imports, type definitions\n if (\n trimmed.startsWith('//') ||\n trimmed.startsWith('*') ||\n trimmed.startsWith('/*') ||\n trimmed.startsWith('import') ||\n trimmed.startsWith('type') ||\n trimmed.startsWith('interface')\n ) {\n continue;\n }\n\n // Skip const declarations (they ARE the named constant)\n if (/^\\s*(?:export\\s+)?const\\s+[A-Z_][A-Z0-9_]*\\s*=/.test(line)) {\n continue;\n }\n\n // Skip JSX text content (numbers in displayed text are fine)\n if (this.isJsxTextContent(line)) {\n continue;\n }\n\n // Skip string literals (section numbers like \"15.1\", \"Section 12\")\n if (this.isNumberInString(line)) {\n continue;\n }\n\n // Skip array indices and common patterns\n if (this.isCommonNumericPattern(line)) {\n continue;\n }\n\n // Find numeric literals in comparisons, assignments, and function calls\n // Only flag numbers >= 2 digits that appear in logic contexts\n const magicPattern = /(?:===?|!==?|>=?|<=?|&&|\\|\\||\\?|,|\\+|-|\\*|\\/|%)\\s*(\\d{2,})\\b/g;\n let match: RegExpExecArray | null;\n\n while ((match = magicPattern.exec(line)) !== null) {\n const literalValue = Number.parseInt(match[1]!, 10);\n \n // Skip allowed values and common time/size values\n if (allowed.has(literalValue) || Number.isNaN(literalValue)) {\n continue;\n }\n\n // Skip if it looks like a port number, HTTP status, or year\n if (this.isKnownNumericConstant(literalValue)) {\n continue;\n }\n\n issues.push(\n this.createIssue({\n severity: SEVERITY.LOW,\n message: `[magic-number] Magic number ${literalValue} found`,\n filePath: file.path,\n line: i + 1,\n codeSnippet: trimmed.slice(0, MAX_SNIPPET_LENGTH),\n suggestion: `Extract to a named constant: const MAX_SOMETHING = ${literalValue};`,\n learnMoreUrl: 'https://refactoring.guru/replace-magic-number-with-symbolic-constant',\n }),\n );\n }\n }\n\n // Limit to 3 magic number issues per file to avoid noise\n return issues.slice(0, 3);\n }\n\n /**\n * Check if file is a config or constants file where magic numbers are expected\n */\n private isConfigOrConstantsFile(filePath: string): boolean {\n return /\\/(config|constants?|settings|theme|styles|tailwind)\\//i.test(filePath) ||\n /\\.(config|constants)\\.[jt]sx?$/.test(filePath) ||\n /\\/constants?\\.[jt]sx?$/.test(filePath);\n }\n\n /**\n * Check if the number appears in JSX text content (not in logic)\n */\n private isJsxTextContent(line: string): boolean {\n // Lines that are primarily JSX text content\n return /^\\s*[<>{}]?\\s*[\"'`].*\\d+.*[\"'`]\\s*[<>{}]?\\s*$/.test(line) ||\n />\\s*\\d+\\s*</.test(line) || // Text between tags\n /\\{['\"`].*\\d+.*['\"`]\\}/.test(line); // String in JSX expression\n }\n\n /**\n * Check if number is inside a string literal\n */\n private isNumberInString(line: string): boolean {\n // Section numbers, version strings, etc.\n if (/['\"`].*\\d+(\\.\\d+)*.*['\"`]/.test(line)) return true;\n if (/Section\\s+\\d+/i.test(line)) return true;\n if (/v\\d+\\.\\d+/.test(line)) return true;\n // Color values in strings (hsl, rgb, hex)\n if (/['\"`]\\s*(hsl|hsla|rgb|rgba|#[0-9a-fA-F]+)/.test(line)) return true;\n // Template literals with color/style values\n if (/`[^`]*\\b(hsl|hsla|rgb|rgba)\\s*\\(/.test(line)) return true;\n // Legal document sections (13.1, 17.1, etc.)\n if (/\\d+\\.\\d+\\.?\\s*(Nivel|Bases|Canales|Derechos)/i.test(line)) return true;\n // JSX comments with section numbers\n if (/\\{\\/\\*\\s*\\d+\\./.test(line)) return true;\n // Numbered lists or sections in JSX\n if (/<(p|span|li|strong)>.*\\d+\\.\\d+/.test(line)) return true;\n // \"X Secciones\" pattern\n if (/\\d+\\s+Secci(ón|ones)/i.test(line)) return true;\n return false;\n }\n\n /**\n * Check for common numeric patterns that aren't magic numbers\n */\n private isCommonNumericPattern(line: string): boolean {\n // Array access with numeric index\n if (/\\[\\d+\\]/.test(line)) return true;\n // Slice/substring with numbers\n if (/\\.(slice|substring|substr)\\s*\\(\\s*\\d+/.test(line)) return true;\n // setTimeout/setInterval with delay\n if (/set(Timeout|Interval)\\s*\\([^,]+,\\s*\\d+/.test(line)) return true;\n // CSS/style values\n if (/:\\s*['\"`]?\\d+(px|em|rem|%|vh|vw|ms|s)['\"`]?/.test(line)) return true;\n // Tailwind classes (detect common patterns directly)\n // Color utilities: bg-*, text-*, border-*, etc.\n if (/\\b(bg|text|border|ring|shadow|outline)-(gray|slate|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose|white|black|primary|secondary|accent|muted|destructive|popover|card|input|background|foreground)-?\\d*/.test(line)) return true;\n // Size utilities: w-*, h-*, p-*, m-*, gap-*, etc.\n if (/\\b(w|h|p|m|px|py|mx|my|pt|pb|pl|pr|mt|mb|ml|mr|gap|space|size|min-w|max-w|min-h|max-h)-\\d+/.test(line)) return true;\n // Rounded utilities\n if (/\\brounded(-\\w+)?-?\\d*/.test(line)) return true;\n // Dark mode variants\n if (/\\bdark:/.test(line)) return true;\n // Gradient utilities\n if (/\\b(from|to|via)-(gray|slate|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose|white|black|primary|secondary)-\\d+/.test(line)) return true;\n // Hover/focus variants\n if (/\\bhover:/.test(line)) return true;\n // HSL/RGB/RGBA color values\n if (/\\b(hsl|hsla|rgb|rgba)\\s*\\(\\s*\\d+/.test(line)) return true;\n // Date manipulation functions (subDays, addDays, subMonths, etc.)\n if (/\\b(sub|add)(Days|Months|Years|Hours|Minutes|Weeks)\\s*\\([^,]+,\\s*\\d+/.test(line)) return true;\n // Format functions with date patterns\n if (/format\\s*\\([^,]+,\\s*['\"`]/.test(line)) return true;\n // Percentage thresholds (common in business logic)\n if (/[<>=]+\\s*\\d{2,3}\\s*$/.test(line.trim()) && /rate|percent|score|ratio|progress/i.test(line)) return true;\n // Grid/flex layout numbers\n if (/grid-cols-\\d+|col-span-\\d+|row-span-\\d+/.test(line)) return true;\n // Z-index values\n if (/z-(?:index)?\\s*[:=]\\s*\\d+/.test(line)) return true;\n // Opacity values\n if (/opacity\\s*[:=]\\s*[\\d.]+/.test(line)) return true;\n // setHours/setMinutes/setSeconds (end of day patterns)\n if (/\\.set(Hours|Minutes|Seconds|Milliseconds)\\s*\\(/.test(line)) return true;\n // Math.max/min with layout calculations\n if (/Math\\.(max|min)\\s*\\([^)]*\\d+/.test(line)) return true;\n // Width/height props in JSX\n if (/\\b(width|height)\\s*=\\s*\\{?\\s*\\d+/.test(line)) return true;\n // innerWidth/innerHeight comparisons (breakpoints)\n if (/inner(Width|Height)\\s*[<>=]+\\s*\\d+/.test(line)) return true;\n // Time strings in text (09:00, 13:00, etc.)\n if (/\\d{1,2}:\\d{2}/.test(line)) return true;\n // Millisecond constants (60000, 3600000, 86400000)\n if (/\\b(60000|3600000|86400000)\\b/.test(line)) return true;\n // String length comparisons\n if (/\\.length\\s*[<>=]+\\s*\\d+/.test(line)) return true;\n // Geographic coordinates (latitude/longitude)\n if (/coords\\s*:\\s*\\[/.test(line)) return true;\n // Animation/transition delays (common values)\n if (/,\\s*(600|800|1000|1200|1500)\\s*\\)/.test(line)) return true;\n // Regex patterns with digit quantifiers\n if (/\\\\d\\{\\d+/.test(line)) return true;\n // Mock/test data arrays\n if (/\\[\\s*\\d+\\s*,\\s*\\d+\\s*,/.test(line) && /random|mock|test|sample/i.test(line)) return true;\n // Hour comparisons (business hours)\n if (/hour\\s*[<>=]+\\s*\\d+/.test(line)) return true;\n // Price arrays or ranges\n if (/price|Price/.test(line) && /\\[\\s*\\d+/.test(line)) return true;\n // Percentage in JSX text\n if (/-?\\d+%/.test(line)) return true;\n // Phone number patterns\n if (/\\d{3}\\s*\\d{3}\\s*\\d{3,4}/.test(line)) return true;\n // Animation keyframes (arrays of positions)\n if (/x:\\s*\\[/.test(line) || /y:\\s*\\[/.test(line)) return true;\n // Test/mock data with random\n if (/Math\\.random\\(\\)/.test(line)) return true;\n // For loops with hour ranges\n if (/for\\s*\\(\\s*let\\s+\\w+\\s*=\\s*\\d+/.test(line)) return true;\n // Polling intervals (common values)\n if (/,\\s*(15000|30000|60000)\\s*\\)/.test(line)) return true;\n // Price/amount comparisons\n if (/(min|max)(Price|Amount)\\s*[<>=]/.test(line)) return true;\n // Days in text (14 días, 30 días)\n if (/\\d+\\s+días/i.test(line)) return true;\n return false;\n }\n\n /**\n * Check if number is a well-known constant (ports, HTTP codes, etc.)\n */\n private isKnownNumericConstant(value: number): boolean {\n // HTTP status codes\n if (value >= 100 && value <= 599) return true;\n // Common ports\n if ([80, 443, 3000, 3001, 4000, 5000, 5173, 8000, 8080, 8443, 9000].includes(value)) return true;\n // Years (reasonable range)\n if (value >= 1900 && value <= 2100) return true;\n // Common byte sizes\n if ([1024, 2048, 4096, 8192, 16384, 32768, 65536].includes(value)) return true;\n // Common time values in ms\n if ([100, 200, 250, 300, 500, 750, 1500, 2000, 3000, 5000, 10000].includes(value)) return true;\n // Large number formatting thresholds\n if ([1000000, 1000000000].includes(value)) return true;\n // Common layout/UI values\n if ([16, 18, 20, 28, 32, 36, 40, 48, 56, 64, 70, 72, 80, 96, 120, 128, 140, 160, 192, 256].includes(value)) return true;\n // Common breakpoints\n if ([320, 375, 414, 640, 768, 1024, 1280, 1440, 1536, 1920].includes(value)) return true;\n return false;\n }\n\n // ---------------------------------------------------------------------------\n // Poor Naming\n // ---------------------------------------------------------------------------\n\n private checkPoorNaming(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n\n // Find single-letter variable declarations (excluding loop vars and common abbreviations)\n const allowed = new Set(['i', 'j', 'k', 'x', 'y', 'z', 'e', 'n', 'T', 'K', 'V', 'P', 'R']);\n const pattern = /(?:const|let|var)\\s+([a-zA-Z])\\s*[=:]/g;\n\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(file.content)) !== null) {\n const name = match[1]!;\n if (!allowed.has(name)) {\n const line = this.getLineNumber(file.content, match.index);\n\n issues.push(\n this.createIssue({\n severity: SEVERITY.LOW,\n message: `[naming] Single-letter variable \"${name}\" is not descriptive`,\n filePath: file.path,\n line,\n suggestion: `Use a descriptive name that explains the variable's purpose.`,\n learnMoreUrl: 'https://refactoring.guru/smells/mysterious-name',\n }),\n );\n }\n }\n\n // Limit to 5 per file\n return issues.slice(0, 5);\n }\n\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n private isTestFile(filePath: string): boolean {\n return /\\.(test|spec)\\.[jt]sx?$/.test(filePath) || filePath.includes('__tests__');\n }\n\n private getLineNumber(content: string, index: number): number {\n return content.slice(0, index).split('\\n').length;\n }\n}\n\nfunction capitalize(str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext, ProjectFile } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\nimport {\n isTestFile,\n getLineNumber,\n hasTryCatch,\n hasAwait,\n isInsideStringOrComment,\n extractFunctionBody,\n} from './analysis-helpers.js';\n\n/**\n * RULE-008: Missing Error Handling\n *\n * Detects code paths that lack proper error handling.\n *\n * WHY: AI generates happy-path code. When things fail in production\n * (and they WILL), there's nothing to catch or report the error.\n */\nexport class MissingErrorHandlingRule extends BaseRule {\n readonly id = RULE_ID.MISSING_ERROR_HANDLING;\n readonly name = 'Missing Error Handling';\n readonly description = 'Detects async operations and API calls without error handling';\n readonly defaultSeverity = SEVERITY.MEDIUM;\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n const { files } = context;\n const issues: Issue[] = [];\n\n for (const file of files) {\n if (isTestFile(file.path)) continue;\n\n issues.push(...this.checkUnhandledAsync(file));\n issues.push(...this.checkUnhandledFetch(file));\n issues.push(...this.checkUnhandledPromiseChains(file));\n issues.push(...this.checkEmptyCatchBlocks(file));\n issues.push(...this.checkSwallowedErrors(file));\n issues.push(...this.checkMissingErrorBoundary(files, context));\n }\n\n return this.deduplicateProjectIssues(issues);\n }\n\n // ---------------------------------------------------------------------------\n // Unhandled Async Functions\n // ---------------------------------------------------------------------------\n\n private checkUnhandledAsync(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n\n const asyncFuncPattern = /^(\\s*)(?:export\\s+)?async\\s+function\\s+(\\w+)/gm;\n let match: RegExpExecArray | null;\n\n while ((match = asyncFuncPattern.exec(file.content)) !== null) {\n const funcName = match[2]!;\n const funcBody = extractFunctionBody(file.content, match.index);\n\n if (funcBody && !hasTryCatch(funcBody) && hasAwait(funcBody)) {\n issues.push(this.createAsyncIssue(file, funcName, match.index));\n }\n }\n\n const asyncArrowPattern = /(?:const|let|var)\\s+(\\w+)\\s*=\\s*async\\s*\\(/g;\n\n while ((match = asyncArrowPattern.exec(file.content)) !== null) {\n const funcName = match[1]!;\n const funcBody = extractFunctionBody(file.content, match.index);\n\n if (funcBody && !hasTryCatch(funcBody) && hasAwait(funcBody)) {\n issues.push(this.createAsyncIssue(file, funcName, match.index));\n }\n }\n\n return issues;\n }\n\n private createAsyncIssue(file: ProjectFile, funcName: string, index: number): Issue {\n return this.createIssue({\n message: `Async function \"${funcName}\" has no try/catch block`,\n filePath: file.path,\n line: getLineNumber(file.content, index),\n suggestion: 'Wrap the async body in try/catch to handle potential errors.',\n learnMoreUrl: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch',\n });\n }\n\n // ---------------------------------------------------------------------------\n // Unhandled Fetch/HTTP Calls\n // ---------------------------------------------------------------------------\n\n private checkUnhandledFetch(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n const fetchPattern = /\\b(fetch|axios\\.(?:get|post|put|patch|delete))\\s*\\(/g;\n let match: RegExpExecArray | null;\n\n while ((match = fetchPattern.exec(file.content)) !== null) {\n const callName = match[1]!;\n const callIndex = match.index;\n\n const surroundingCode = file.content.slice(Math.max(0, callIndex - 500), callIndex);\n const isInTryCatch = /\\btry\\s*\\{[^}]*$/.test(surroundingCode);\n const hasCatchChain = /\\.catch\\s*\\(/.test(file.content.slice(callIndex, callIndex + 200));\n\n if (!isInTryCatch && !hasCatchChain) {\n issues.push(\n this.createIssue({\n message: `${callName}() call without error handling`,\n filePath: file.path,\n line: getLineNumber(file.content, callIndex),\n suggestion: 'HTTP calls can fail. Wrap in try/catch or add .catch() handler.',\n learnMoreUrl: 'https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#checking_that_the_fetch_was_successful',\n }),\n );\n }\n }\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // Unhandled Promise Chains\n // ---------------------------------------------------------------------------\n\n private checkUnhandledPromiseChains(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n const thenPattern = /\\.then\\s*\\([^)]*\\)(?:\\s*\\.then\\s*\\([^)]*\\))*/g;\n let match: RegExpExecArray | null;\n\n while ((match = thenPattern.exec(file.content)) !== null) {\n if (isInsideStringOrComment(file.content, match.index)) continue;\n\n const chainEnd = match.index + match[0].length;\n const afterChain = file.content.slice(chainEnd, chainEnd + 50);\n\n if (!/^\\s*\\.catch\\s*\\(/.test(afterChain)) {\n issues.push(\n this.createIssue({\n message: 'Promise chain without .catch() handler',\n filePath: file.path,\n line: getLineNumber(file.content, match.index),\n suggestion: 'Add .catch() to handle rejected promises, or convert to async/await with try/catch.',\n learnMoreUrl: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#error_handling',\n }),\n );\n }\n }\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // Empty Catch Blocks\n // ---------------------------------------------------------------------------\n\n /**\n * Detects catch blocks that don't actually handle the error:\n * - Empty catch: catch(e) { }\n * - Console-only catch: catch(e) { console.log(e) }\n * - Generic catch without re-throw or reporting\n */\n private checkEmptyCatchBlocks(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n \n // Match catch blocks and capture their body\n const catchPattern = /\\bcatch\\s*\\(\\s*(\\w+)?\\s*\\)\\s*\\{/g;\n let match: RegExpExecArray | null;\n\n while ((match = catchPattern.exec(file.content)) !== null) {\n if (isInsideStringOrComment(file.content, match.index)) continue;\n\n const catchStart = match.index + match[0].length;\n const catchBody = this.extractCatchBody(file.content, catchStart);\n \n if (!catchBody) continue;\n\n const trimmedBody = catchBody.trim();\n \n // Remove comments to check if truly empty\n const bodyWithoutComments = trimmedBody\n .replace(/\\/\\/.*$/gm, '')\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '')\n .trim();\n \n // Empty catch block (including those with only comments)\n if (bodyWithoutComments === '') {\n issues.push(\n this.createIssue({\n severity: SEVERITY.HIGH,\n message: 'Empty catch block silently swallows errors',\n filePath: file.path,\n line: getLineNumber(file.content, match.index),\n codeSnippet: match[0] + ' }',\n suggestion: 'Handle the error properly: log it, report to monitoring, or re-throw.',\n learnMoreUrl: 'https://eslint.org/docs/latest/rules/no-empty',\n }),\n );\n continue;\n }\n\n // Console-only catch (just logging, no real handling)\n if (this.isConsoleOnlyCatch(trimmedBody)) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: 'Catch block only logs error without proper handling',\n filePath: file.path,\n line: getLineNumber(file.content, match.index),\n suggestion: 'Consider reporting to an error monitoring service, showing user feedback, or re-throwing.',\n learnMoreUrl: 'https://kentcdodds.com/blog/get-a-catch-block-error-message-with-typescript',\n }),\n );\n }\n }\n\n return issues;\n }\n\n /**\n * Extracts the body of a catch block (content between { and matching })\n */\n private extractCatchBody(content: string, startIndex: number): string | null {\n let depth = 1;\n let i = startIndex;\n \n while (i < content.length && depth > 0) {\n if (content[i] === '{') depth++;\n else if (content[i] === '}') depth--;\n i++;\n }\n \n if (depth !== 0) return null;\n return content.slice(startIndex, i - 1);\n }\n\n /**\n * Checks if catch body only contains console.log/error/warn statements\n */\n private isConsoleOnlyCatch(body: string): boolean {\n // Remove all console statements\n const withoutConsole = body\n .replace(/console\\.(log|error|warn|info|debug)\\s*\\([^)]*\\)\\s*;?/g, '')\n .trim();\n \n // If nothing left (or just whitespace/comments), it's console-only\n const withoutComments = withoutConsole\n .replace(/\\/\\/.*$/gm, '')\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '')\n .trim();\n \n return withoutComments === '';\n }\n\n // ---------------------------------------------------------------------------\n // Swallowed Errors in Promise Chains\n // ---------------------------------------------------------------------------\n\n /**\n * Detects .catch() handlers that swallow errors:\n * - .catch(() => {})\n * - .catch(() => null)\n * - .catch(() => undefined)\n * - .catch(e => console.log(e))\n */\n private checkSwallowedErrors(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n \n // Match .catch() with arrow functions or function expressions\n const swallowedPatterns = [\n // .catch(() => {}) or .catch(() => { })\n /\\.catch\\s*\\(\\s*\\(\\s*\\w*\\s*\\)\\s*=>\\s*\\{\\s*\\}\\s*\\)/g,\n // .catch(() => null) or .catch(() => undefined)\n /\\.catch\\s*\\(\\s*\\(\\s*\\w*\\s*\\)\\s*=>\\s*(?:null|undefined)\\s*\\)/g,\n // .catch(function() {}) \n /\\.catch\\s*\\(\\s*function\\s*\\(\\s*\\w*\\s*\\)\\s*\\{\\s*\\}\\s*\\)/g,\n ];\n\n for (const pattern of swallowedPatterns) {\n let match: RegExpExecArray | null;\n \n while ((match = pattern.exec(file.content)) !== null) {\n if (isInsideStringOrComment(file.content, match.index)) continue;\n\n issues.push(\n this.createIssue({\n severity: SEVERITY.HIGH,\n message: 'Promise .catch() swallows error without handling',\n filePath: file.path,\n line: getLineNumber(file.content, match.index),\n codeSnippet: match[0],\n suggestion: 'Handle the error: log it, report to monitoring, show user feedback, or re-throw.',\n learnMoreUrl: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#error_handling',\n }),\n );\n }\n }\n\n // Check for .catch(e => console.log(e)) pattern\n const consoleOnlyCatchPattern = /\\.catch\\s*\\(\\s*\\(?\\s*(\\w+)\\s*\\)?\\s*=>\\s*\\{?\\s*console\\.(log|error|warn)\\s*\\(\\s*\\1\\s*\\)\\s*;?\\s*\\}?\\s*\\)/g;\n let match: RegExpExecArray | null;\n \n while ((match = consoleOnlyCatchPattern.exec(file.content)) !== null) {\n if (isInsideStringOrComment(file.content, match.index)) continue;\n\n issues.push(\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: 'Promise .catch() only logs error without proper handling',\n filePath: file.path,\n line: getLineNumber(file.content, match.index),\n codeSnippet: match[0],\n suggestion: 'Consider reporting to an error monitoring service or showing user feedback.',\n learnMoreUrl: 'https://kentcdodds.com/blog/get-a-catch-block-error-message-with-typescript',\n }),\n );\n }\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // Missing Error Boundary (React)\n // ---------------------------------------------------------------------------\n\n private checkMissingErrorBoundary(\n files: readonly ProjectFile[],\n context: RuleContext,\n ): Issue[] {\n const deps = { ...context.packageJson?.dependencies, ...context.packageJson?.devDependencies };\n if (!('react' in deps)) return [];\n\n const hasErrorBoundary = files.some(\n (f) =>\n /\\bErrorBoundary\\b/.test(f.content) ||\n /\\bcomponentDidCatch\\b/.test(f.content) ||\n /react-error-boundary/.test(f.content),\n );\n\n if (!hasErrorBoundary) {\n return [\n this.createIssue({\n message: 'React project has no ErrorBoundary component',\n filePath: 'project',\n suggestion: 'Add an ErrorBoundary: npm install react-error-boundary',\n learnMoreUrl: 'https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary',\n }),\n ];\n }\n\n return [];\n }\n\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n private deduplicateProjectIssues(issues: Issue[]): Issue[] {\n const seen = new Set<string>();\n return issues.filter((issue) => {\n if (issue.filePath !== 'project') return true;\n const key = `${issue.ruleId}:${issue.message}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n }\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\nimport { isTestFile, getLineNumber } from './analysis-helpers.js';\n\n/**\n * RULE-009: Abandoned TODO/FIXME Comments\n *\n * Detects TODO, FIXME, HACK, and XXX comments left in production code.\n *\n * WHY: AI-generated code is riddled with placeholder comments like\n * \"// TODO: implement error handling\" that never get resolved. Each\n * unresolved TODO is a ticking time bomb — incomplete logic that\n * vibecoders accepted without finishing the implementation.\n * These comments signal unfinished work that shipped anyway.\n */\nexport class AbandonedTodoRule extends BaseRule {\n readonly id = RULE_ID.ABANDONED_TODO;\n readonly name = 'Abandoned TODO/FIXME';\n readonly description = 'Detects unresolved TODO, FIXME, HACK, and XXX comments';\n readonly defaultSeverity = SEVERITY.MEDIUM;\n\n /** Matches TODO/FIXME/HACK/XXX in single-line and block comments */\n private static readonly TODO_PATTERN =\n /(?:\\/\\/|\\/\\*|\\*)\\s*(TODO|FIXME|HACK|XXX)\\b[:\\s]*(.*?)(?:\\*\\/)?$/gim;\n\n /** Keywords that indicate urgent/unfinished work → MEDIUM severity */\n private static readonly URGENT_KEYWORDS = /\\b(FIXME|HACK|XXX)\\b/i;\n\n /** Patterns suggesting low-urgency TODOs (optimization, nice-to-have) */\n private static readonly LOW_URGENCY =\n /\\b(optimi[zs]e|later|eventually|nice.to.have|someday|maybe|consider)\\b/i;\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n const issues: Issue[] = [];\n\n for (const file of context.files) {\n if (isTestFile(file.path)) continue;\n\n // Strip JSDoc/block comments to avoid flagging TODOs in documentation\n const contentWithoutJsdoc = file.content.replace(/\\/\\*\\*[\\s\\S]*?\\*\\//g, (match) =>\n '\\n'.repeat((match.match(/\\n/g) ?? []).length),\n );\n\n const regex = new RegExp(\n AbandonedTodoRule.TODO_PATTERN.source,\n AbandonedTodoRule.TODO_PATTERN.flags,\n );\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(contentWithoutJsdoc)) !== null) {\n const keyword = match[1] ?? 'TODO';\n const comment = match[2]?.trim() ?? '';\n const line = getLineNumber(contentWithoutJsdoc, match.index);\n const severity = this.classifySeverity(keyword, comment);\n\n const snippet = file.content.split('\\n')[line - 1]?.trim() ?? '';\n\n issues.push(\n this.createIssue({\n severity,\n message: `Unresolved ${keyword.toUpperCase()}${comment ? `: \"${comment}\"` : ''}`,\n filePath: file.path,\n line,\n codeSnippet: snippet,\n suggestion:\n 'Remove this TODO by implementing the missing functionality, or create a ticket to track it.',\n learnMoreUrl: 'https://refactoring.guru/smells/comments',\n }),\n );\n }\n }\n\n return issues;\n }\n\n /**\n * Classifies severity based on keyword and comment content.\n * FIXME/HACK/XXX → always MEDIUM (indicates broken/hacky code).\n * TODO with low-urgency language + code below → LOW.\n * TODO with context (e.g., \"implement this\") → MEDIUM.\n */\n private classifySeverity(keyword: string, comment: string): typeof SEVERITY.MEDIUM | typeof SEVERITY.LOW {\n if (AbandonedTodoRule.URGENT_KEYWORDS.test(keyword)) {\n return SEVERITY.MEDIUM;\n }\n\n if (comment && AbandonedTodoRule.LOW_URGENCY.test(comment)) {\n return SEVERITY.LOW;\n }\n\n return SEVERITY.MEDIUM;\n }\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext, ProjectFile } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\n\n/**\n * RULE-010: Bloated Barrel Files\n *\n * Detects index/barrel files with excessive re-exports.\n *\n * WHY: AI tools love generating barrel files that re-export everything\n * from a directory. This kills tree-shaking, slows down bundlers,\n * creates circular dependency risks, and makes IDE auto-imports\n * unreliable. A barrel with 30+ re-exports is a sign that nobody\n * thought about module boundaries — they just dumped everything.\n */\nexport class BloatedBarrelRule extends BaseRule {\n readonly id = RULE_ID.BLOATED_BARREL;\n readonly name = 'Bloated Barrel Files';\n readonly description = 'Detects barrel/index files with excessive re-exports';\n readonly defaultSeverity = SEVERITY.MEDIUM;\n\n /** Thresholds for re-export counts */\n private static readonly MEDIUM_THRESHOLD = 15;\n private static readonly HIGH_THRESHOLD = 30;\n\n /** Matches barrel file names */\n private static readonly BARREL_PATTERN = /^index\\.[jt]sx?$/;\n\n /** Matches re-export statements */\n private static readonly RE_EXPORT_PATTERNS = [\n /export\\s+\\{[^}]*\\}\\s+from\\s+['\"][^'\"]+['\"]/g,\n /export\\s+\\*\\s+from\\s+['\"][^'\"]+['\"]/g,\n /export\\s+\\*\\s+as\\s+\\w+\\s+from\\s+['\"][^'\"]+['\"]/g,\n /export\\s+type\\s+\\{[^}]*\\}\\s+from\\s+['\"][^'\"]+['\"]/g,\n ];\n\n /** Patterns that indicate actual logic (not just re-exports) */\n private static readonly LOGIC_PATTERNS = [\n /(?:const|let|var)\\s+\\w+\\s*=(?!\\s*require)/,\n /function\\s+\\w+/,\n /class\\s+\\w+/,\n /if\\s*\\(/,\n /for\\s*\\(/,\n /while\\s*\\(/,\n /switch\\s*\\(/,\n ];\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n const issues: Issue[] = [];\n\n for (const file of context.files) {\n if (!this.isBarrelFile(file)) continue;\n if (this.hasActualLogic(file.content)) continue;\n\n const reExportCount = this.countReExports(file.content);\n\n if (reExportCount > BloatedBarrelRule.MEDIUM_THRESHOLD) {\n const severity =\n reExportCount > BloatedBarrelRule.HIGH_THRESHOLD\n ? SEVERITY.HIGH\n : SEVERITY.MEDIUM;\n\n issues.push(\n this.createIssue({\n severity,\n message: `Barrel file has ${reExportCount} re-exports`,\n filePath: file.path,\n suggestion: `This barrel file re-exports ${reExportCount} modules. Consider organizing into sub-barrels by domain (e.g., components/index.ts, utils/index.ts).`,\n learnMoreUrl:\n 'https://marvinh.dev/blog/speeding-up-javascript-ecosystem-part-7/',\n }),\n );\n }\n }\n\n return issues;\n }\n\n private isBarrelFile(file: ProjectFile): boolean {\n const fileName = file.path.split('/').pop() ?? '';\n return BloatedBarrelRule.BARREL_PATTERN.test(fileName);\n }\n\n /**\n * Checks if the file contains actual logic beyond re-exports.\n * If it does, it's not a pure barrel file — skip it.\n */\n private hasActualLogic(content: string): boolean {\n // Strip all export/import lines to check for remaining logic\n const strippedLines = content\n .split('\\n')\n .filter((line) => {\n const trimmed = line.trim();\n return (\n trimmed.length > 0 &&\n !trimmed.startsWith('//') &&\n !trimmed.startsWith('*') &&\n !trimmed.startsWith('/*') &&\n !trimmed.startsWith('export') &&\n !trimmed.startsWith('import')\n );\n });\n\n return strippedLines.some((line) =>\n BloatedBarrelRule.LOGIC_PATTERNS.some((p) => p.test(line)),\n );\n }\n\n /** Counts the number of re-export statements in the file */\n private countReExports(content: string): number {\n let count = 0;\n\n for (const pattern of BloatedBarrelRule.RE_EXPORT_PATTERNS) {\n const regex = new RegExp(pattern.source, pattern.flags);\n const matches = content.match(regex);\n count += matches?.length ?? 0;\n }\n\n return count;\n }\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext, ProjectFile } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\nimport { isTestFile } from './analysis-helpers.js';\n\n/**\n * RULE-011: Style Inconsistency\n *\n * Detects mixed coding styles across the project: naming conventions,\n * function declaration styles, quote styles, and semicolon usage.\n *\n * WHY: When you vibecode with AI, each prompt generates code in whatever\n * style the model feels like. One file uses camelCase, the next snake_case.\n * Arrow functions here, function declarations there. The result is a\n * Frankenstein codebase with zero consistency — a clear sign nobody\n * reviewed or enforced standards.\n */\nexport class StyleInconsistencyRule extends BaseRule {\n readonly id = RULE_ID.STYLE_INCONSISTENCY;\n readonly name = 'Style Inconsistency';\n readonly description = 'Detects mixed coding styles across the project';\n readonly defaultSeverity = SEVERITY.MEDIUM;\n\n /** Minimum percentage for minority style to be flagged (avoids one-off noise) */\n private static readonly MINORITY_THRESHOLD = 20;\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n const sourceFiles = context.files.filter(\n (f) => !isTestFile(f.path) && /\\.[jt]sx?$/.test(f.extension),\n );\n\n if (sourceFiles.length === 0) return [];\n\n const issues: Issue[] = [];\n\n this.checkNamingStyle(sourceFiles, issues);\n this.checkFunctionStyle(sourceFiles, issues);\n this.checkQuoteStyle(sourceFiles, issues);\n this.checkSemicolonStyle(sourceFiles, issues);\n\n return issues;\n }\n\n /** Detects mix of camelCase vs snake_case in variable/function declarations */\n private checkNamingStyle(files: readonly ProjectFile[], issues: Issue[]): void {\n let camelCount = 0;\n let snakeCount = 0;\n\n const declRegex = /(?:const|let|var|function)\\s+([a-zA-Z_]\\w*)/g;\n\n for (const file of files) {\n const regex = new RegExp(declRegex.source, declRegex.flags);\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(file.content)) !== null) {\n const name = match[1] ?? '';\n if (name.length < 2) continue;\n // Skip UPPER_SNAKE (constants) and PascalCase (classes/components)\n if (/^[A-Z_][A-Z0-9_]*$/.test(name)) continue;\n if (/^[A-Z]/.test(name)) continue;\n\n if (name.includes('_')) snakeCount++;\n else if (/[a-z][A-Z]/.test(name)) camelCount++;\n }\n }\n\n this.reportMix('naming', 'camelCase', camelCount, 'snake_case', snakeCount, issues);\n }\n\n /** Detects mix of function declarations vs arrow function expressions */\n private checkFunctionStyle(files: readonly ProjectFile[], issues: Issue[]): void {\n let declarationCount = 0;\n let arrowCount = 0;\n\n for (const file of files) {\n const declarations = file.content.match(/^(?:export\\s+)?function\\s+\\w+/gm);\n declarationCount += declarations?.length ?? 0;\n\n const arrows = file.content.match(/(?:const|let|var)\\s+\\w+\\s*=\\s*(?:async\\s+)?\\([^)]*\\)\\s*=>/gm);\n arrowCount += arrows?.length ?? 0;\n }\n\n this.reportMix('function style', 'function declarations', declarationCount, 'arrow functions', arrowCount, issues);\n }\n\n /** Detects mix of single quotes vs double quotes in imports */\n private checkQuoteStyle(files: readonly ProjectFile[], issues: Issue[]): void {\n let singleCount = 0;\n let doubleCount = 0;\n\n for (const file of files) {\n const singles = file.content.match(/(?:import|from)\\s+'[^']*'/g);\n singleCount += singles?.length ?? 0;\n\n const doubles = file.content.match(/(?:import|from)\\s+\"[^\"]*\"/g);\n doubleCount += doubles?.length ?? 0;\n }\n\n this.reportMix('quote style', 'single quotes', singleCount, 'double quotes', doubleCount, issues);\n }\n\n /** Detects mix of semicolons vs no-semicolons at end of statements */\n private checkSemicolonStyle(files: readonly ProjectFile[], issues: Issue[]): void {\n let withSemi = 0;\n let withoutSemi = 0;\n\n // Only check meaningful statement lines (skip comments, blank, braces)\n const statementLine = /^(?!.*(?:\\/\\/|\\/\\*|\\*\\/|\\*\\s))(?!.*[{}\\s]*$).+$/;\n\n for (const file of files) {\n for (const line of file.content.split('\\n')) {\n const trimmed = line.trim();\n if (!statementLine.test(trimmed)) continue;\n if (trimmed.length < 3) continue;\n // Skip lines ending with { } , ( — not statement endings\n if (/[{},(\\s]$/.test(trimmed)) continue;\n\n if (trimmed.endsWith(';')) withSemi++;\n else if (/\\w['\"`)\\]]$/.test(trimmed)) withoutSemi++;\n }\n }\n\n this.reportMix('semicolons', 'with semicolons', withSemi, 'without semicolons', withoutSemi, issues);\n }\n\n /**\n * Reports a style inconsistency if the minority style exceeds the threshold.\n * Only creates an issue when both styles are meaningfully present.\n */\n private reportMix(\n type: string,\n styleA: string,\n countA: number,\n styleB: string,\n countB: number,\n issues: Issue[],\n ): void {\n const total = countA + countB;\n if (total < 5) return; // Not enough data to judge\n\n const [majority, majorityCount, minority, minorityCount] =\n countA >= countB\n ? [styleA, countA, styleB, countB] as const\n : [styleB, countB, styleA, countA] as const;\n\n const minorityPct = Math.round((minorityCount / total) * 100);\n\n if (minorityPct < StyleInconsistencyRule.MINORITY_THRESHOLD) return;\n\n const majorityPct = 100 - minorityPct;\n\n issues.push(\n this.createIssue({\n message: `Mixed ${type}: ${majority} (${majorityPct}%) vs ${minority} (${minorityPct}%)`,\n filePath: 'project',\n suggestion: `Found mixed ${type}: ${majority} (${majorityPct}%) vs ${minority} (${minorityPct}%). Pick one style and use it consistently. Consider using a formatter like Biome or Prettier.`,\n learnMoreUrl: 'https://google.github.io/styleguide/tsguide.html',\n }),\n );\n }\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\n\n/**\n * RULE-012: Duplicate Dependencies\n *\n * Detects multiple packages that serve the same purpose in package.json.\n *\n * WHY: Every AI prompt is stateless — it doesn't know you already have\n * axios when it suggests installing node-fetch. Vibecoders end up with\n * 3 HTTP clients, 2 state managers, and 2 validation libraries.\n * This bloats bundle size, confuses the team, and creates maintenance\n * nightmares when you need to update or patch vulnerabilities.\n */\nexport class DuplicateDepsRule extends BaseRule {\n readonly id = RULE_ID.DUPLICATE_DEPS;\n readonly name = 'Duplicate Dependencies';\n readonly description = 'Detects multiple packages serving the same purpose';\n readonly defaultSeverity = SEVERITY.HIGH;\n\n /**\n * Categories of packages that serve the same purpose.\n * If 2+ from the same category are installed, it's a problem.\n */\n private static readonly CATEGORIES: ReadonlyMap<string, readonly string[]> = new Map([\n ['HTTP client', ['axios', 'node-fetch', 'got', 'ky', 'superagent', 'undici']],\n ['state management', ['redux', '@reduxjs/toolkit', 'zustand', 'jotai', 'recoil', 'mobx', 'valtio', 'xstate']],\n ['testing framework', ['jest', 'vitest', 'mocha', 'ava', 'jasmine']],\n ['CSS-in-JS', ['styled-components', '@emotion/react', '@emotion/styled', 'stitches', '@vanilla-extract/css', 'linaria']],\n ['date library', ['moment', 'dayjs', 'date-fns', 'luxon']],\n ['validation', ['zod', 'yup', 'joi', 'ajv', 'superstruct', 'valibot']],\n ['logging', ['winston', 'pino', 'bunyan', 'log4js', 'morgan']],\n ['ORM', ['prisma', '@prisma/client', 'typeorm', 'sequelize', 'drizzle-orm', 'knex', 'mikro-orm']],\n ['bundler', ['webpack', 'vite', 'esbuild', 'rollup', 'parcel', 'turbopack']],\n ['linter/formatter', ['eslint', '@biomejs/biome', 'biome', 'tslint']],\n ]);\n\n /**\n * Known valid combinations that should NOT be flagged.\n * Each entry is a Set of package names that commonly coexist.\n */\n private static readonly ALLOWED_COMBOS: readonly ReadonlySet<string>[] = [\n new Set(['eslint', 'prettier']),\n new Set(['@biomejs/biome', 'prettier']),\n new Set(['@prisma/client', 'prisma']),\n new Set(['redux', '@reduxjs/toolkit']),\n new Set(['@emotion/react', '@emotion/styled']),\n ];\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n const { packageJson } = context;\n if (!packageJson) return [];\n\n const allDeps = new Set([\n ...Object.keys(packageJson.dependencies ?? {}),\n ...Object.keys(packageJson.devDependencies ?? {}),\n ]);\n\n if (allDeps.size === 0) return [];\n\n const issues: Issue[] = [];\n\n for (const [category, packages] of DuplicateDepsRule.CATEGORIES) {\n const found = packages.filter((pkg) => allDeps.has(pkg));\n\n if (found.length < 2) continue;\n if (this.isAllowedCombo(found)) continue;\n\n issues.push(\n this.createIssue({\n message: `Found ${found.length} ${category} libraries: ${found.join(', ')}`,\n filePath: 'package.json',\n suggestion: `Found ${found.length} ${category} libraries: ${found.join(', ')}. Pick ONE and remove the rest. Multiple libraries for the same purpose add bundle size and confusion.`,\n learnMoreUrl: 'https://bundlephobia.com/',\n }),\n );\n }\n\n return issues;\n }\n\n /**\n * Checks if the found packages form a known valid combination.\n * E.g., eslint + prettier is standard and should not be flagged.\n */\n private isAllowedCombo(found: readonly string[]): boolean {\n const foundSet = new Set(found);\n\n return DuplicateDepsRule.ALLOWED_COMBOS.some((combo) => {\n // If ALL found packages are within a single allowed combo, skip\n if (foundSet.size <= combo.size && [...foundSet].every((pkg) => combo.has(pkg))) {\n return true;\n }\n return false;\n });\n }\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext, ProjectFile } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\nimport { isTestFile } from './analysis-helpers.js';\n\n/**\n * RULE-013: God File\n *\n * Detects files with too many responsibilities: excessive exports,\n * mixed concerns (classes + utils + types), and high import fan-in.\n *\n * WHY: AI generates everything you ask for in a single file. Need a\n * component, its types, helper functions, and API calls? The AI dumps\n * it all in one place. The result is a \"god file\" that every other\n * file depends on — impossible to refactor, test, or reason about.\n * This is the #1 architectural smell in vibecoded projects.\n */\nexport class GodFileRule extends BaseRule {\n readonly id = RULE_ID.GOD_FILE;\n readonly name = 'God File';\n readonly description = 'Detects files with too many responsibilities';\n readonly defaultSeverity = SEVERITY.HIGH;\n\n private static readonly MAX_EXPORTS = 10;\n private static readonly MAX_IMPORTERS = 8;\n private static readonly MIN_CONCERN_CATEGORIES = 3;\n\n /** Barrel/index file pattern — skip these */\n private static readonly BARREL_PATTERN = /(?:^|\\/)index\\.[jt]sx?$/;\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n const { files } = context;\n const issues: Issue[] = [];\n\n // Pre-compute import fan-in map: filePath → count of files that import it\n const importerCounts = this.buildImporterMap(files);\n\n for (const file of files) {\n if (this.shouldSkip(file)) continue;\n\n const exportCount = this.countExports(file.content);\n const concernCount = this.countConcernCategories(file.content);\n const importerCount = importerCounts.get(file.path) ?? 0;\n\n const reasons: string[] = [];\n\n if (exportCount > GodFileRule.MAX_EXPORTS) {\n reasons.push(`${exportCount} exports (max: ${GodFileRule.MAX_EXPORTS})`);\n }\n\n if (concernCount >= GodFileRule.MIN_CONCERN_CATEGORIES) {\n reasons.push(`${concernCount} mixed concern types`);\n }\n\n if (importerCount > GodFileRule.MAX_IMPORTERS) {\n reasons.push(`imported by ${importerCount} files`);\n }\n\n // Flag if at least 2 signals fire (avoids false positives from a single metric)\n if (reasons.length >= 2) {\n issues.push(\n this.createIssue({\n message: `God file detected: ${reasons.join(', ')}`,\n filePath: file.path,\n suggestion: `This file has ${exportCount} exports and is imported by ${importerCount} files. It's doing too much. Split by responsibility using the Single Responsibility Principle.`,\n learnMoreUrl: 'https://refactoring.guru/smells/large-class',\n }),\n );\n }\n }\n\n return issues;\n }\n\n private shouldSkip(file: ProjectFile): boolean {\n if (isTestFile(file.path)) return true;\n if (GodFileRule.BARREL_PATTERN.test(file.path)) return true;\n if (file.path.endsWith('.d.ts')) return true;\n return false;\n }\n\n /** Counts named exports (export const, export function, export class, etc.) */\n private countExports(content: string): number {\n const patterns = [\n /^export\\s+(?:async\\s+)?function\\s+\\w+/gm,\n /^export\\s+(?:const|let|var)\\s+\\w+/gm,\n /^export\\s+class\\s+\\w+/gm,\n /^export\\s+(?:interface|type)\\s+\\w+/gm,\n /^export\\s+enum\\s+\\w+/gm,\n ];\n\n let count = 0;\n for (const pattern of patterns) {\n const regex = new RegExp(pattern.source, pattern.flags);\n const matches = content.match(regex);\n count += matches?.length ?? 0;\n }\n\n // Also count named re-exports: export { foo, bar, baz }\n const reExportRegex = /export\\s+\\{([^}]+)\\}/g;\n let match: RegExpExecArray | null;\n while ((match = reExportRegex.exec(content)) !== null) {\n const names = match[1];\n if (names) {\n count += names.split(',').length;\n }\n }\n\n return count;\n }\n\n /**\n * Counts how many distinct concern categories exist in the file.\n * Categories: class/component, utility functions, type definitions,\n * constants/config, API/fetch calls.\n */\n private countConcernCategories(content: string): number {\n let categories = 0;\n\n // 1. Class or React component definitions\n if (/(?:^export\\s+)?class\\s+\\w+/m.test(content) || /(?:function|const)\\s+\\w+.*(?:JSX|React|tsx|<\\w+)/m.test(content)) {\n categories++;\n }\n\n // 2. Utility/helper functions (non-class, non-component)\n if (/^export\\s+(?:async\\s+)?function\\s+(?!.*Component|.*Page|.*Layout)\\w+/m.test(content)) {\n categories++;\n }\n\n // 3. Type/interface definitions\n if (/^export\\s+(?:interface|type)\\s+\\w+/m.test(content)) {\n categories++;\n }\n\n // 4. Constants or configuration objects\n if (/^export\\s+const\\s+[A-Z_][A-Z0-9_]*\\s*=/m.test(content)) {\n categories++;\n }\n\n // 5. API/fetch/HTTP calls\n if (/(?:fetch|axios|\\.get|\\.post|\\.put|\\.delete|\\.patch)\\s*\\(/m.test(content)) {\n categories++;\n }\n\n return categories;\n }\n\n /**\n * Builds a map of filePath → number of other files that import from it.\n * Uses relative import paths to match files within the project.\n */\n private buildImporterMap(files: readonly ProjectFile[]): Map<string, number> {\n const counts = new Map<string, number>();\n\n // Collect all import targets from all files\n const importRegex = /(?:import|from)\\s+['\"](\\.[^'\"]+)['\"]/g;\n\n for (const file of files) {\n const regex = new RegExp(importRegex.source, importRegex.flags);\n const seen = new Set<string>(); // Dedupe imports within same file\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(file.content)) !== null) {\n const importPath = match[1];\n if (!importPath) continue;\n\n // Resolve relative import to approximate file path\n const resolved = this.resolveImportPath(file.path, importPath);\n if (resolved && !seen.has(resolved)) {\n seen.add(resolved);\n counts.set(resolved, (counts.get(resolved) ?? 0) + 1);\n }\n }\n }\n\n return counts;\n }\n\n /**\n * Resolves a relative import path against the importing file's directory.\n * Returns the approximate target file path (without extension resolution).\n */\n private resolveImportPath(fromPath: string, importPath: string): string | null {\n const dir = fromPath.split('/').slice(0, -1).join('/');\n const parts = [...dir.split('/'), ...importPath.split('/')].filter(Boolean);\n\n const resolved: string[] = [];\n for (const part of parts) {\n if (part === '.') continue;\n else if (part === '..') resolved.pop();\n else resolved.push(part);\n }\n\n return resolved.join('/') || null;\n }\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext, ProjectFile } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\nimport { isTestFile } from './analysis-helpers.js';\n\n/**\n * RULE-006: Separation of Concerns\n *\n * Detects code that mixes architectural layers — UI with data fetching,\n * route handlers with business logic, or raw SQL outside data layers.\n *\n * WHY: AI tools generate \"working\" code by dumping everything into one file.\n * A React component that fetches data, transforms it, AND renders it is\n * the hallmark of vibecoded slop. Clean architecture separates concerns\n * so each module has ONE reason to change.\n */\nexport class SeparationOfConcernsRule extends BaseRule {\n readonly id = RULE_ID.SEPARATION_OF_CONCERNS;\n readonly name = 'Separation of Concerns';\n readonly description = 'Detects code that mixes UI, data, and business logic layers';\n readonly defaultSeverity = SEVERITY.MEDIUM;\n\n // Actual fetch/data calls - NOT error checking utilities\n // Note: axios patterns handled separately to allow better false positive filtering\n private static readonly FETCH_PATTERNS =\n /(?<!\\w)\\bfetch\\s*\\(|axios\\.(?!isAxiosError|CancelToken|create|defaults|interceptors)\\w+\\s*\\(|\\.query\\s*\\(|prisma\\.\\w+|supabase\\.\\w+/;\n\n // Patterns that look like fetch but are actually something else\n private static readonly FALSE_POSITIVE_PATTERNS = [\n /axios\\.isAxiosError/, // Error type checking, not fetching\n /axios\\.CancelToken/, // Cancel token creation\n /axios\\.create/, // Creating axios instance (config)\n /axios\\.defaults/, // Setting defaults (config)\n /typeof\\s+fetch/, // Type checking\n /window\\.fetch/, // Polyfill checks\n /globalThis\\.fetch/, // Polyfill checks\n ];\n\n private static readonly SQL_KEYWORDS =\n /\\b(SELECT|INSERT\\s+INTO|UPDATE\\s+\\w+\\s+SET|DELETE\\s+FROM|CREATE\\s+TABLE)\\b/;\n\n private static readonly DATA_LAYER_DIRS =\n /\\/(db|database|repositor(y|ies)|dal|data|migrations|seeds?|prisma)\\//i;\n\n private static readonly CONFIG_PATTERNS =\n /\\.(config|setup|env)\\.[jt]sx?$|\\.d\\.ts$/;\n\n /** Auth-related file patterns where data fetching in UI is expected */\n private static readonly AUTH_PATTERNS =\n /\\/(auth|login|signup|sign-up|signout|sign-out|register|forgot-password|reset-password)\\//i;\n\n private static readonly FUNCTION_DEF =\n /(?:^|\\n)\\s*(?:export\\s+)?(?:async\\s+)?function\\s+\\w+|(?:const|let)\\s+\\w+\\s*=\\s*(?:async\\s+)?\\(/g;\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n const issues: Issue[] = [];\n\n for (const file of context.files) {\n if (isTestFile(file.path) || SeparationOfConcernsRule.CONFIG_PATTERNS.test(file.path)) {\n continue;\n }\n\n this.checkUiFetching(file, issues);\n this.checkRouteLogic(file, issues);\n this.checkSqlPlacement(file, issues);\n }\n\n return issues;\n }\n\n /** Check if a line is inside a string literal or template */\n private isInsideStringOrTemplate(line: string, fullContent: string, lineIndex: number): boolean {\n const trimmed = line.trim();\n \n // Line starts with a string quote (likely a string definition)\n if (/^['\"`]/.test(trimmed)) return true;\n \n // Line is inside a template literal (backtick string)\n // Check if we're inside a {`...`} JSX expression\n if (/^\\{`/.test(trimmed) || /`\\}$/.test(trimmed)) return true;\n \n // Check for template literal content (common in code examples)\n // Look for patterns like: {`some code here`}\n if (/\\{`[^`]*$/.test(line) || /^[^`]*`\\}/.test(line)) return true;\n \n // Check if line is part of a multi-line template literal\n // by scanning from the start of the file to this line\n const lines = fullContent.split('\\n');\n \n // More robust: scan from file start to current line\n // Track template literal state (are we inside one?)\n let insideTemplate = false;\n for (let i = 0; i <= lineIndex && i < lines.length; i++) {\n const currentLine = lines[i]!;\n // Count backticks on this line, accounting for escaped ones\n const unescapedBackticks = currentLine.replace(/\\\\`/g, '').match(/`/g) || [];\n \n // Each backtick toggles the state\n for (const _ of unescapedBackticks) {\n insideTemplate = !insideTemplate;\n }\n }\n \n if (insideTemplate) return true;\n \n return false;\n }\n\n /** UI components (.tsx/.jsx) that directly call fetch/axios/prisma/supabase */\n private checkUiFetching(file: ProjectFile, issues: Issue[]): void {\n if (file.extension !== '.tsx' && file.extension !== '.jsx') return;\n\n // Skip auth-related files where data fetching in UI is the expected pattern\n // (OAuth flows, login forms, etc. need to call auth SDKs directly)\n if (SeparationOfConcernsRule.AUTH_PATTERNS.test(file.path)) return;\n\n const lines = file.content.split('\\n');\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n \n // Skip if line matches any false positive pattern\n if (SeparationOfConcernsRule.FALSE_POSITIVE_PATTERNS.some(pattern => pattern.test(line))) {\n continue;\n }\n \n // Skip if inside a string or template literal (code examples, etc.)\n if (this.isInsideStringOrTemplate(line, file.content, i)) {\n continue;\n }\n \n // Skip comments\n const trimmed = line.trim();\n if (trimmed.startsWith('//') || trimmed.startsWith('*') || trimmed.startsWith('/*')) {\n continue;\n }\n \n if (SeparationOfConcernsRule.FETCH_PATTERNS.test(line)) {\n issues.push(\n this.createIssue({\n message: 'UI component contains data fetching logic',\n filePath: file.path,\n line: i + 1,\n codeSnippet: line.trim(),\n suggestion:\n 'Move data fetching to a custom hook (useXxx) or service layer. Components should only handle rendering.',\n learnMoreUrl: 'https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html',\n }),\n );\n }\n }\n }\n\n /** Route handlers (req/res or NextRequest) with >5 function definitions = too much logic */\n private checkRouteLogic(file: ProjectFile, issues: Issue[]): void {\n const hasExpressHandler = /\\breq\\.\\w+/.test(file.content) && /\\bres\\.\\w+/.test(file.content);\n const hasNextHandler = /NextRequest|NextResponse/.test(file.content);\n if (!hasExpressHandler && !hasNextHandler) return;\n\n const regex = new RegExp(SeparationOfConcernsRule.FUNCTION_DEF.source, 'g');\n const matches = file.content.match(regex);\n // Threshold of 5 is reasonable for Next.js App Router where having\n // GET, POST, helper functions in one file is common and acceptable\n if (matches && matches.length > 5) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: `Route handler contains ${matches.length} function definitions — too much business logic`,\n filePath: file.path,\n suggestion:\n 'Extract business logic to a service/use-case layer. Route handlers should only handle HTTP concerns.',\n learnMoreUrl: 'https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html',\n }),\n );\n }\n }\n\n /** Raw SQL strings in files outside data-layer directories */\n private checkSqlPlacement(file: ProjectFile, issues: Issue[]): void {\n if (SeparationOfConcernsRule.DATA_LAYER_DIRS.test(file.path)) return;\n\n const lines = file.content.split('\\n');\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const trimmed = line.trim();\n // Skip comments, regex literals, and string definitions of patterns\n if (trimmed.startsWith('//') || trimmed.startsWith('*') || trimmed.startsWith('/*')) continue;\n if (/^\\s*(?:private|protected|public|static|readonly|const|let|var)\\b.*\\//.test(line)) continue;\n // Skip lines that are regex literals (start with /)\n if (/^\\s*\\/[^/]/.test(line)) continue;\n\n const match = SeparationOfConcernsRule.SQL_KEYWORDS.exec(line);\n if (match) {\n issues.push(\n this.createIssue({\n message: `Raw SQL (${match[1]}) found outside data access layer`,\n filePath: file.path,\n line: i + 1,\n codeSnippet: trimmed,\n suggestion: 'Move database queries to a repository or data access layer.',\n learnMoreUrl: 'https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html',\n }),\n );\n }\n }\n }\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext, ProjectFile } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\nimport { isTestFile, getLineNumber, isInsideStringOrComment } from './analysis-helpers.js';\n\n/**\n * RULE-007: Obsolete Patterns\n *\n * Detects outdated JavaScript/TypeScript patterns that AI models reproduce\n * because their training data includes legacy code.\n *\n * WHY: LLMs are trained on millions of lines of pre-ES6 code. They'll\n * happily generate `var`, callback pyramids, and class components because\n * that's what the training distribution looks like. Modern JS has better\n * alternatives for every one of these patterns.\n */\nexport class ObsoletePatternsRule extends BaseRule {\n readonly id = RULE_ID.OBSOLETE_PATTERNS;\n readonly name = 'Obsolete Patterns';\n readonly description = 'Detects outdated JS/TS patterns that should use modern alternatives';\n readonly defaultSeverity = SEVERITY.MEDIUM;\n\n private static readonly CONFIG_PATTERNS =\n /\\.(config|setup|env)\\.[jt]sx?$|\\.d\\.ts$/;\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n const issues: Issue[] = [];\n\n for (const file of context.files) {\n if (isTestFile(file.path) || ObsoletePatternsRule.CONFIG_PATTERNS.test(file.path)) continue;\n\n this.checkVarDeclarations(file, issues);\n this.checkCallbackHell(file, issues);\n this.checkClassComponents(file, issues);\n this.checkCommonJsInTs(file, issues);\n this.checkLegacyApis(file, issues);\n }\n\n return issues;\n }\n\n /** `var` declarations — should be const/let */\n private checkVarDeclarations(file: ProjectFile, issues: Issue[]): void {\n const lines = file.content.split('\\n');\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n // Match `var ` at word boundary, skip if inside string/comment\n if (/\\bvar\\s+\\w+/.test(line) && !isInsideStringOrComment(file.content, file.content.indexOf(line))) {\n const trimmed = line.trim();\n if (trimmed.startsWith('//') || trimmed.startsWith('*') || trimmed.startsWith('/*')) continue;\n issues.push(this.createObsoleteIssue(file.path, i + 1, trimmed, 'var', 'const/let'));\n }\n }\n }\n\n /** .then() chains with 3+ nesting levels — should be async/await */\n private checkCallbackHell(file: ProjectFile, issues: Issue[]): void {\n const thenChain = /\\.then\\([^)]*\\)\\s*\\.then\\([^)]*\\)\\s*\\.then\\(/;\n if (thenChain.test(file.content)) {\n const line = getLineNumber(file.content, file.content.search(thenChain));\n issues.push(\n this.createIssue({\n message: 'Promise chain with 3+ .then() calls detected',\n filePath: file.path,\n line,\n suggestion: 'Replace .then() chains with async/await. The modern alternative is more readable and less error-prone.',\n learnMoreUrl: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises',\n }),\n );\n }\n }\n\n /** React class components — should be function components */\n private checkClassComponents(file: ProjectFile, issues: Issue[]): void {\n if (file.extension !== '.tsx' && file.extension !== '.jsx') return;\n\n const pattern = /extends\\s+(?:React\\.)?Component\\b/g;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(file.content)) !== null) {\n const line = getLineNumber(file.content, match.index);\n issues.push(\n this.createIssue({\n message: 'React class component detected',\n filePath: file.path,\n line,\n suggestion: 'Replace class components with function components + hooks. The modern alternative is more readable and less error-prone.',\n learnMoreUrl: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises',\n }),\n );\n }\n }\n\n /** require() or module.exports in .ts/.tsx files */\n private checkCommonJsInTs(file: ProjectFile, issues: Issue[]): void {\n if (file.extension !== '.ts' && file.extension !== '.tsx') return;\n\n const patterns = [\n { regex: /\\brequire\\s*\\(/g, name: 'require()' },\n { regex: /\\bmodule\\.exports\\b/g, name: 'module.exports' },\n ];\n\n for (const { regex, name } of patterns) {\n let match: RegExpExecArray | null;\n while ((match = regex.exec(file.content)) !== null) {\n if (isInsideStringOrComment(file.content, match.index)) continue;\n const line = getLineNumber(file.content, match.index);\n issues.push(\n this.createObsoleteIssue(file.path, line, name, 'CommonJS (require/module.exports)', 'ES modules (import/export)'),\n );\n }\n }\n }\n\n /** Legacy APIs: arguments keyword, new Array(), new Object() */\n private checkLegacyApis(file: ProjectFile, issues: Issue[]): void {\n const legacyPatterns: Array<{ regex: RegExp; old: string; modern: string }> = [\n { regex: /\\barguments\\b/g, old: 'arguments keyword', modern: 'rest parameters (...args)' },\n { regex: /\\bnew\\s+Array\\s*\\(/g, old: 'new Array()', modern: 'array literal []' },\n { regex: /\\bnew\\s+Object\\s*\\(/g, old: 'new Object()', modern: 'object literal {}' },\n ];\n\n for (const { regex, old, modern } of legacyPatterns) {\n let match: RegExpExecArray | null;\n while ((match = regex.exec(file.content)) !== null) {\n if (isInsideStringOrComment(file.content, match.index)) continue;\n const line = getLineNumber(file.content, match.index);\n issues.push(this.createObsoleteIssue(file.path, line, match[0].trim(), old, modern));\n }\n }\n }\n\n private createObsoleteIssue(\n filePath: string, line: number, snippet: string, old: string, modern: string,\n ): Issue {\n return this.createIssue({\n message: `Obsolete pattern: \"${old}\" detected`,\n filePath,\n line,\n codeSnippet: snippet,\n suggestion: `Replace ${old} with ${modern}. The modern alternative is more readable and less error-prone.`,\n learnMoreUrl: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises',\n });\n }\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext, ProjectFile } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\nimport { isTestFile, getLineNumber } from './analysis-helpers.js';\n\n/**\n * RULE-016: AI Smell\n *\n * Detects telltale signs of AI-generated code that was accepted without review:\n * obvious comments, leftover console.logs, generic naming, boilerplate, and\n * placeholder logic that was never implemented.\n *\n * WHY: AI tools produce code that \"works\" but is littered with noise —\n * comments that restate the code, variables named `data` or `result`,\n * files named `utils.ts` that become junk drawers, and placeholder\n * implementations that were never completed. These smells indicate the\n * developer accepted AI output without critical review.\n */\nexport class AiSmellRule extends BaseRule {\n readonly id = RULE_ID.AI_SMELL;\n readonly name = 'AI Smell';\n readonly description = 'Detects signs of unreviewed AI-generated code';\n readonly defaultSeverity = SEVERITY.LOW;\n\n /** Comment patterns that just restate the next line of code */\n private static readonly OBVIOUS_COMMENT_PAIRS: ReadonlyArray<{ comment: RegExp; code: RegExp }> = [\n // Only flag very obvious restating comments - be conservative\n { comment: /\\/\\/\\s*get\\s+the\\s+\\w+\\s*$/i, code: /\\bget\\w+/i },\n { comment: /\\/\\/\\s*set\\s+the\\s+\\w+\\s*$/i, code: /\\bset\\w+/i },\n { comment: /\\/\\/\\s*return\\s+the\\s+\\w+\\s*$/i, code: /\\breturn\\b/ },\n { comment: /\\/\\/\\s*increment\\s+\\w+\\s*$/i, code: /\\+\\+|\\+=\\s*1/ },\n { comment: /\\/\\/\\s*loop\\s+through\\s+\\w+\\s*$/i, code: /\\bfor\\b|\\.forEach|\\.map/ },\n // Don't flag \"check if X\" - often contains useful context\n ];\n\n /** Variable names that scream \"I didn't think about naming\" */\n private static readonly GENERIC_NAMES = new Set([\n 'data', 'result', 'temp', 'tmp', 'info', 'item', 'element',\n 'val', 'obj', 'arr', 'str', 'num', 'flag', 'ret',\n ]);\n\n /** File basenames that are dumping grounds */\n private static readonly GENERIC_FILES = new Set([\n 'utils.ts', 'helpers.ts', 'misc.ts', 'common.ts', 'stuff.ts',\n 'utils.js', 'helpers.js', 'misc.js', 'common.js', 'stuff.js',\n 'utils.tsx', 'helpers.tsx', 'misc.tsx', 'common.tsx', 'stuff.tsx',\n 'utils.jsx', 'helpers.jsx', 'misc.jsx', 'common.jsx', 'stuff.jsx',\n ]);\n\n /** CRA boilerplate markers — all must be present to flag */\n private static readonly CRA_MARKERS = [\n 'This project was bootstrapped with',\n 'Getting Started',\n 'Available Scripts',\n 'Learn More',\n ];\n\n /** Placeholder implementation patterns - code that was never finished */\n private static readonly PLACEHOLDER_PATTERNS: ReadonlyArray<{\n pattern: RegExp;\n message: string;\n severity: typeof SEVERITY[keyof typeof SEVERITY];\n }> = [\n {\n pattern: /throw\\s+new\\s+Error\\s*\\(\\s*['\"`](?:Not\\s+implemented|TODO|FIXME|implement|stub)['\"`]\\s*\\)/gi,\n message: 'Placeholder \"throw new Error\" - implementation never completed',\n severity: SEVERITY.HIGH,\n },\n {\n pattern: /throw\\s+new\\s+Error\\s*\\(\\s*['\"`].*(?:not\\s+yet|coming\\s+soon|later).*['\"`]\\s*\\)/gi,\n message: 'Deferred implementation - code promises future work that may never happen',\n severity: SEVERITY.MEDIUM,\n },\n {\n pattern: /return\\s+(?:null|undefined)\\s*;?\\s*\\/\\/\\s*(?:TODO|FIXME|placeholder|stub|implement)/gi,\n message: 'Placeholder return with TODO comment - incomplete implementation',\n severity: SEVERITY.HIGH,\n },\n {\n pattern: /\\/\\/\\s*TODO:?\\s*implement\\s+(?:this|here|later|soon)/gi,\n message: 'TODO comment marking unimplemented code',\n severity: SEVERITY.MEDIUM,\n },\n {\n pattern: /\\(\\s*\\)\\s*=>\\s*\\{\\s*\\}\\s*(?:,|;|\\))/g,\n message: 'Empty arrow function - likely a placeholder callback',\n severity: SEVERITY.LOW,\n },\n ];\n\n /** AI-generated code markers */\n private static readonly AI_MARKERS: ReadonlyArray<{\n pattern: RegExp;\n message: string;\n }> = [\n {\n pattern: /\\/[/*]\\s*(?:Generated|Created|Written)\\s+(?:by|with|using)\\s+(?:AI|ChatGPT|GPT-?4?|Claude|Copilot|Gemini|Bard)/gi,\n message: 'AI attribution comment - code may need human review',\n },\n {\n pattern: /\\/[/*]\\s*(?:This\\s+(?:code|function|class)\\s+was\\s+)?(?:auto-?generated|machine-?generated)/gi,\n message: 'Auto-generated code marker - verify correctness',\n },\n ];\n\n /** Boilerplate comment patterns that indicate copy-paste from docs/tutorials */\n private static readonly BOILERPLATE_COMMENTS: ReadonlyArray<{\n pattern: RegExp;\n message: string;\n }> = [\n {\n pattern: /\\/[/*]\\s*(?:Example|Sample)\\s+(?:usage|code|implementation):/gi,\n message: 'Example/sample code comment - likely copied from documentation',\n },\n {\n pattern: /\\/[/*]\\s*(?:Copy|Paste)\\s+(?:this|the\\s+following)/gi,\n message: 'Copy-paste instruction comment left in code',\n },\n {\n pattern: /\\/[/*]\\s*(?:Replace|Change)\\s+(?:this|the\\s+following)\\s+with\\s+your/gi,\n message: 'Template instruction comment - customization never completed',\n },\n ];\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n const issues: Issue[] = [];\n\n for (const file of context.files) {\n // README boilerplate check (only for README.md)\n if (file.path.endsWith('README.md')) {\n this.checkBoilerplateReadme(file, issues);\n continue;\n }\n\n // Skip non-source and markdown files\n if (!['.ts', '.tsx', '.js', '.jsx'].includes(file.extension)) continue;\n\n // Generic file name check\n this.checkGenericFileName(file, issues);\n\n if (isTestFile(file.path)) continue;\n\n this.checkObviousComments(file, issues);\n this.checkConsoleLog(file, issues);\n this.checkGenericNaming(file, issues);\n this.checkPlaceholderCode(file, issues);\n this.checkAiMarkers(file, issues);\n this.checkBoilerplateComments(file, issues);\n }\n\n return issues;\n }\n\n private checkObviousComments(file: ProjectFile, issues: Issue[]): void {\n const lines = file.content.split('\\n');\n for (let i = 0; i < lines.length - 1; i++) {\n const commentLine = lines[i]!.trim();\n const nextLine = lines[i + 1]!.trim();\n if (!commentLine.startsWith('//')) continue;\n\n // Skip comments that contain useful context (numbers, times, reasons, etc.)\n if (this.hasUsefulContext(commentLine)) continue;\n\n for (const pair of AiSmellRule.OBVIOUS_COMMENT_PAIRS) {\n if (pair.comment.test(commentLine) && pair.code.test(nextLine)) {\n issues.push(this.createIssue({\n message: 'Obvious comment that restates the code',\n filePath: file.path,\n line: i + 1,\n codeSnippet: commentLine,\n suggestion: 'Remove comments that just restate what the code does. Good comments explain WHY, not WHAT.',\n learnMoreUrl: 'https://refactoring.guru/smells/comments',\n }));\n break;\n }\n }\n }\n }\n\n /**\n * Checks if a comment contains useful context beyond just restating code.\n * Comments with numbers, times, reasons, warnings, etc. are valuable.\n */\n private hasUsefulContext(comment: string): boolean {\n // Contains numbers (often timeouts, limits, versions, etc.)\n if (/\\d+/.test(comment)) return true;\n \n // Contains time units\n if (/\\b(?:min|sec|hour|day|ms|millisecond|second|minute)\\b/i.test(comment)) return true;\n \n // Contains reason/explanation words\n if (/\\b(?:because|since|due\\s+to|reason|why|note|important|warning|caution|never|always|must|security|performance|workaround|hack|bug|fix)\\b/i.test(comment)) return true;\n \n // Contains URLs or references\n if (/https?:\\/\\/|see\\s+|refer\\s+to|@see/i.test(comment)) return true;\n \n // Long comments (>50 chars after //) likely have context\n const commentText = comment.replace(/^\\/\\/\\s*/, '');\n if (commentText.length > 50) return true;\n \n return false;\n }\n\n /** Files where console.log is expected (CLI entry points, scripts) */\n private static readonly CLI_PATTERNS = /(?:cli|bin|scripts?|commands?)\\.[jt]sx?$/;\n\n private checkConsoleLog(file: ProjectFile, issues: Issue[]): void {\n // Skip CLI entry points where console.log IS the output mechanism\n if (AiSmellRule.CLI_PATTERNS.test(file.path)) return;\n\n const regex = /\\bconsole\\.log\\s*\\(/g;\n let match: RegExpExecArray | null;\n while ((match = regex.exec(file.content)) !== null) {\n const line = getLineNumber(file.content, match.index);\n issues.push(this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: 'console.log left in production code',\n filePath: file.path,\n line,\n suggestion: 'Remove console.log or replace with a proper logger. Use console.error/warn for intentional logging.',\n learnMoreUrl: 'https://refactoring.guru/smells/comments',\n }));\n }\n }\n\n private checkGenericNaming(file: ProjectFile, issues: Issue[]): void {\n // Match variable declarations, but exclude destructuring patterns like { data }\n // Destructuring is idiomatic: const { data } = await response.json()\n const regex = /\\b(?:const|let|var)\\s+(\\w+)\\s*=/g;\n let match: RegExpExecArray | null;\n while ((match = regex.exec(file.content)) !== null) {\n const name = match[1]!;\n if (AiSmellRule.GENERIC_NAMES.has(name)) {\n // Skip if this looks like destructuring (preceded by { or ,)\n const beforeMatch = file.content.slice(Math.max(0, match.index - 20), match.index);\n if (/[{,]\\s*$/.test(beforeMatch)) continue;\n \n // Skip if there's a type annotation (const data: SomeType =)\n const afterName = file.content.slice(match.index + match[0].length, match.index + match[0].length + 30);\n if (/^\\s*:/.test(afterName)) continue;\n\n const line = getLineNumber(file.content, match.index);\n issues.push(this.createIssue({\n severity: SEVERITY.INFO,\n message: `Generic variable name \"${name}\" — lacks semantic meaning`,\n filePath: file.path,\n line,\n codeSnippet: match[0],\n suggestion: `Rename \"${name}\" to describe what it actually holds (e.g., \"userData\", \"fetchResult\", \"parsedConfig\").`,\n learnMoreUrl: 'https://refactoring.guru/smells/comments',\n }));\n }\n }\n }\n\n private checkGenericFileName(file: ProjectFile, issues: Issue[]): void {\n const basename = file.path.split('/').pop() ?? '';\n if (AiSmellRule.GENERIC_FILES.has(basename)) {\n issues.push(this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: `Generic file name \"${basename}\" — likely a dumping ground`,\n filePath: file.path,\n suggestion: `Rename to describe its purpose (e.g., \"string-formatters.ts\", \"date-helpers.ts\", \"validation.ts\").`,\n learnMoreUrl: 'https://refactoring.guru/smells/comments',\n }));\n }\n }\n\n private checkBoilerplateReadme(file: ProjectFile, issues: Issue[]): void {\n const hasAll = AiSmellRule.CRA_MARKERS.every((marker) => file.content.includes(marker));\n if (hasAll) {\n issues.push(this.createIssue({\n message: 'Boilerplate README detected (Create React App default)',\n filePath: file.path,\n suggestion: 'Replace the default README with actual project documentation: what it does, how to run it, architecture decisions.',\n learnMoreUrl: 'https://refactoring.guru/smells/comments',\n }));\n }\n }\n\n // ---------------------------------------------------------------------------\n // Placeholder Code Detection\n // ---------------------------------------------------------------------------\n\n private checkPlaceholderCode(file: ProjectFile, issues: Issue[]): void {\n for (const { pattern, message, severity } of AiSmellRule.PLACEHOLDER_PATTERNS) {\n const regex = new RegExp(pattern.source, pattern.flags);\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(file.content)) !== null) {\n const line = getLineNumber(file.content, match.index);\n const snippet = match[0].slice(0, 60) + (match[0].length > 60 ? '...' : '');\n\n issues.push(this.createIssue({\n severity,\n message,\n filePath: file.path,\n line,\n codeSnippet: snippet,\n suggestion: 'Complete the implementation or remove the placeholder. Shipping stubs to production is a code smell.',\n learnMoreUrl: 'https://refactoring.guru/smells/lazy-class',\n }));\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // AI Attribution Markers\n // ---------------------------------------------------------------------------\n\n private checkAiMarkers(file: ProjectFile, issues: Issue[]): void {\n for (const { pattern, message } of AiSmellRule.AI_MARKERS) {\n const regex = new RegExp(pattern.source, pattern.flags);\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(file.content)) !== null) {\n const line = getLineNumber(file.content, match.index);\n\n issues.push(this.createIssue({\n severity: SEVERITY.LOW,\n message,\n filePath: file.path,\n line,\n codeSnippet: match[0],\n suggestion: 'Review AI-generated code carefully. Remove attribution comments after verification.',\n learnMoreUrl: 'https://refactoring.guru/smells/comments',\n }));\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Boilerplate Comments (copy-paste from docs)\n // ---------------------------------------------------------------------------\n\n private checkBoilerplateComments(file: ProjectFile, issues: Issue[]): void {\n for (const { pattern, message } of AiSmellRule.BOILERPLATE_COMMENTS) {\n const regex = new RegExp(pattern.source, pattern.flags);\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(file.content)) !== null) {\n const line = getLineNumber(file.content, match.index);\n\n issues.push(this.createIssue({\n severity: SEVERITY.MEDIUM,\n message,\n filePath: file.path,\n line,\n codeSnippet: match[0],\n suggestion: 'Remove boilerplate comments. Code should be self-documenting or have meaningful comments.',\n learnMoreUrl: 'https://refactoring.guru/smells/comments',\n }));\n }\n }\n }\n}\n","import type { ProjectFile } from '@vibertest/shared';\n\n/**\n * Helpers for the code-duplication rule.\n * Handles normalization, chunking, and hashing of source code\n * to detect duplicate blocks across files.\n */\n\n/** A detected duplicate block shared between two files */\nexport interface DuplicateBlock {\n readonly hash: string;\n readonly lineCount: number;\n readonly occurrences: ReadonlyArray<{ filePath: string; startLine: number }>;\n}\n\n/** Minimum consecutive lines to consider a duplicate */\nconst MIN_CHUNK_SIZE = 10;\n\n/** Maximum chunk size to check (performance cap) */\nconst MAX_CHUNK_SIZE = 30;\n\n/**\n * Normalizes a line for comparison: trims whitespace, removes\n * single-line comments, and collapses remaining whitespace.\n */\nfunction normalizeLine(line: string): string {\n return line\n .replace(/\\/\\/.*$/, '') // strip single-line comments\n .replace(/\\/\\*.*?\\*\\//g, '') // strip inline block comments\n .trim()\n .replace(/\\s+/g, ' ');\n}\n\n/**\n * Lines that are too generic to be meaningful duplicates.\n * These are structural patterns that naturally repeat across\n * UI components, route handlers, and boilerplate.\n */\nconst GENERIC_LINE_PATTERNS = [\n /^return\\s*\\(?\\s*$/, // return (\n /^\\);\\s*$/, // );\n /^}\\s*$/, // }\n /^<\\/\\w+>\\s*$/, // </div>\n /^<\\w+\\s*$/, // <div\n /^className=/, // className=...\n /^<\\w+\\s+className=/, // <div className=...\n /^export\\s+default\\s+/, // export default\n /^\"use\\s+(client|server)\"/, // \"use client\" / \"use server\"\n /^try\\s*{$/, // try {\n /^}\\s*catch\\s*\\(/, // } catch (\n /^}\\s*finally\\s*{$/, // } finally {\n /^const\\s+\\[\\w+,\\s*set\\w+\\]\\s*=\\s*useState/, // const [x, setX] = useState\n /^const\\s+\\w+\\s*=\\s*useRef/, // const x = useRef\n /^useEffect\\s*\\(\\s*\\(\\)\\s*=>\\s*{$/, // useEffect(() => {\n];\n\n/** Checks if a normalized line is too generic to count as meaningful duplication */\nfunction isGenericLine(normalized: string): boolean {\n return GENERIC_LINE_PATTERNS.some((pattern) => pattern.test(normalized));\n}\n\n/**\n * Prepares file content for duplication analysis:\n * - Strips import lines (imports naturally repeat)\n * - Strips empty/comment-only lines\n * - Strips type/interface declarations (can legitimately repeat)\n * - Strips generic UI/structural lines that repeat by nature\n * Returns array of { normalized, originalLine } tuples.\n */\nexport function prepareLines(\n content: string,\n): ReadonlyArray<{ normalized: string; originalLine: number }> {\n const raw = content.split('\\n');\n const result: Array<{ normalized: string; originalLine: number }> = [];\n\n let inBlockComment = false;\n\n for (let i = 0; i < raw.length; i++) {\n const line = raw[i]!;\n\n // Track block comments\n if (inBlockComment) {\n if (line.includes('*/')) inBlockComment = false;\n continue;\n }\n if (line.trimStart().startsWith('/*')) {\n if (!line.includes('*/')) inBlockComment = true;\n continue;\n }\n\n const trimmed = line.trim();\n\n // Skip imports, empty lines, comment-only lines, type/interface declarations\n if (\n trimmed === '' ||\n trimmed.startsWith('import ') ||\n trimmed.startsWith('import{') ||\n trimmed.startsWith('//') ||\n trimmed.startsWith('*') ||\n trimmed.startsWith('export type ') ||\n trimmed.startsWith('export interface ') ||\n trimmed.startsWith('type ') ||\n trimmed.startsWith('interface ')\n ) {\n continue;\n }\n\n const normalized = normalizeLine(line);\n if (normalized.length > 0 && !isGenericLine(normalized)) {\n result.push({ normalized, originalLine: i + 1 });\n }\n }\n\n return result;\n}\n\n/**\n * Simple string hash (djb2). Fast and sufficient for dedup detection.\n * Not cryptographic — just needs to be consistent and low-collision.\n */\nfunction djb2Hash(str: string): string {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = ((hash << 5) + hash + str.charCodeAt(i)) | 0;\n }\n return hash.toString(36);\n}\n\n/** Chunk occurrence entry for the hash map */\ninterface ChunkOccurrence {\n filePath: string;\n startLine: number;\n lineCount: number;\n /** The actual normalized chunk content for verification */\n content: string;\n}\n\n/** Builds a hash map of code chunks across all files */\nfunction buildChunkMap(\n files: readonly ProjectFile[],\n): Map<string, ChunkOccurrence[]> {\n const chunkMap = new Map<string, ChunkOccurrence[]>();\n\n for (const file of files) {\n const lines = prepareLines(file.content);\n if (lines.length < MIN_CHUNK_SIZE) continue;\n\n const maxChunk = Math.min(lines.length, MAX_CHUNK_SIZE);\n\n for (let size = MIN_CHUNK_SIZE; size <= maxChunk; size++) {\n for (let start = 0; start <= lines.length - size; start++) {\n const chunk = lines.slice(start, start + size).map((l) => l.normalized).join('\\n');\n const hash = `${size}_${djb2Hash(chunk)}`;\n const startLine = lines[start]!.originalLine;\n\n const existing = chunkMap.get(hash);\n if (existing) {\n const isDifferentFile = existing.every((e) => e.filePath !== file.path);\n // IMPORTANT: Verify actual content match to avoid hash collisions\n const hasMatchingContent = existing.some((e) => e.content === chunk);\n if (isDifferentFile && hasMatchingContent) {\n existing.push({ filePath: file.path, startLine, lineCount: size, content: chunk });\n }\n } else {\n chunkMap.set(hash, [{ filePath: file.path, startLine, lineCount: size, content: chunk }]);\n }\n }\n }\n }\n\n return chunkMap;\n}\n\n/**\n * Finds duplicate code blocks across the given files.\n * Uses a sliding window of MIN_CHUNK_SIZE lines, hashing each chunk\n * and tracking which files contain the same hash.\n */\nexport function findDuplicates(files: readonly ProjectFile[]): readonly DuplicateBlock[] {\n const chunkMap = buildChunkMap(files);\n const duplicates: DuplicateBlock[] = [];\n const reportedPairs = new Set<string>();\n\n for (const [hash, occurrences] of chunkMap) {\n if (occurrences.length < 2) continue;\n\n const pairKey = occurrences.map((o) => o.filePath).sort().join('|');\n if (reportedPairs.has(pairKey)) continue;\n reportedPairs.add(pairKey);\n\n duplicates.push({\n hash,\n lineCount: occurrences[0]!.lineCount,\n occurrences: occurrences.map((o) => ({ filePath: o.filePath, startLine: o.startLine })),\n });\n }\n\n return duplicates;\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\nimport { isTestFile } from './analysis-helpers.js';\nimport { findDuplicates } from './code-duplication-helpers.js';\n\n/**\n * RULE-009: Code Duplication\n *\n * Detects blocks of code that are copy-pasted across multiple files.\n *\n * WHY: AI tools generate code per-prompt with no memory of what they\n * already generated. The result is the same validation logic, the same\n * fetch wrapper, the same error handler duplicated across 5 files.\n * Copy-paste is the enemy of maintainability — fix a bug in one place,\n * forget the other four. DRY exists for a reason.\n */\nexport class CodeDuplicationRule extends BaseRule {\n readonly id = RULE_ID.CODE_DUPLICATION;\n readonly name = 'Code Duplication';\n readonly description = 'Detects duplicate code blocks across files';\n readonly defaultSeverity = SEVERITY.MEDIUM;\n\n /** Minimum duplicate lines to classify as HIGH severity */\n private static readonly HIGH_SEVERITY_THRESHOLD = 20;\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n // Filter to source files, skip tests (test setup legitimately repeats)\n const sourceFiles = context.files.filter(\n (f) => ['.ts', '.tsx', '.js', '.jsx'].includes(f.extension) && !isTestFile(f.path),\n );\n\n if (sourceFiles.length < 2) return [];\n\n const duplicates = findDuplicates(sourceFiles);\n const issues: Issue[] = [];\n\n for (const dup of duplicates) {\n const severity = dup.lineCount >= CodeDuplicationRule.HIGH_SEVERITY_THRESHOLD ? SEVERITY.HIGH : SEVERITY.MEDIUM;\n const files = dup.occurrences.map((o) => o.filePath);\n const firstOccurrence = dup.occurrences[0]!;\n\n issues.push(\n this.createIssue({\n severity,\n message: `${dup.lineCount} duplicate lines found across ${files.length} files`,\n filePath: firstOccurrence.filePath,\n line: firstOccurrence.startLine,\n suggestion: `Found ${dup.lineCount} duplicate lines between ${files[0]} and ${files[1]}. Extract to a shared module to follow DRY principle.`,\n learnMoreUrl: 'https://refactoring.guru/smells/duplicate-code',\n }),\n );\n }\n\n return issues;\n }\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext, ProjectFile } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\nimport { isTestFile } from './analysis-helpers.js';\n\n/**\n * RULE-010: Circular Dependencies\n *\n * Builds an import graph from relative imports and detects cycles using\n * DFS with three-color marking (white → gray → black).\n *\n * WHY: AI tools generate code file-by-file without understanding the\n * dependency graph. Module A imports B, B imports C, C imports A — boom,\n * circular dependency. This causes runtime errors, undefined imports,\n * and makes the codebase impossible to reason about. Bundlers may handle\n * it, but your architecture shouldn't rely on bundler magic.\n */\nexport class CircularDepsRule extends BaseRule {\n readonly id = RULE_ID.CIRCULAR_DEPS;\n readonly name = 'Circular Dependencies';\n readonly description = 'Detects circular import chains between modules';\n readonly defaultSeverity = SEVERITY.HIGH;\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n const sourceFiles = context.files.filter(\n (f) => ['.ts', '.tsx', '.js', '.jsx'].includes(f.extension) && !isTestFile(f.path),\n );\n\n const graph = this.buildImportGraph(sourceFiles);\n const cycles = this.detectCycles(graph);\n const issues: Issue[] = [];\n\n // Deduplicate cycles (A→B→A is the same as B→A→B)\n const reported = new Set<string>();\n\n for (const cycle of cycles) {\n const key = [...cycle].sort().join('|');\n if (reported.has(key)) continue;\n reported.add(key);\n\n const chain = [...cycle, cycle[0]].join(' → ');\n issues.push(\n this.createIssue({\n message: `Circular dependency: ${chain}`,\n filePath: cycle[0]!,\n suggestion: `Circular dependency detected: ${chain}. Break the cycle by extracting shared code to a third module.`,\n learnMoreUrl: 'https://refactoring.guru/smells/shotgun-surgery',\n }),\n );\n }\n\n return issues;\n }\n\n /**\n * Builds a directed graph: file → [files it imports via relative paths].\n * Only considers relative imports (starting with . or ..).\n */\n private buildImportGraph(files: readonly ProjectFile[]): Map<string, string[]> {\n const graph = new Map<string, string[]>();\n const filePaths = new Set(files.map((f) => f.path));\n\n for (const file of files) {\n const imports = this.extractRelativeImports(file);\n const resolved: string[] = [];\n\n for (const imp of imports) {\n const target = this.resolveImport(file.path, imp, filePaths);\n if (target) resolved.push(target);\n }\n\n graph.set(file.path, resolved);\n }\n\n return graph;\n }\n\n /** Extracts relative import paths from a file's content */\n private extractRelativeImports(file: ProjectFile): string[] {\n const regex = /(?:import|export)\\s+.*?from\\s+['\"](\\.[^'\"]+)['\"]/g;\n const imports: string[] = [];\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(file.content)) !== null) {\n imports.push(match[1]!);\n }\n\n // Also catch dynamic imports: import('./foo')\n const dynamicRegex = /import\\s*\\(\\s*['\"](\\.[^'\"]+)['\"]\\s*\\)/g;\n while ((match = dynamicRegex.exec(file.content)) !== null) {\n imports.push(match[1]!);\n }\n\n return imports;\n }\n\n /**\n * Resolves a relative import to an actual file path in the project.\n * Tries common extensions: .ts, .tsx, .js, .jsx, /index.ts, /index.js\n */\n private resolveImport(fromPath: string, importPath: string, knownFiles: Set<string>): string | null {\n const dir = fromPath.split('/').slice(0, -1).join('/');\n const segments = importPath.split('/');\n const resolved: string[] = dir ? dir.split('/') : [];\n\n for (const seg of segments) {\n if (seg === '.') continue;\n else if (seg === '..') resolved.pop();\n else resolved.push(seg);\n }\n\n const base = resolved.join('/');\n const extensions = ['.ts', '.tsx', '.js', '.jsx'];\n\n // Direct match (import already has extension)\n if (knownFiles.has(base)) return base;\n\n // Try adding extensions\n for (const ext of extensions) {\n if (knownFiles.has(base + ext)) return base + ext;\n }\n\n // Try index files\n for (const ext of extensions) {\n const indexPath = `${base}/index${ext}`;\n if (knownFiles.has(indexPath)) return indexPath;\n }\n\n return null;\n }\n\n /**\n * DFS cycle detection with three-color marking:\n * - WHITE (unvisited) → start DFS\n * - GRAY (in current path) → cycle found!\n * - BLACK (fully explored) → skip\n */\n private detectCycles(graph: Map<string, string[]>): string[][] {\n const WHITE = 0, GRAY = 1, BLACK = 2;\n const color = new Map<string, number>();\n const parent = new Map<string, string>();\n const cycles: string[][] = [];\n\n for (const node of graph.keys()) {\n color.set(node, WHITE);\n }\n\n const dfs = (node: string): void => {\n color.set(node, GRAY);\n\n for (const neighbor of graph.get(node) ?? []) {\n if (!color.has(neighbor)) continue;\n\n if (color.get(neighbor) === GRAY) {\n // Found a cycle — reconstruct it\n const cycle = [neighbor];\n let current = node;\n while (current !== neighbor) {\n cycle.push(current);\n current = parent.get(current) ?? neighbor;\n }\n cycle.reverse();\n cycles.push(cycle);\n } else if (color.get(neighbor) === WHITE) {\n parent.set(neighbor, node);\n dfs(neighbor);\n }\n }\n\n color.set(node, BLACK);\n };\n\n for (const node of graph.keys()) {\n if (color.get(node) === WHITE) {\n dfs(node);\n }\n }\n\n return cycles;\n }\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext, ProjectFile } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\nimport { isTestFile, getLineNumber, isInsideStringOrComment } from './analysis-helpers.js';\n\n/**\n * RULE-019: Security Anti-Patterns\n *\n * Detects common security vulnerabilities in code.\n *\n * WHY: AI-generated code often ignores security best practices.\n * These patterns can lead to data breaches, XSS, SQL injection, etc.\n */\nexport class SecurityAntipatternsRule extends BaseRule {\n readonly id = RULE_ID.SECURITY_ANTIPATTERNS;\n readonly name = 'Security Anti-Patterns';\n readonly description = 'Detects common security vulnerabilities and anti-patterns';\n readonly defaultSeverity = SEVERITY.HIGH;\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n const { files, packageJson } = context;\n const issues: Issue[] = [];\n\n for (const file of files) {\n if (isTestFile(file.path)) continue;\n\n issues.push(...this.checkSqlInjection(file));\n issues.push(...this.checkCorsWildcard(file));\n issues.push(...this.checkLocalStorageSensitive(file));\n issues.push(...this.checkDangerousHtml(file));\n issues.push(...this.checkEvalUsage(file));\n issues.push(...this.checkInsecureRandomness(file));\n issues.push(...this.checkHardcodedCredentials(file));\n }\n\n // Project-level checks\n issues.push(...this.checkMissingSecurityHeaders(files, packageJson));\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // SQL Injection Detection\n // ---------------------------------------------------------------------------\n\n /**\n * Detects potential SQL injection vulnerabilities:\n * - Template literals in SQL queries\n * - String concatenation in SQL queries\n */\n private checkSqlInjection(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n const lines = file.content.split('\\n');\n\n // SQL statement patterns (more specific to avoid false positives)\n // Must have SQL keyword followed by typical SQL syntax\n const sqlPatterns = [\n /\\bSELECT\\s+[\\w*,\\s]+\\s+FROM\\b/i, // SELECT ... FROM\n /\\bINSERT\\s+INTO\\s+\\w+/i, // INSERT INTO table\n /\\bUPDATE\\s+\\w+\\s+SET\\b/i, // UPDATE table SET\n /\\bDELETE\\s+FROM\\s+\\w+/i, // DELETE FROM table\n /\\bDROP\\s+(TABLE|DATABASE|INDEX)\\b/i, // DROP TABLE/DATABASE/INDEX\n /\\bCREATE\\s+(TABLE|DATABASE|INDEX)\\b/i, // CREATE TABLE/DATABASE/INDEX\n /\\bALTER\\s+TABLE\\s+\\w+/i, // ALTER TABLE table\n /\\bTRUNCATE\\s+TABLE\\b/i, // TRUNCATE TABLE (not just \"truncate\")\n /\\bEXEC(UTE)?\\s+\\w+/i, // EXEC/EXECUTE procedure\n ];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n \n // Skip comments\n if (line.trim().startsWith('//') || line.trim().startsWith('*')) continue;\n\n // Find template literals with interpolation\n const templateMatch = /`([^`]*\\$\\{[^}]+\\}[^`]*)`/.exec(line);\n if (templateMatch) {\n const templateContent = templateMatch[1]!;\n // Only flag if the template literal contains a SQL statement pattern\n if (sqlPatterns.some(pattern => pattern.test(templateContent))) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.CRITICAL,\n message: 'Potential SQL injection: template literal with variable interpolation in SQL query',\n filePath: file.path,\n line: i + 1,\n codeSnippet: line.trim().slice(0, 80),\n suggestion: 'Use parameterized queries or prepared statements instead of string interpolation.',\n learnMoreUrl: 'https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html',\n }),\n );\n }\n }\n\n // Find string concatenation with SQL\n const concatPattern = /([\"'])([^\"']*)\\1\\s*\\+\\s*\\w+|\\w+\\s*\\+\\s*([\"'])([^\"']*)\\3/g;\n let concatMatch: RegExpExecArray | null;\n \n while ((concatMatch = concatPattern.exec(line)) !== null) {\n const stringContent = concatMatch[2] || concatMatch[4] || '';\n if (sqlPatterns.some(pattern => pattern.test(stringContent))) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.CRITICAL,\n message: 'Potential SQL injection: string concatenation in SQL query',\n filePath: file.path,\n line: i + 1,\n codeSnippet: line.trim().slice(0, 80),\n suggestion: 'Use parameterized queries or prepared statements instead of string concatenation.',\n learnMoreUrl: 'https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html',\n }),\n );\n break;\n }\n }\n }\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // CORS Wildcard Detection\n // ---------------------------------------------------------------------------\n\n /**\n * Detects CORS wildcard configuration outside test files\n */\n private checkCorsWildcard(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n \n // Skip config files that might legitimately have CORS settings documented\n if (/\\.(md|txt|json)$/.test(file.path)) return [];\n\n const patterns = [\n // cors({ origin: '*' })\n /cors\\s*\\(\\s*\\{[^}]*origin\\s*:\\s*['\"`]\\*['\"`]/,\n // Access-Control-Allow-Origin: *\n /Access-Control-Allow-Origin['\"`:]\\s*['\"`]?\\*/,\n // res.header('Access-Control-Allow-Origin', '*')\n /\\.header\\s*\\(\\s*['\"`]Access-Control-Allow-Origin['\"`]\\s*,\\s*['\"`]\\*['\"`]\\s*\\)/,\n // setHeader('Access-Control-Allow-Origin', '*')\n /setHeader\\s*\\(\\s*['\"`]Access-Control-Allow-Origin['\"`]\\s*,\\s*['\"`]\\*['\"`]\\s*\\)/,\n ];\n\n for (const pattern of patterns) {\n const match = pattern.exec(file.content);\n if (match) {\n const line = getLineNumber(file.content, match.index);\n issues.push(\n this.createIssue({\n severity: SEVERITY.HIGH,\n message: 'CORS wildcard (*) allows any origin to access your API',\n filePath: file.path,\n line,\n codeSnippet: match[0].slice(0, 60),\n suggestion: 'Restrict CORS to specific trusted origins instead of using wildcard.',\n learnMoreUrl: 'https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html',\n }),\n );\n }\n }\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // localStorage Sensitive Data Detection\n // ---------------------------------------------------------------------------\n\n /**\n * Detects storing sensitive data in localStorage\n */\n private checkLocalStorageSensitive(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n \n // Sensitive key patterns\n const sensitiveKeys = [\n 'token', 'jwt', 'auth', 'session', 'password', 'secret', \n 'apikey', 'api_key', 'api-key', 'credential', 'private',\n 'access_token', 'refresh_token', 'bearer'\n ];\n\n const pattern = /localStorage\\.setItem\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/gi;\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(file.content)) !== null) {\n const key = match[1]!.toLowerCase();\n \n if (sensitiveKeys.some(sensitive => key.includes(sensitive))) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.HIGH,\n message: `Sensitive data \"${match[1]}\" stored in localStorage (vulnerable to XSS)`,\n filePath: file.path,\n line: getLineNumber(file.content, match.index),\n codeSnippet: match[0],\n suggestion: 'Use httpOnly cookies for sensitive tokens, or encrypt data before storing.',\n learnMoreUrl: 'https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html#local-storage',\n }),\n );\n }\n }\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // Dangerous HTML Injection Detection\n // ---------------------------------------------------------------------------\n\n /**\n * Detects dangerous HTML injection patterns\n */\n private checkDangerousHtml(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n const lines = file.content.split('\\n');\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n \n // Skip comments\n if (line.trim().startsWith('//') || line.trim().startsWith('*')) continue;\n\n // innerHTML with variable\n if (/\\.innerHTML\\s*=\\s*(?!['\"`]<)/.test(line)) {\n // Check if it's not a static string\n if (!/\\.innerHTML\\s*=\\s*['\"`][^'\"`]*['\"`]\\s*;?\\s*$/.test(line)) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.HIGH,\n message: 'innerHTML with dynamic content is vulnerable to XSS',\n filePath: file.path,\n line: i + 1,\n codeSnippet: line.trim().slice(0, 80),\n suggestion: 'Use textContent for text, or sanitize HTML with DOMPurify.',\n learnMoreUrl: 'https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html',\n }),\n );\n }\n }\n\n // dangerouslySetInnerHTML in React\n if (/dangerouslySetInnerHTML\\s*=\\s*\\{\\s*\\{/.test(line)) {\n // Check if __html comes from a variable (not a static string)\n const nextLines = lines.slice(i, i + 3).join(' ');\n if (!/__html\\s*:\\s*['\"`][^'\"`]*['\"`]/.test(nextLines)) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: 'dangerouslySetInnerHTML with dynamic content requires careful sanitization',\n filePath: file.path,\n line: i + 1,\n codeSnippet: line.trim().slice(0, 80),\n suggestion: 'Ensure HTML is sanitized with DOMPurify before rendering.',\n learnMoreUrl: 'https://react.dev/reference/react-dom/components/common#dangerously-setting-the-inner-html',\n }),\n );\n }\n }\n\n // document.write\n if (/document\\.write\\s*\\(/.test(line)) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.HIGH,\n message: 'document.write() is dangerous and can enable XSS attacks',\n filePath: file.path,\n line: i + 1,\n codeSnippet: line.trim().slice(0, 80),\n suggestion: 'Use DOM manipulation methods like createElement() and appendChild() instead.',\n learnMoreUrl: 'https://developer.mozilla.org/en-US/docs/Web/API/Document/write#notes',\n }),\n );\n }\n }\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // eval() Usage Detection\n // ---------------------------------------------------------------------------\n\n /**\n * Detects usage of eval() and similar dangerous functions\n */\n private checkEvalUsage(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n \n const dangerousFunctions = [\n { pattern: /\\beval\\s*\\(/, name: 'eval()' },\n { pattern: /new\\s+Function\\s*\\(/, name: 'new Function()' },\n { pattern: /setTimeout\\s*\\(\\s*['\"`]/, name: 'setTimeout() with string' },\n { pattern: /setInterval\\s*\\(\\s*['\"`]/, name: 'setInterval() with string' },\n ];\n\n for (const { pattern, name } of dangerousFunctions) {\n let match: RegExpExecArray | null;\n const regex = new RegExp(pattern.source, 'g');\n\n while ((match = regex.exec(file.content)) !== null) {\n if (isInsideStringOrComment(file.content, match.index)) continue;\n\n issues.push(\n this.createIssue({\n severity: SEVERITY.CRITICAL,\n message: `${name} executes arbitrary code and is a security risk`,\n filePath: file.path,\n line: getLineNumber(file.content, match.index),\n codeSnippet: match[0],\n suggestion: 'Avoid eval() and similar functions. Use safer alternatives like JSON.parse() for data.',\n learnMoreUrl: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#never_use_eval!',\n }),\n );\n }\n }\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // Insecure Randomness Detection\n // ---------------------------------------------------------------------------\n\n /**\n * Detects usage of Math.random() for security-sensitive operations\n */\n private checkInsecureRandomness(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n const lines = file.content.split('\\n');\n\n // Security-sensitive contexts (more specific to avoid false positives)\n const sensitiveContexts = [\n 'token', 'secret', 'apikey', 'api_key', 'password', 'salt', 'nonce', \n 'csrf', 'session_id', 'sessionid', 'auth_token', 'authtoken',\n 'access_token', 'refresh_token', 'jwt', 'bearer'\n ];\n\n // Contexts that are NOT security-sensitive (common false positives)\n const safePrefixes = [\n 'toast', 'modal', 'dialog', 'popup', 'notification', 'message',\n 'animation', 'particle', 'canvas', 'color', 'style', 'css',\n 'component', 'element', 'node', 'item', 'index', 'key'\n ];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const lineLower = line.toLowerCase();\n \n if (/Math\\.random\\s*\\(\\s*\\)/.test(line)) {\n // Skip if it's in a safe context\n if (safePrefixes.some(prefix => lineLower.includes(prefix))) {\n continue;\n }\n \n // Check if used in security-sensitive context\n if (sensitiveContexts.some(ctx => lineLower.includes(ctx))) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.HIGH,\n message: 'Math.random() is not cryptographically secure for security-sensitive operations',\n filePath: file.path,\n line: i + 1,\n codeSnippet: line.trim().slice(0, 80),\n suggestion: 'Use crypto.randomUUID() or crypto.getRandomValues() for security-sensitive randomness.',\n learnMoreUrl: 'https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues',\n }),\n );\n }\n }\n }\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // Hardcoded Credentials in Code (beyond env files)\n // ---------------------------------------------------------------------------\n\n /**\n * Detects hardcoded credentials in code\n */\n private checkHardcodedCredentials(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n \n // Skip env files (handled by hardcoded-secrets rule)\n if (/\\.env/.test(file.path)) return [];\n\n const patterns = [\n // password = \"...\"\n { pattern: /\\bpassword\\s*[:=]\\s*['\"`][^'\"`]{4,}['\"`]/i, type: 'password' },\n // apiKey = \"...\"\n { pattern: /\\b(api[_-]?key|apikey)\\s*[:=]\\s*['\"`][^'\"`]{8,}['\"`]/i, type: 'API key' },\n // secret = \"...\"\n { pattern: /\\b(secret|private[_-]?key)\\s*[:=]\\s*['\"`][^'\"`]{8,}['\"`]/i, type: 'secret' },\n // Authorization: \"Bearer ...\"\n { pattern: /Authorization['\"`:]\\s*['\"`]Bearer\\s+[A-Za-z0-9._-]{20,}['\"`]/i, type: 'bearer token' },\n ];\n\n for (const { pattern, type } of patterns) {\n let match: RegExpExecArray | null;\n const regex = new RegExp(pattern.source, 'gi');\n\n while ((match = regex.exec(file.content)) !== null) {\n // Skip if it looks like a placeholder or example\n const value = match[0].toLowerCase();\n if (\n value.includes('example') ||\n value.includes('placeholder') ||\n value.includes('your_') ||\n value.includes('xxx') ||\n value.includes('***') ||\n value.includes('...') ||\n value.includes('abc123') ||\n value.includes('process.env') ||\n value.includes('${')\n ) {\n continue;\n }\n\n // Skip JSX props that contain code examples\n const lineStart = file.content.lastIndexOf('\\n', match.index) + 1;\n const lineEnd = file.content.indexOf('\\n', match.index);\n const line = file.content.slice(lineStart, lineEnd === -1 ? undefined : lineEnd);\n if (/(?:text|code|example|snippet|content)=\\{?['\"`]/i.test(line)) {\n continue;\n }\n \n // Skip if it's inside a string that looks like a code example\n if (/['\"`]export\\s+const\\s+\\w+\\s*=/.test(line)) {\n continue;\n }\n\n issues.push(\n this.createIssue({\n severity: SEVERITY.CRITICAL,\n message: `Hardcoded ${type} found in source code`,\n filePath: file.path,\n line: getLineNumber(file.content, match.index),\n codeSnippet: match[0].slice(0, 40) + '...',\n suggestion: 'Move credentials to environment variables and use process.env.',\n learnMoreUrl: 'https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html',\n }),\n );\n }\n }\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // Missing Security Headers (Express/Node projects)\n // ---------------------------------------------------------------------------\n\n /**\n * Checks if Express projects have security headers configured\n */\n private checkMissingSecurityHeaders(\n files: readonly ProjectFile[],\n packageJson?: Record<string, unknown>,\n ): Issue[] {\n const deps = {\n ...(packageJson?.dependencies as Record<string, string> | undefined),\n ...(packageJson?.devDependencies as Record<string, string> | undefined),\n };\n\n // Only check Express projects\n if (!('express' in deps)) return [];\n\n // Check if helmet is installed\n const hasHelmet = 'helmet' in deps;\n \n // Check if helmet is used in any file\n const usesHelmet = files.some(f => \n /\\bhelmet\\s*\\(/.test(f.content) || \n /app\\.use\\s*\\(\\s*helmet/.test(f.content)\n );\n\n if (!hasHelmet || !usesHelmet) {\n return [\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: 'Express project without Helmet security headers',\n filePath: 'project',\n suggestion: 'Install and use Helmet: npm install helmet && app.use(helmet())',\n learnMoreUrl: 'https://helmetjs.github.io/',\n }),\n ];\n }\n\n return [];\n }\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext, ProjectFile } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\nimport { isTestFile, getLineNumber } from './analysis-helpers.js';\n\n/**\n * RULE-020: React Performance Anti-Patterns\n *\n * Detects common React patterns that cause unnecessary re-renders\n * and performance issues.\n *\n * WHY: AI-generated React code often works but performs poorly.\n * These patterns cause components to re-render unnecessarily,\n * leading to sluggish UIs and wasted resources.\n */\nexport class ReactPerformanceRule extends BaseRule {\n readonly id = RULE_ID.REACT_PERFORMANCE;\n readonly name = 'React Performance Anti-Patterns';\n readonly description = 'Detects React patterns that cause unnecessary re-renders';\n readonly defaultSeverity = SEVERITY.MEDIUM;\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n const { files, packageJson } = context;\n \n // Only run on React projects\n const deps = {\n ...(packageJson?.dependencies as Record<string, string> | undefined),\n ...(packageJson?.devDependencies as Record<string, string> | undefined),\n };\n \n if (!('react' in deps)) return [];\n\n const issues: Issue[] = [];\n\n for (const file of files) {\n if (isTestFile(file.path)) continue;\n if (!this.isReactFile(file)) continue;\n\n // Only check the most impactful patterns\n issues.push(...this.checkArrayIndexAsKey(file));\n issues.push(...this.checkUseEffectMissingDeps(file));\n issues.push(...this.checkStateInLoop(file));\n issues.push(...this.checkLargeComponentInRender(file));\n \n // These are lower priority - only check if file doesn't have other issues\n const fileIssueCount = issues.filter(i => i.filePath === file.path).length;\n if (fileIssueCount === 0) {\n issues.push(...this.checkInlineObjectsInJsx(file));\n issues.push(...this.checkInlineFunctionsInJsx(file));\n issues.push(...this.checkSpreadPropsAntipattern(file));\n }\n }\n\n return issues;\n }\n\n /**\n * Check if file is a React component file\n */\n private isReactFile(file: ProjectFile): boolean {\n // Check for React imports or JSX\n return /\\bimport\\s+.*\\bReact\\b|from\\s+['\"]react['\"]|<\\w+[^>]*>/.test(file.content);\n }\n\n // ---------------------------------------------------------------------------\n // Inline Objects in JSX Props\n // ---------------------------------------------------------------------------\n\n /**\n * Detects inline object literals in JSX props like:\n * - style={{ color: 'red' }}\n * - options={{ foo: 'bar' }}\n * \n * These create new object references on every render.\n */\n private checkInlineObjectsInJsx(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n const lines = file.content.split('\\n');\n\n // Pattern: prop={{ ... }} or prop={[ ... ]}\n // But NOT: prop={{ __html: ... }} (dangerouslySetInnerHTML is intentional)\n // And NOT: className={{ ... }} (CSS modules pattern)\n const inlineObjectPattern = /\\b(\\w+)\\s*=\\s*\\{\\s*(\\{(?!_|\\.\\.\\.)[^}]*\\}|\\[[^\\]]*\\])\\s*\\}/g;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n \n // Skip if not in JSX context (simple heuristic: has < or is indented after <)\n if (!/<\\w+/.test(line) && !line.trim().startsWith('<') && !/^\\s{2,}\\w+=/.test(line)) {\n continue;\n }\n\n let match: RegExpExecArray | null;\n const regex = new RegExp(inlineObjectPattern.source, 'g');\n\n while ((match = regex.exec(line)) !== null) {\n const propName = match[1]!.toLowerCase();\n \n // Skip known safe patterns\n if (this.isSafeInlineProp(propName, match[2]!)) continue;\n\n // Skip style prop with simple static values\n if (propName === 'style' && this.isSimpleStyleObject(match[2]!)) continue;\n\n issues.push(\n this.createIssue({\n message: `Inline ${match[2]!.startsWith('[') ? 'array' : 'object'} in \"${match[1]}\" prop creates new reference on every render`,\n filePath: file.path,\n line: i + 1,\n codeSnippet: line.trim().slice(0, 80),\n suggestion: 'Extract to a constant outside the component, or use useMemo() for computed values.',\n learnMoreUrl: 'https://react.dev/reference/react/useMemo#skipping-expensive-recalculations',\n }),\n );\n }\n }\n\n // Limit to 2 per file to avoid noise\n return issues.slice(0, 2);\n }\n\n /**\n * Check if prop is safe to have inline objects\n */\n private isSafeInlineProp(propName: string, value: string): boolean {\n // dangerouslySetInnerHTML is intentional\n if (propName === 'dangerouslysetinnerhtml') return true;\n // className with CSS modules\n if (propName === 'classname' && /styles\\[/.test(value)) return true;\n // Spread props\n if (value.startsWith('{...')) return true;\n // Empty objects/arrays\n if (value === '{}' || value === '[]') return true;\n // Framer Motion animation props (these are expected to be inline)\n const animationProps = [\n 'initial', 'animate', 'exit', 'transition', 'variants',\n 'whilehover', 'whiletap', 'whileinview', 'whilefocus', 'whiledrag',\n 'viewport', 'layout', 'layoutid', 'dragconstraints', 'dragelastic',\n 'cardtransition'\n ];\n if (animationProps.includes(propName)) return true;\n // Chart/graph props (Recharts, Victory, etc.)\n const chartProps = [\n 'tick', 'margin', 'domain', 'ticks', 'radius', 'offset',\n 'dot', 'activedot', 'wrapperstyle', 'labelstyle', 'contentstyle',\n 'itemstyle', 'legendstyle', 'axisstyle'\n ];\n if (chartProps.includes(propName)) return true;\n // Form library props\n const formProps = ['defaultvalue', 'defaultvalues', 'resolver', 'value', 'steps'];\n if (formProps.includes(propName)) return true;\n return false;\n }\n\n /**\n * Check if style object is simple enough to not matter\n */\n private isSimpleStyleObject(value: string): boolean {\n // Count properties - if only 1-2, it's probably fine\n const propCount = (value.match(/:/g) || []).length;\n return propCount <= 2;\n }\n\n // ---------------------------------------------------------------------------\n // Inline Functions in JSX Props\n // ---------------------------------------------------------------------------\n\n /**\n * Detects inline arrow functions in JSX event handlers:\n * - onClick={() => handleClick()}\n * - onChange={(e) => setValue(e.target.value)}\n * \n * These create new function references on every render.\n * Only flags complex callbacks, not simple ones.\n */\n private checkInlineFunctionsInJsx(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n const lines = file.content.split('\\n');\n\n // Pattern: onEvent={() => ...} or onEvent={(e) => ...}\n const inlineFunctionPattern = /\\b(on\\w+)\\s*=\\s*\\{\\s*\\(?[\\w,\\s]*\\)?\\s*=>/g;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n \n let match: RegExpExecArray | null;\n const regex = new RegExp(inlineFunctionPattern.source, 'g');\n\n while ((match = regex.exec(line)) !== null) {\n const eventName = match[1]!;\n \n // Get the rest of the line after the arrow\n const restOfLine = line.slice(match.index + match[0].length);\n \n // Skip simple callbacks (these are acceptable)\n if (this.isSimpleCallback(restOfLine)) continue;\n \n // Skip if it's a single expression (no braces)\n if (!restOfLine.includes('{') && /^\\s*\\w+\\(/.test(restOfLine)) continue;\n\n issues.push(\n this.createIssue({\n severity: SEVERITY.LOW,\n message: `Inline function in \"${eventName}\" creates new reference on every render`,\n filePath: file.path,\n line: i + 1,\n codeSnippet: line.trim().slice(0, 80),\n suggestion: 'Extract to useCallback() or define as a stable function reference.',\n learnMoreUrl: 'https://react.dev/reference/react/useCallback',\n }),\n );\n }\n }\n\n // Limit to 2 per file - these are very common and often acceptable\n return issues.slice(0, 2);\n }\n\n /**\n * Check if callback is simple enough to not matter\n */\n private isSimpleCallback(restOfLine: string): boolean {\n // Simple function call: doSomething()}\n if (/^\\s*\\w+\\(\\)\\s*\\}/.test(restOfLine)) return true;\n // Simple setter: setValue(value)} or setValue(e.target.value)}\n if (/^\\s*set\\w+\\([^)]*\\)\\s*\\}/.test(restOfLine)) return true;\n // Toggle: setOpen(!open)} or setOpen(prev => !prev)}\n if (/^\\s*set\\w+\\((!|prev)/.test(restOfLine)) return true;\n // Single function call with argument: handleClick(item)}\n if (/^\\s*\\w+\\(\\w+\\)\\s*\\}/.test(restOfLine)) return true;\n // Navigation: router.push(...)} or navigate(...)}\n if (/^\\s*(router|navigate)\\.\\w+\\(/.test(restOfLine)) return true;\n // Event prevention: e.preventDefault()}\n if (/^\\s*e\\.(preventDefault|stopPropagation)\\(\\)/.test(restOfLine)) return true;\n return false;\n }\n\n // ---------------------------------------------------------------------------\n // Array Index as Key\n // ---------------------------------------------------------------------------\n\n /**\n * Detects using array index as key in lists:\n * - {items.map((item, index) => <Item key={index} />)}\n * - {items.map((item, i) => <Item key={i} />)}\n * \n * This causes issues when list items are reordered or filtered.\n * Only flags when the list is likely to be dynamic (has state-like name).\n */\n private checkArrayIndexAsKey(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n \n // Pattern: .map((item, index) => ... key={index}\n const mapWithIndexPattern = /\\.map\\s*\\(\\s*\\(\\s*(\\w+)\\s*,\\s*(\\w+)\\s*\\)\\s*=>/g;\n let mapMatch: RegExpExecArray | null;\n\n while ((mapMatch = mapWithIndexPattern.exec(file.content)) !== null) {\n const itemVar = mapMatch[1]!;\n const indexVar = mapMatch[2]!;\n \n // Look for key={indexVar} in the next ~500 chars\n const searchArea = file.content.slice(mapMatch.index, mapMatch.index + 500);\n const keyPattern = new RegExp(`key\\\\s*=\\\\s*\\\\{\\\\s*${indexVar}\\\\s*\\\\}`, 'g');\n \n if (keyPattern.test(searchArea)) {\n // Check if the item likely has an id property\n // If we see item.id or item.key in the search area, it's worse\n const hasIdProperty = new RegExp(`${itemVar}\\\\.(id|key|uuid|_id)\\\\b`).test(searchArea);\n \n issues.push(\n this.createIssue({\n severity: hasIdProperty ? SEVERITY.HIGH : SEVERITY.MEDIUM,\n message: `Using array index \"${indexVar}\" as key causes issues with list reordering`,\n filePath: file.path,\n line: getLineNumber(file.content, mapMatch.index),\n suggestion: hasIdProperty \n ? `Use ${itemVar}.id as the key instead of the array index.`\n : 'Use a unique identifier from your data (e.g., item.id) as the key instead.',\n learnMoreUrl: 'https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key',\n }),\n );\n }\n }\n\n // Limit to 3 per file\n return issues.slice(0, 3);\n }\n\n // ---------------------------------------------------------------------------\n // useEffect Missing Dependencies\n // ---------------------------------------------------------------------------\n\n /**\n * Detects useEffect with empty dependency array but using external values:\n * - useEffect(() => { doSomething(prop) }, [])\n * \n * This is a common source of stale closure bugs.\n */\n private checkUseEffectMissingDeps(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n \n // Find useEffect with empty deps: useEffect(() => { ... }, [])\n const useEffectPattern = /useEffect\\s*\\(\\s*\\(\\s*\\)\\s*=>\\s*\\{([\\s\\S]*?)\\}\\s*,\\s*\\[\\s*\\]\\s*\\)/g;\n let match: RegExpExecArray | null;\n\n while ((match = useEffectPattern.exec(file.content)) !== null) {\n const effectBody = match[1]!;\n \n // Check if the effect body references external variables\n if (this.hasExternalReferences(effectBody)) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.HIGH,\n message: 'useEffect with empty deps array may have stale closure over props/state',\n filePath: file.path,\n line: getLineNumber(file.content, match.index),\n suggestion: 'Add dependencies to the array, or verify the empty array is intentional.',\n learnMoreUrl: 'https://react.dev/reference/react/useEffect#specifying-reactive-dependencies',\n }),\n );\n }\n }\n\n return issues.slice(0, 3);\n }\n\n /**\n * Check if code references external variables (props, state)\n */\n private hasExternalReferences(code: string): boolean {\n const trimmed = code.trim();\n \n // Skip if empty\n if (!trimmed) return false;\n \n // Skip if it's ONLY a comment or return statement\n if (/^\\/\\/.*$/.test(trimmed) || /^return\\s*;?\\s*$/.test(trimmed)) return false;\n \n // Check for prop-like access\n if (/\\bprops\\.\\w+/.test(code)) return true;\n \n // Check for common state/prop variable names\n if (/\\b(data|items|value|user|config|settings|options|state|count|loading|error)\\b/.test(code)) return true;\n \n // Check for function calls with variable arguments (not literals)\n // e.g., fetchData(userId) but not fetchData(\"static\")\n if (/\\b\\w+\\(\\s*[a-z]\\w*\\s*\\)/.test(code) && !/\\b(console|Math|JSON|Object|Array|String|Number|Boolean)\\b/.test(code)) {\n return true;\n }\n \n return false;\n }\n\n // ---------------------------------------------------------------------------\n // State Updates in Loop\n // ---------------------------------------------------------------------------\n\n /**\n * Detects setState calls inside loops:\n * - items.forEach(item => setItems([...items, item]))\n * \n * This causes multiple re-renders instead of one.\n */\n private checkStateInLoop(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n \n // Pattern: .forEach/.map with setState inside\n const loopPattern = /\\.(forEach|map)\\s*\\([^)]*=>\\s*\\{[^}]*\\bset[A-Z]\\w*\\s*\\(/g;\n let match: RegExpExecArray | null;\n\n while ((match = loopPattern.exec(file.content)) !== null) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.HIGH,\n message: 'setState inside loop causes multiple re-renders',\n filePath: file.path,\n line: getLineNumber(file.content, match.index),\n suggestion: 'Batch state updates: collect all changes first, then call setState once.',\n learnMoreUrl: 'https://react.dev/learn/queueing-a-series-of-state-updates',\n }),\n );\n }\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // Large Component Defined in Render\n // ---------------------------------------------------------------------------\n\n /**\n * Detects components defined inside other components:\n * - function Parent() { const Child = () => <div />; return <Child /> }\n * \n * This recreates the component on every render.\n */\n private checkLargeComponentInRender(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n const lines = file.content.split('\\n');\n\n // Track if we're inside a component\n let componentDepth = 0;\n let braceDepth = 0;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const trimmedLine = line.trim();\n\n // Detect top-level component start (not indented or export)\n const isTopLevelComponent = /^(export\\s+)?(function|const)\\s+[A-Z]\\w*\\s*[=(]/.test(line);\n \n // Detect nested component (indented const/function with PascalCase)\n const isNestedComponent = /^\\s+(const|function)\\s+[A-Z]\\w*\\s*=\\s*(\\([^)]*\\)|)\\s*=>/.test(line) ||\n /^\\s+function\\s+[A-Z]\\w*\\s*\\(/.test(line);\n\n if (isTopLevelComponent) {\n componentDepth = 1;\n braceDepth = 0;\n } else if (isNestedComponent && componentDepth > 0 && braceDepth > 0) {\n // We're inside a component and found a nested component definition\n issues.push(\n this.createIssue({\n message: 'Component defined inside another component is recreated on every render',\n filePath: file.path,\n line: i + 1,\n codeSnippet: trimmedLine.slice(0, 80),\n suggestion: 'Move the component outside, or use useMemo() if it needs parent scope.',\n learnMoreUrl: 'https://react.dev/learn/your-first-component#nesting-and-organizing-components',\n }),\n );\n }\n\n // Track braces\n const opens = (line.match(/\\{/g) || []).length;\n const closes = (line.match(/\\}/g) || []).length;\n braceDepth += opens - closes;\n \n // Reset when we exit the component\n if (componentDepth > 0 && braceDepth <= 0) {\n componentDepth = 0;\n braceDepth = 0;\n }\n }\n\n return issues.slice(0, 3);\n }\n\n // ---------------------------------------------------------------------------\n // Spread Props Anti-pattern\n // ---------------------------------------------------------------------------\n\n /**\n * Detects spreading all props to child components:\n * - <Child {...props} />\n * \n * This passes unnecessary props and makes the component harder to understand.\n * Only flags when spreading the full props object, not rest props.\n */\n private checkSpreadPropsAntipattern(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n \n // Pattern: <Component {...props} /> where props is the full props object\n // Skip {...rest} or {...otherProps} which are common valid patterns\n const spreadPattern = /<\\w+[^>]*\\{\\s*\\.\\.\\.props\\s*\\}[^>]*>/g;\n let match: RegExpExecArray | null;\n\n while ((match = spreadPattern.exec(file.content)) !== null) {\n // Skip if it's spreading rest props (common valid pattern)\n const context = file.content.slice(Math.max(0, match.index - 200), match.index);\n if (/\\.\\.\\.\\s*props\\s*\\}/.test(context) || /const\\s*\\{[^}]*,\\s*\\.\\.\\.props\\s*\\}/.test(context)) {\n continue;\n }\n\n issues.push(\n this.createIssue({\n severity: SEVERITY.LOW,\n message: 'Spreading all props passes unnecessary data and obscures component API',\n filePath: file.path,\n line: getLineNumber(file.content, match.index),\n codeSnippet: match[0].slice(0, 60),\n suggestion: 'Explicitly pass only the props the child component needs.',\n learnMoreUrl: 'https://react.dev/learn/passing-props-to-a-component',\n }),\n );\n }\n\n // Limit to 2 per file\n return issues.slice(0, 2);\n }\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext, ProjectFile } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\n/**\n * RULE-021: Missing Project Standards\n *\n * Detects when a project lacks common configuration files and standards.\n *\n * WHY: AI-generated projects often skip essential setup like linting,\n * formatting, TypeScript config, and documentation. This leads to\n * inconsistent code and makes collaboration difficult.\n */\nexport class MissingProjectStandardsRule extends BaseRule {\n readonly id = RULE_ID.MISSING_PROJECT_STANDARDS;\n readonly name = 'Missing Project Standards';\n readonly description = 'Detects missing configuration files and project standards';\n readonly defaultSeverity = SEVERITY.LOW;\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n const { packageJson, projectRoot } = context;\n const issues: Issue[] = [];\n\n // Get all files in project root (including dotfiles)\n const rootFiles = this.getRootFiles(projectRoot);\n const fileNames = new Set(rootFiles.map(f => f.toLowerCase()));\n\n // Detect project type\n const projectType = this.detectProjectType(packageJson);\n\n // Check for missing standards based on project type\n issues.push(...this.checkLintingConfig(fileNames, packageJson));\n issues.push(...this.checkFormattingConfig(fileNames, packageJson));\n issues.push(...this.checkTypeScriptConfig(fileNames, packageJson, projectType));\n issues.push(...this.checkEditorConfig(fileNames));\n issues.push(...this.checkGitConfig(fileNames));\n issues.push(...this.checkDocumentation(fileNames));\n issues.push(...this.checkEnvExample(fileNames));\n\n return issues;\n }\n\n /**\n * Get all files in the project root directory\n */\n private getRootFiles(projectRoot: string): string[] {\n try {\n return fs.readdirSync(projectRoot);\n } catch {\n return [];\n }\n }\n\n /**\n * Detect the type of project based on dependencies\n */\n private detectProjectType(packageJson?: Record<string, unknown>): string {\n const deps = {\n ...(packageJson?.dependencies as Record<string, string> | undefined),\n ...(packageJson?.devDependencies as Record<string, string> | undefined),\n };\n\n if ('next' in deps) return 'nextjs';\n if ('react' in deps) return 'react';\n if ('vue' in deps) return 'vue';\n if ('angular' in deps || '@angular/core' in deps) return 'angular';\n if ('express' in deps || 'fastify' in deps || 'koa' in deps) return 'node-backend';\n if ('typescript' in deps) return 'typescript';\n return 'javascript';\n }\n\n // ---------------------------------------------------------------------------\n // Linting Configuration\n // ---------------------------------------------------------------------------\n\n private checkLintingConfig(\n fileNames: Set<string>,\n packageJson?: Record<string, unknown>,\n ): Issue[] {\n const lintConfigs = [\n '.eslintrc', '.eslintrc.js', '.eslintrc.cjs', '.eslintrc.json', '.eslintrc.yml',\n 'eslint.config.js', 'eslint.config.mjs', 'eslint.config.cjs',\n 'biome.json', 'biome.jsonc',\n '.oxlintrc.json',\n ];\n\n const hasLintConfig = lintConfigs.some(config => fileNames.has(config));\n \n // Check package.json for eslintConfig\n const hasEslintInPackage = packageJson?.eslintConfig !== undefined;\n \n // Check for lint script\n const scripts = packageJson?.scripts as Record<string, string> | undefined;\n const hasLintScript = scripts?.lint !== undefined;\n\n if (!hasLintConfig && !hasEslintInPackage) {\n return [\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: 'No linting configuration found (ESLint, Biome, or similar)',\n filePath: 'project',\n suggestion: hasLintScript \n ? 'You have a lint script but no config file. Add eslint.config.js or biome.json.'\n : 'Add ESLint: npm init @eslint/config, or Biome: npm install --save-dev @biomejs/biome',\n learnMoreUrl: 'https://eslint.org/docs/latest/use/getting-started',\n }),\n ];\n }\n\n return [];\n }\n\n // ---------------------------------------------------------------------------\n // Formatting Configuration\n // ---------------------------------------------------------------------------\n\n private checkFormattingConfig(\n fileNames: Set<string>,\n packageJson?: Record<string, unknown>,\n ): Issue[] {\n const formatConfigs = [\n '.prettierrc', '.prettierrc.js', '.prettierrc.cjs', '.prettierrc.json', \n '.prettierrc.yml', '.prettierrc.yaml', 'prettier.config.js', 'prettier.config.cjs',\n 'biome.json', 'biome.jsonc', // Biome handles formatting too\n 'dprint.json', // dprint\n ];\n\n const hasFormatConfig = formatConfigs.some(config => fileNames.has(config));\n \n // Check package.json for prettier config\n const hasPrettierInPackage = packageJson?.prettier !== undefined;\n\n // Check if using Biome (which handles formatting)\n const deps = {\n ...(packageJson?.dependencies as Record<string, string> | undefined),\n ...(packageJson?.devDependencies as Record<string, string> | undefined),\n };\n const hasBiome = '@biomejs/biome' in deps;\n\n if (!hasFormatConfig && !hasPrettierInPackage && !hasBiome) {\n return [\n this.createIssue({\n severity: SEVERITY.LOW,\n message: 'No code formatting configuration found (Prettier, Biome, or similar)',\n filePath: 'project',\n suggestion: 'Add Prettier: npm install --save-dev prettier && echo {} > .prettierrc',\n learnMoreUrl: 'https://prettier.io/docs/en/install.html',\n }),\n ];\n }\n\n return [];\n }\n\n // ---------------------------------------------------------------------------\n // TypeScript Configuration\n // ---------------------------------------------------------------------------\n\n private checkTypeScriptConfig(\n fileNames: Set<string>,\n packageJson?: Record<string, unknown>,\n projectType?: string,\n ): Issue[] {\n const deps = {\n ...(packageJson?.dependencies as Record<string, string> | undefined),\n ...(packageJson?.devDependencies as Record<string, string> | undefined),\n };\n\n // Skip if not a TypeScript project\n if (!('typescript' in deps)) return [];\n\n const hasTsConfig = fileNames.has('tsconfig.json');\n\n if (!hasTsConfig) {\n return [\n this.createIssue({\n severity: SEVERITY.HIGH,\n message: 'TypeScript installed but no tsconfig.json found',\n filePath: 'project',\n suggestion: 'Run: npx tsc --init',\n learnMoreUrl: 'https://www.typescriptlang.org/docs/handbook/tsconfig-json.html',\n }),\n ];\n }\n\n return [];\n }\n\n // ---------------------------------------------------------------------------\n // Editor Configuration\n // ---------------------------------------------------------------------------\n\n private checkEditorConfig(fileNames: Set<string>): Issue[] {\n const hasEditorConfig = fileNames.has('.editorconfig');\n\n if (!hasEditorConfig) {\n return [\n this.createIssue({\n severity: SEVERITY.LOW,\n message: 'No .editorconfig file for consistent editor settings',\n filePath: 'project',\n suggestion: 'Add .editorconfig to ensure consistent indentation and line endings across editors.',\n learnMoreUrl: 'https://editorconfig.org/',\n }),\n ];\n }\n\n return [];\n }\n\n // ---------------------------------------------------------------------------\n // Git Configuration\n // ---------------------------------------------------------------------------\n\n private checkGitConfig(fileNames: Set<string>): Issue[] {\n const issues: Issue[] = [];\n\n // Check for .gitignore\n if (!fileNames.has('.gitignore')) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: 'No .gitignore file found',\n filePath: 'project',\n suggestion: 'Add .gitignore to prevent committing node_modules, build artifacts, and secrets.',\n learnMoreUrl: 'https://git-scm.com/docs/gitignore',\n }),\n );\n }\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // Documentation\n // ---------------------------------------------------------------------------\n\n private checkDocumentation(\n fileNames: Set<string>,\n ): Issue[] {\n const readmeFiles = ['readme.md', 'readme.txt', 'readme', 'readme.markdown'];\n const hasReadme = readmeFiles.some(f => fileNames.has(f));\n\n if (!hasReadme) {\n return [\n this.createIssue({\n severity: SEVERITY.LOW,\n message: 'No README.md file found',\n filePath: 'project',\n suggestion: 'Add a README.md with project description, setup instructions, and usage examples.',\n learnMoreUrl: 'https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-readmes',\n }),\n ];\n }\n\n return [];\n }\n\n // ---------------------------------------------------------------------------\n // Environment Example\n // ---------------------------------------------------------------------------\n\n private checkEnvExample(\n fileNames: Set<string>,\n ): Issue[] {\n // Check if project uses environment variables\n const hasEnvFile = fileNames.has('.env') || \n fileNames.has('.env.local') || \n fileNames.has('.env.development');\n \n if (!hasEnvFile) return [];\n\n // Check for .env.example\n const hasEnvExample = fileNames.has('.env.example') || \n fileNames.has('.env.sample') ||\n fileNames.has('.env.template');\n\n if (!hasEnvExample) {\n return [\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: 'Project uses .env but no .env.example file for documentation',\n filePath: 'project',\n suggestion: 'Add .env.example with placeholder values so other developers know what variables are needed.',\n learnMoreUrl: 'https://www.twilio.com/blog/working-with-environment-variables-in-node-js-html',\n }),\n ];\n }\n\n return [];\n }\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext, ProjectFile } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\nimport {\n detectWebFramework,\n isWebApplication,\n isTestFile,\n getLineNumber,\n} from './analysis-helpers.js';\n\n/**\n * RULE-022: Missing Compliance Pages\n *\n * Detects web projects missing legally required pages (Terms, Privacy, Cookies)\n * or that have AI-generated legal pages with unresolved placeholders.\n * Also detects analytics without cookie consent and auth without delete account.\n *\n * WHY: The AI generates your app but not the legal infrastructure around it.\n * A vibecoder ships a SaaS with user accounts but no Terms of Service —\n * that's a legal liability. Cookie consent isn't optional in the EU.\n */\nexport class MissingComplianceRule extends BaseRule {\n readonly id = RULE_ID.MISSING_COMPLIANCE;\n readonly name = 'Missing Compliance';\n readonly description = 'Detects missing legal pages, cookie consent, and compliance issues';\n readonly defaultSeverity = SEVERITY.HIGH;\n\n // ---------------------------------------------------------------------------\n // Legal Page Patterns\n // ---------------------------------------------------------------------------\n\n private static readonly TERMS_PATTERNS = [\n /terms/i,\n /tos/i,\n /terms-of-service/i,\n /terms-and-conditions/i,\n /terminos/i,\n /condiciones/i,\n ];\n\n private static readonly PRIVACY_PATTERNS = [\n /privacy/i,\n /privacy-policy/i,\n /privacidad/i,\n /datos-personales/i,\n ];\n\n private static readonly COOKIE_PATTERNS = [\n /cookie-policy/i,\n /cookies/i,\n /cookie-notice/i,\n ];\n\n // ---------------------------------------------------------------------------\n // Placeholder Patterns (for detecting unfinished legal pages)\n // ---------------------------------------------------------------------------\n\n private static readonly PLACEHOLDER_PATTERNS: Array<{ pattern: RegExp; description: string }> = [\n // Bracketed placeholders\n { pattern: /\\[Company Name\\]/gi, description: '[Company Name]' },\n { pattern: /\\[Your Company\\]/gi, description: '[Your Company]' },\n { pattern: /\\[App Name\\]/gi, description: '[App Name]' },\n { pattern: /\\[Your App Name\\]/gi, description: '[Your App Name]' },\n { pattern: /\\[Product Name\\]/gi, description: '[Product Name]' },\n { pattern: /\\[Website URL\\]/gi, description: '[Website URL]' },\n { pattern: /\\[Contact Email\\]/gi, description: '[Contact Email]' },\n { pattern: /\\[Your Email\\]/gi, description: '[Your Email]' },\n { pattern: /\\[Your Address\\]/gi, description: '[Your Address]' },\n { pattern: /\\[Company Address\\]/gi, description: '[Company Address]' },\n { pattern: /\\[Effective Date\\]/gi, description: '[Effective Date]' },\n { pattern: /\\[Last Updated\\]/gi, description: '[Last Updated]' },\n { pattern: /\\[Insert Date\\]/gi, description: '[Insert Date]' },\n { pattern: /\\[Jurisdiction\\]/gi, description: '[Jurisdiction]' },\n { pattern: /\\[Your State\\/Country\\]/gi, description: '[Your State/Country]' },\n { pattern: /\\[Data Protection Officer\\]/gi, description: '[Data Protection Officer]' },\n // Common AI-generated dummy values\n { pattern: /\\bAcme Inc\\.?\\b/gi, description: 'Acme Inc' },\n { pattern: /\\bAcme Corp\\.?\\b/gi, description: 'Acme Corp' },\n { pattern: /\\bExample Inc\\.?\\b/gi, description: 'Example Inc' },\n { pattern: /\\bexample\\.com\\b/gi, description: 'example.com' },\n { pattern: /\\byourcompany\\.com\\b/gi, description: 'yourcompany.com' },\n { pattern: /\\byour-app\\.com\\b/gi, description: 'your-app.com' },\n { pattern: /\\bjohn@example\\.com\\b/gi, description: 'john@example.com' },\n { pattern: /\\bcontact@example\\.com\\b/gi, description: 'contact@example.com' },\n { pattern: /\\bsupport@example\\.com\\b/gi, description: 'support@example.com' },\n { pattern: /\\b123 Main Street\\b/gi, description: '123 Main Street' },\n { pattern: /\\b1234 Example Street\\b/gi, description: '1234 Example Street' },\n ];\n\n // ---------------------------------------------------------------------------\n // Analytics Detection\n // ---------------------------------------------------------------------------\n\n private static readonly ANALYTICS_PACKAGES = [\n '@google-analytics/data', 'google-analytics', 'gtag', 'ga-4',\n 'react-ga', 'react-ga4', '@segment/analytics-next', 'analytics',\n '@vercel/analytics', '@vercel/speed-insights', 'mixpanel', 'mixpanel-browser',\n 'hotjar', '@hotjar/browser', 'posthog', 'posthog-js',\n 'amplitude', '@amplitude/analytics-browser', 'plausible', '@plausible/tracker',\n 'heap', 'heap-js', 'fullstory', '@fullstory/browser', 'clarity', 'clarity-js',\n ];\n\n private static readonly ANALYTICS_CODE_PATTERNS = [\n /gtag\\s*\\(\\s*['\"`]config['\"`]/,\n /window\\.gtag/,\n /GA_TRACKING_ID/,\n /GA_MEASUREMENT_ID/,\n /G-[A-Z0-9]{10}/,\n /UA-\\d+-\\d+/,\n /googletagmanager\\.com/,\n /google-analytics\\.com/,\n /analytics\\.track\\s*\\(/,\n /analytics\\.page\\s*\\(/,\n /analytics\\.identify\\s*\\(/,\n /trackEvent\\s*\\(/,\n /trackPageView\\s*\\(/,\n /logEvent\\s*\\(/,\n ];\n\n // ---------------------------------------------------------------------------\n // Cookie Consent Detection\n // ---------------------------------------------------------------------------\n\n private static readonly COOKIE_CONSENT_PACKAGES = [\n 'cookie-consent', 'react-cookie-consent', 'cookieconsent',\n 'vanilla-cookieconsent', '@orestbida/iubenda', 'orejime',\n 'gdpr-cookie-consent', 'cookie-notice', 'tarteaucitron', 'klaro',\n ];\n\n private static readonly COOKIE_CONSENT_CODE_PATTERNS = [\n /CookieConsent/,\n /CookieBanner/,\n /cookieConsent/,\n /cookie-consent/,\n /cookie-banner/,\n /gdpr-banner/,\n /ConsentBanner/,\n /ConsentManager/,\n /CookieNotice/,\n /acceptCookies/,\n /rejectCookies/,\n /cookiePolicy/,\n /consentGiven/,\n /hasConsent/,\n /showCookieBanner/,\n /manageCookies/,\n /cookiePreferences/,\n ];\n\n // ---------------------------------------------------------------------------\n // Auth Detection\n // ---------------------------------------------------------------------------\n\n private static readonly AUTH_PACKAGES = [\n 'next-auth', '@auth/core', 'passport', '@supabase/auth-helpers-nextjs',\n '@supabase/ssr', 'firebase/auth', '@clerk/nextjs', 'clerk',\n 'auth0', '@auth0/nextjs-auth0', 'lucia', 'lucia-auth', 'better-auth', 'arctic',\n ];\n\n private static readonly AUTH_CODE_PATTERNS = [\n /signUp\\s*\\(/,\n /signup\\s*\\(/,\n /register\\s*\\(/,\n /createUser\\s*\\(/,\n /createAccount\\s*\\(/,\n /registerUser\\s*\\(/,\n /auth\\.signUp\\s*\\(/,\n /supabase\\.auth\\.signUp\\s*\\(/,\n /NextAuth\\s*\\(/,\n /AuthProvider/,\n /getServerSession\\s*\\(/,\n /useSession\\s*\\(/,\n ];\n\n private static readonly DELETE_ACCOUNT_PATTERNS = [\n /deleteAccount\\s*\\(/,\n /deleteUser\\s*\\(/,\n /removeAccount\\s*\\(/,\n /deactivateAccount\\s*\\(/,\n /\\/api\\/account\\/delete/,\n /\\/api\\/user\\/delete/,\n /auth\\.deleteUser\\s*\\(/,\n /supabase\\.auth\\.admin\\.deleteUser\\s*\\(/,\n /[\"']Delete Account[\"']/i,\n /[\"']Delete My Account[\"']/i,\n /[\"']Remove Account[\"']/i,\n /[\"']Deactivate Account[\"']/i,\n /[\"']Eliminar cuenta[\"']/i,\n /[\"']Borrar cuenta[\"']/i,\n /deleteAccountModal/i,\n /DeleteAccountButton/i,\n ];\n\n // ---------------------------------------------------------------------------\n // Main Analysis\n // ---------------------------------------------------------------------------\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n // Skip non-web applications\n if (!isWebApplication(context)) {\n return [];\n }\n\n const issues: Issue[] = [];\n const { files, packageJson } = context;\n\n // Filter out test files\n const sourceFiles = files.filter(f => !isTestFile(f.path));\n\n // 022-A: Check for missing legal pages\n issues.push(...this.checkMissingLegalPages(sourceFiles));\n\n // 022-B: Check for placeholder content in legal pages\n issues.push(...this.checkLegalPlaceholders(sourceFiles));\n\n // 022-C: Check for analytics without cookie consent\n issues.push(...this.checkAnalyticsConsent(sourceFiles, packageJson));\n\n // 022-D: Check for auth without delete account\n issues.push(...this.checkAuthDeleteAccount(sourceFiles, packageJson));\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // 022-A: Missing Legal Pages\n // ---------------------------------------------------------------------------\n\n private checkMissingLegalPages(files: readonly ProjectFile[]): Issue[] {\n const issues: Issue[] = [];\n\n const hasTerms = this.hasLegalPage(files, MissingComplianceRule.TERMS_PATTERNS);\n const hasPrivacy = this.hasLegalPage(files, MissingComplianceRule.PRIVACY_PATTERNS);\n\n if (!hasTerms) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.HIGH,\n message: 'Missing Terms of Service page',\n filePath: 'project',\n suggestion: [\n 'Create a Terms of Service page at /terms or /legal/terms.',\n 'Any app with user accounts or payments legally requires one.',\n 'Consider using a legal template service or consulting a lawyer.',\n ].join('\\n'),\n learnMoreUrl: 'https://termly.io/resources/articles/terms-of-service/',\n }),\n );\n }\n\n if (!hasPrivacy) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.HIGH,\n message: 'Missing Privacy Policy page',\n filePath: 'project',\n suggestion: [\n 'Create a Privacy Policy page at /privacy or /legal/privacy.',\n 'GDPR, CCPA, and most jurisdictions require one for any app that collects user data.',\n 'Even basic analytics or contact forms require a privacy policy.',\n ].join('\\n'),\n learnMoreUrl: 'https://gdpr.eu/privacy-notice/',\n }),\n );\n }\n\n return issues;\n }\n\n private hasLegalPage(files: readonly ProjectFile[], patterns: RegExp[]): boolean {\n for (const file of files) {\n // Check file path\n for (const pattern of patterns) {\n if (pattern.test(file.path)) return true;\n }\n\n // Check for links to legal pages in content\n for (const pattern of patterns) {\n const hrefPattern = new RegExp(`href=[\"']/[^\"']*${pattern.source}`, 'i');\n const toPattern = new RegExp(`to=[\"']/[^\"']*${pattern.source}`, 'i');\n if (hrefPattern.test(file.content) || toPattern.test(file.content)) {\n return true;\n }\n }\n }\n\n return false;\n }\n\n // ---------------------------------------------------------------------------\n // 022-B: Legal Placeholders\n // ---------------------------------------------------------------------------\n\n private checkLegalPlaceholders(files: readonly ProjectFile[]): Issue[] {\n const issues: Issue[] = [];\n\n // Find legal page files\n const legalFiles = files.filter(f => this.isLegalFile(f.path));\n\n for (const file of legalFiles) {\n const placeholders: string[] = [];\n\n for (const { pattern, description } of MissingComplianceRule.PLACEHOLDER_PATTERNS) {\n if (pattern.test(file.content)) {\n placeholders.push(description);\n }\n }\n\n if (placeholders.length > 0) {\n const displayPlaceholders = placeholders.slice(0, 5);\n const moreCount = placeholders.length - 5;\n\n issues.push(\n this.createIssue({\n severity: SEVERITY.CRITICAL,\n message: `Legal page has ${placeholders.length} unresolved placeholder(s)`,\n filePath: file.path,\n suggestion: [\n `Found: ${displayPlaceholders.join(', ')}${moreCount > 0 ? ` and ${moreCount} more` : ''}`,\n '',\n 'Publishing legal pages with placeholders is worse than having none.',\n 'It signals negligence if there\\'s ever a legal dispute.',\n 'Replace all placeholders with your actual company information.',\n ].join('\\n'),\n learnMoreUrl: 'https://termly.io/resources/articles/terms-of-service/',\n }),\n );\n }\n }\n\n return issues;\n }\n\n private isLegalFile(filePath: string): boolean {\n const allPatterns = [\n ...MissingComplianceRule.TERMS_PATTERNS,\n ...MissingComplianceRule.PRIVACY_PATTERNS,\n ...MissingComplianceRule.COOKIE_PATTERNS,\n /legal/i,\n ];\n\n return allPatterns.some(p => p.test(filePath));\n }\n\n // ---------------------------------------------------------------------------\n // 022-C: Analytics Without Cookie Consent\n // ---------------------------------------------------------------------------\n\n private checkAnalyticsConsent(\n files: readonly ProjectFile[],\n packageJson: import('@vibertest/shared').PackageJson | null,\n ): Issue[] {\n const hasAnalytics = this.detectAnalytics(files, packageJson);\n const hasCookieConsent = this.detectCookieConsent(files, packageJson);\n\n if (hasAnalytics && !hasCookieConsent) {\n return [\n this.createIssue({\n severity: SEVERITY.HIGH,\n message: 'Analytics detected without cookie consent implementation',\n filePath: 'project',\n suggestion: [\n 'GDPR and ePrivacy Directive require informed consent before setting non-essential cookies.',\n 'Implement a cookie consent banner using a library like:',\n ' - react-cookie-consent',\n ' - vanilla-cookieconsent',\n ' - klaro',\n '',\n 'Users must be able to accept or reject analytics cookies.',\n ].join('\\n'),\n learnMoreUrl: 'https://gdpr.eu/cookies/',\n }),\n ];\n }\n\n return [];\n }\n\n private detectAnalytics(\n files: readonly ProjectFile[],\n packageJson: import('@vibertest/shared').PackageJson | null,\n ): boolean {\n // Check package.json\n if (packageJson) {\n const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };\n for (const pkg of MissingComplianceRule.ANALYTICS_PACKAGES) {\n if (pkg in deps) return true;\n }\n }\n\n // Check source files\n for (const file of files) {\n for (const pattern of MissingComplianceRule.ANALYTICS_CODE_PATTERNS) {\n if (pattern.test(file.content)) return true;\n }\n }\n\n return false;\n }\n\n private detectCookieConsent(\n files: readonly ProjectFile[],\n packageJson: import('@vibertest/shared').PackageJson | null,\n ): boolean {\n // Check package.json\n if (packageJson) {\n const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };\n for (const pkg of MissingComplianceRule.COOKIE_CONSENT_PACKAGES) {\n if (pkg in deps) return true;\n }\n }\n\n // Check source files\n for (const file of files) {\n for (const pattern of MissingComplianceRule.COOKIE_CONSENT_CODE_PATTERNS) {\n if (pattern.test(file.content)) return true;\n }\n }\n\n // Check for cookie policy page (indicates awareness)\n const hasCookiePage = files.some(f =>\n MissingComplianceRule.COOKIE_PATTERNS.some(p => p.test(f.path)),\n );\n\n return hasCookiePage;\n }\n\n // ---------------------------------------------------------------------------\n // 022-D: Auth Without Delete Account\n // ---------------------------------------------------------------------------\n\n private checkAuthDeleteAccount(\n files: readonly ProjectFile[],\n packageJson: import('@vibertest/shared').PackageJson | null,\n ): Issue[] {\n const hasAuth = this.detectAuth(files, packageJson);\n const hasDeleteAccount = this.detectDeleteAccount(files);\n\n if (hasAuth && !hasDeleteAccount) {\n return [\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: 'User authentication detected without account deletion mechanism',\n filePath: 'project',\n suggestion: [\n 'GDPR Article 17 (Right to Erasure) requires users to be able to delete their accounts.',\n 'Various consumer protection laws also mandate this capability.',\n '',\n 'Add:',\n ' 1. A delete account API endpoint',\n ' 2. A \"Delete Account\" option in user settings',\n ' 3. Proper data cleanup when accounts are deleted',\n ].join('\\n'),\n learnMoreUrl: 'https://gdpr.eu/right-to-be-forgotten/',\n }),\n ];\n }\n\n return [];\n }\n\n private detectAuth(\n files: readonly ProjectFile[],\n packageJson: import('@vibertest/shared').PackageJson | null,\n ): boolean {\n // Check package.json\n if (packageJson) {\n const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };\n for (const pkg of MissingComplianceRule.AUTH_PACKAGES) {\n if (pkg in deps) return true;\n }\n }\n\n // Check source files\n for (const file of files) {\n for (const pattern of MissingComplianceRule.AUTH_CODE_PATTERNS) {\n if (pattern.test(file.content)) return true;\n }\n }\n\n return false;\n }\n\n private detectDeleteAccount(files: readonly ProjectFile[]): boolean {\n for (const file of files) {\n for (const pattern of MissingComplianceRule.DELETE_ACCOUNT_PATTERNS) {\n if (pattern.test(file.content)) return true;\n }\n }\n\n return false;\n }\n}\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext, ProjectFile } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\nimport {\n isWebApplication,\n isTestFile,\n isStoryFile,\n getLineNumber,\n getLayoutFiles,\n} from './analysis-helpers.js';\n\n/**\n * RULE-023: Accessibility Anti-Patterns\n *\n * Detects HTML and JSX patterns that make the application inaccessible\n * to users with disabilities. AI-generated UI code consistently produces\n * visually functional but semantically broken markup.\n *\n * WHY: Every <div onClick> is a button that keyboard users can't reach.\n * Every <img> without alt text is invisible content. Beyond being the\n * right thing to do, accessibility violations create legal liability.\n */\nexport class AccessibilityRule extends BaseRule {\n readonly id = RULE_ID.ACCESSIBILITY;\n readonly name = 'Accessibility';\n readonly description = 'Detects accessibility anti-patterns in HTML/JSX';\n readonly defaultSeverity = SEVERITY.MEDIUM;\n\n // ---------------------------------------------------------------------------\n // Placeholder Alt Text Patterns\n // ---------------------------------------------------------------------------\n\n private static readonly PLACEHOLDER_ALT_TEXTS = new Set([\n 'image', 'photo', 'picture', 'img', 'icon', 'placeholder',\n 'alt text', 'description', 'untitled', 'alt', 'logo', 'banner',\n ]);\n\n // ---------------------------------------------------------------------------\n // Non-Interactive Elements\n // ---------------------------------------------------------------------------\n\n private static readonly NON_INTERACTIVE_ELEMENTS = new Set([\n 'div', 'span', 'li', 'td', 'section', 'article', 'header',\n 'footer', 'main', 'aside', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\n ]);\n\n // ---------------------------------------------------------------------------\n // Generic Link Text\n // ---------------------------------------------------------------------------\n\n private static readonly GENERIC_LINK_TEXTS = new Set([\n 'click here', 'here', 'link', 'read more', 'learn more', 'more',\n 'this', 'page', 'this page', 'click', 'go', 'see more', 'view more',\n ]);\n\n // ---------------------------------------------------------------------------\n // Main Analysis\n // ---------------------------------------------------------------------------\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n // Skip non-web applications\n if (!isWebApplication(context)) {\n return [];\n }\n\n const issues: Issue[] = [];\n const { files } = context;\n\n // Filter to JSX/TSX/HTML files, excluding tests and stories\n const uiFiles = files.filter(f =>\n /\\.[jt]sx?$/.test(f.extension) &&\n !isTestFile(f.path) &&\n !isStoryFile(f.path),\n );\n\n for (const file of uiFiles) {\n // 023-A: Images without alt text\n issues.push(...this.checkImagesWithoutAlt(file));\n\n // 023-B: Non-semantic click handlers\n issues.push(...this.checkNonSemanticClickHandlers(file));\n\n // 023-C: Form inputs without labels\n issues.push(...this.checkInputsWithoutLabels(file));\n\n // 023-E: Non-descriptive link text\n issues.push(...this.checkGenericLinkText(file));\n }\n\n // 023-D: Missing ARIA landmarks (project-level check)\n const layoutFiles = getLayoutFiles(context);\n issues.push(...this.checkMissingLandmarks(layoutFiles));\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // 023-A: Images Without Alt Text\n // ---------------------------------------------------------------------------\n\n private checkImagesWithoutAlt(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n\n // Match <img> and <Image> tags\n const imgPattern = /<(?:img|Image)\\s+([^>]*?)(?:\\/>|>)/gi;\n let match: RegExpExecArray | null;\n\n while ((match = imgPattern.exec(file.content)) !== null) {\n const attributes = match[1] ?? '';\n const line = getLineNumber(file.content, match.index);\n\n // Check for alt attribute\n const altMatch = attributes.match(/alt\\s*=\\s*[\"']([^\"']*)[\"']/i);\n const hasRole = /role\\s*=\\s*[\"'](?:presentation|none)[\"']/i.test(attributes);\n const hasAriaHidden = /aria-hidden\\s*=\\s*[\"']true[\"']/i.test(attributes);\n\n // Skip decorative images (properly marked)\n if (hasRole || hasAriaHidden) continue;\n\n if (!altMatch) {\n // No alt attribute at all\n issues.push(\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: 'Image missing alt attribute',\n filePath: file.path,\n line,\n codeSnippet: match[0].slice(0, 60),\n suggestion: [\n 'Add descriptive alt text that conveys the image\\'s purpose.',\n 'For decorative images, use alt=\"\" with role=\"presentation\".',\n 'Screen readers cannot describe images without alt text.',\n ].join('\\n'),\n learnMoreUrl: 'https://www.w3.org/WAI/tutorials/images/',\n }),\n );\n } else {\n const altText = altMatch[1]?.toLowerCase().trim() ?? '';\n\n // Check for empty alt on content images\n if (altText === '' && !hasRole) {\n // Check if it looks decorative based on src\n const srcMatch = attributes.match(/src\\s*=\\s*[\"']([^\"']*)[\"']/i);\n const src = srcMatch?.[1]?.toLowerCase() ?? '';\n const looksDecorative = /(?:icon|divider|spacer|bg|background|pattern)/.test(src);\n\n if (!looksDecorative) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.LOW,\n message: 'Image has empty alt text but may not be decorative',\n filePath: file.path,\n line,\n codeSnippet: match[0].slice(0, 60),\n suggestion: [\n 'If this is a decorative image, add role=\"presentation\".',\n 'If it conveys content, add descriptive alt text.',\n ].join('\\n'),\n learnMoreUrl: 'https://www.w3.org/WAI/tutorials/images/decorative/',\n }),\n );\n }\n }\n\n // Check for placeholder alt text\n if (MissingComplianceRule.PLACEHOLDER_ALT_TEXTS.has(altText)) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: `Image has placeholder alt text: \"${altText}\"`,\n filePath: file.path,\n line,\n codeSnippet: match[0].slice(0, 60),\n suggestion: [\n 'Replace with descriptive text that explains the image\\'s content or purpose.',\n 'Good alt text: \"Team photo at the 2024 company retreat\"',\n 'Bad alt text: \"image\", \"photo\", \"picture\"',\n ].join('\\n'),\n learnMoreUrl: 'https://www.w3.org/WAI/tutorials/images/',\n }),\n );\n }\n }\n }\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // 023-B: Non-Semantic Click Handlers\n // ---------------------------------------------------------------------------\n\n private checkNonSemanticClickHandlers(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n\n // Match elements with onClick\n const onClickPattern = /<(\\w+)\\s+([^>]*onClick[^>]*)>/gi;\n let match: RegExpExecArray | null;\n\n while ((match = onClickPattern.exec(file.content)) !== null) {\n const tagName = match[1]?.toLowerCase() ?? '';\n const attributes = match[2] ?? '';\n const line = getLineNumber(file.content, match.index);\n\n // Skip interactive elements\n if (!AccessibilityRule.NON_INTERACTIVE_ELEMENTS.has(tagName)) continue;\n\n // Check for compensating ARIA attributes\n const hasRole = /role\\s*=\\s*[\"'](?:button|link)[\"']/i.test(attributes);\n const hasTabIndex = /tabIndex\\s*=\\s*\\{?\\s*0\\s*\\}?/i.test(attributes);\n\n if (!hasRole || !hasTabIndex) {\n // Table rows are a common pattern, reduce severity\n const severity = tagName === 'tr' ? SEVERITY.LOW : SEVERITY.MEDIUM;\n\n issues.push(\n this.createIssue({\n severity,\n message: `Non-semantic <${tagName}> with onClick handler`,\n filePath: file.path,\n line,\n codeSnippet: match[0].slice(0, 60),\n suggestion: [\n `Use <button> or <a> instead of <${tagName}> for interactive elements.`,\n 'If you must use a non-semantic element, add:',\n ' role=\"button\" tabIndex={0} onKeyDown={handleKeyDown}',\n '',\n 'Non-semantic elements are invisible to keyboard users and screen readers.',\n ].join('\\n'),\n learnMoreUrl: 'https://www.w3.org/WAI/ARIA/apg/patterns/button/',\n }),\n );\n }\n }\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // 023-C: Form Inputs Without Labels\n // ---------------------------------------------------------------------------\n\n private checkInputsWithoutLabels(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n\n // Match input, select, textarea elements\n const inputPattern = /<(input|select|textarea)\\s+([^>]*)(?:\\/>|>)/gi;\n let match: RegExpExecArray | null;\n\n // Collect all label htmlFor values in the file\n const labelForPattern = /<label[^>]*htmlFor\\s*=\\s*[\"']([^\"']+)[\"']/gi;\n const labelForIds = new Set<string>();\n let labelMatch: RegExpExecArray | null;\n while ((labelMatch = labelForPattern.exec(file.content)) !== null) {\n labelForIds.add(labelMatch[1] ?? '');\n }\n\n // Reset regex\n inputPattern.lastIndex = 0;\n\n while ((match = inputPattern.exec(file.content)) !== null) {\n const tagName = match[1]?.toLowerCase() ?? '';\n const attributes = match[2] ?? '';\n const line = getLineNumber(file.content, match.index);\n\n // Skip hidden inputs and submit buttons\n if (/type\\s*=\\s*[\"']hidden[\"']/i.test(attributes)) continue;\n if (/type\\s*=\\s*[\"']submit[\"']/i.test(attributes)) continue;\n\n // Check for various labeling methods\n const hasAriaLabel = /aria-label\\s*=\\s*[\"'][^\"']+[\"']/i.test(attributes);\n const hasAriaLabelledBy = /aria-labelledby\\s*=\\s*[\"'][^\"']+[\"']/i.test(attributes);\n\n // Check for id that matches a label's htmlFor\n const idMatch = attributes.match(/(?:^|\\s)id\\s*=\\s*[\"']([^\"']+)[\"']/i);\n const inputId = idMatch?.[1] ?? '';\n const hasMatchingLabel = inputId && labelForIds.has(inputId);\n\n // Check if wrapped in a label (heuristic: look for <label> before on same line or previous lines)\n const beforeMatch = file.content.slice(Math.max(0, match.index - 200), match.index);\n const isWrappedInLabel = /<label[^>]*>\\s*[^<]*$/.test(beforeMatch);\n\n if (!hasAriaLabel && !hasAriaLabelledBy && !hasMatchingLabel && !isWrappedInLabel) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: `<${tagName}> without associated label`,\n filePath: file.path,\n line,\n codeSnippet: match[0].slice(0, 60),\n suggestion: [\n 'Add a label using one of these methods:',\n ' 1. Wrap in <label>: <label>Name <input /></label>',\n ' 2. Use htmlFor: <label htmlFor=\"name\">Name</label><input id=\"name\" />',\n ' 3. Use aria-label: <input aria-label=\"Search query\" />',\n '',\n 'Placeholder text is NOT a substitute for a label.',\n ].join('\\n'),\n learnMoreUrl: 'https://www.w3.org/WAI/tutorials/forms/labels/',\n }),\n );\n }\n }\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // 023-D: Missing ARIA Landmarks\n // ---------------------------------------------------------------------------\n\n private checkMissingLandmarks(layoutFiles: readonly ProjectFile[]): Issue[] {\n if (layoutFiles.length === 0) return [];\n\n let hasMain = false;\n let hasNav = false;\n\n for (const file of layoutFiles) {\n if (/<main[\\s>]/i.test(file.content) || /role\\s*=\\s*[\"']main[\"']/i.test(file.content)) {\n hasMain = true;\n }\n if (/<nav[\\s>]/i.test(file.content) || /role\\s*=\\s*[\"']navigation[\"']/i.test(file.content)) {\n hasNav = true;\n }\n }\n\n const issues: Issue[] = [];\n\n if (!hasMain && !hasNav) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.LOW,\n message: 'No ARIA landmarks found in layout files',\n filePath: 'project',\n suggestion: [\n 'Use semantic HTML5 elements to define page structure:',\n ' <main> - Main content area',\n ' <nav> - Navigation sections',\n ' <header> - Page or section headers',\n ' <footer> - Page or section footers',\n '',\n 'Landmarks help screen reader users navigate the page structure.',\n ].join('\\n'),\n learnMoreUrl: 'https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/',\n }),\n );\n }\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // 023-E: Non-Descriptive Link Text\n // ---------------------------------------------------------------------------\n\n private checkGenericLinkText(file: ProjectFile): Issue[] {\n const issues: Issue[] = [];\n\n // Match <a> and <Link> elements with text content\n const linkPattern = /<(?:a|Link)\\s+([^>]*)>([^<]+)<\\/(?:a|Link)>/gi;\n let match: RegExpExecArray | null;\n\n while ((match = linkPattern.exec(file.content)) !== null) {\n const attributes = match[1] ?? '';\n const linkText = match[2]?.trim().toLowerCase() ?? '';\n const line = getLineNumber(file.content, match.index);\n\n // Skip if has aria-label\n if (/aria-label\\s*=\\s*[\"'][^\"']+[\"']/i.test(attributes)) continue;\n\n if (AccessibilityRule.GENERIC_LINK_TEXTS.has(linkText)) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.LOW,\n message: `Non-descriptive link text: \"${linkText}\"`,\n filePath: file.path,\n line,\n codeSnippet: match[0].slice(0, 60),\n suggestion: [\n 'Use descriptive text that makes sense out of context.',\n 'Screen reader users often navigate by listing all links.',\n '',\n 'Bad: <a href=\"/pricing\">click here</a>',\n 'Good: <a href=\"/pricing\">View pricing plans</a>',\n ].join('\\n'),\n learnMoreUrl: 'https://www.w3.org/WAI/WCAG21/Understanding/link-purpose-in-context.html',\n }),\n );\n }\n }\n\n return issues;\n }\n}\n\n// Helper reference for placeholder alt texts (used in checkImagesWithoutAlt)\nconst MissingComplianceRule = {\n PLACEHOLDER_ALT_TEXTS: AccessibilityRule['PLACEHOLDER_ALT_TEXTS'],\n};\n","import { RULE_ID, SEVERITY } from '@vibertest/shared';\nimport type { Issue, RuleContext, ProjectFile } from '@vibertest/shared';\nimport { BaseRule } from './base-rule.js';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport {\n detectWebFramework,\n isWebApplication,\n isTestFile,\n getLayoutFiles,\n type WebFramework,\n} from './analysis-helpers.js';\n\n/**\n * RULE-024: Missing Production Basics\n *\n * Detects web projects missing fundamental production-readiness elements:\n * favicon, meta description, Open Graph tags, 404 page, robots.txt, etc.\n *\n * WHY: The AI generates the app but not the infrastructure around it.\n * The favicon is the Vercel triangle, the title says \"Create Next App\",\n * shared links show no preview. These make the project look amateur.\n */\nexport class MissingProductionBasicsRule extends BaseRule {\n readonly id = RULE_ID.MISSING_PRODUCTION_BASICS;\n readonly name = 'Missing Production Basics';\n readonly description = 'Detects missing favicon, meta tags, 404 page, and other production basics';\n readonly defaultSeverity = SEVERITY.MEDIUM;\n\n // ---------------------------------------------------------------------------\n // Known Framework Defaults\n // ---------------------------------------------------------------------------\n\n private static readonly DEFAULT_TITLES = new Set([\n 'create next app',\n 'create react app',\n 'vite + react',\n 'vite + react + ts',\n 'vite + vue',\n 'vite + svelte',\n 'vite app',\n 'react app',\n 'vue app',\n 'svelte app',\n 'next.js app',\n 'nuxt app',\n 'my app',\n 'my application',\n 'app',\n 'home',\n 'index',\n 'page',\n 'untitled',\n 'document',\n 'welcome to react',\n 'welcome to next.js',\n ]);\n\n private static readonly DEFAULT_DESCRIPTIONS = new Set([\n 'generated by create next app',\n 'generated by create react app',\n 'vite + react',\n 'vite app',\n 'nuxt 3 minimal starter',\n 'sveltekit demo app',\n 'welcome to astro',\n 'web site created using create-react-app',\n ]);\n\n // Known favicon file sizes for framework defaults (approximate)\n private static readonly DEFAULT_FAVICON_SIZES: Record<string, number[]> = {\n 'nextjs': [15406, 15000, 16000], // Vercel triangle\n 'cra': [3870, 3800, 4000], // React logo\n 'vite': [4286, 4200, 4400], // Vite logo\n 'astro': [4535, 4500, 4600], // Astro logo\n 'sveltekit': [1497, 1400, 1600], // Svelte logo\n };\n\n // ---------------------------------------------------------------------------\n // Main Analysis\n // ---------------------------------------------------------------------------\n\n protected async analyze(context: RuleContext): Promise<readonly Issue[]> {\n // Skip non-web applications\n if (!isWebApplication(context)) {\n return [];\n }\n\n const issues: Issue[] = [];\n const { files, projectRoot } = context;\n const framework = detectWebFramework(context);\n\n // 024-A: Check favicon\n issues.push(...this.checkFavicon(files, projectRoot, framework));\n\n // 024-B: Check meta description\n issues.push(...this.checkMetaDescription(context));\n\n // 024-C: Check Open Graph tags\n issues.push(...this.checkOpenGraphTags(context));\n\n // 024-D: Check page title\n issues.push(...this.checkPageTitle(context));\n\n // 024-E: Check 404 page\n issues.push(...this.checkNotFoundPage(files, framework));\n\n // 024-F: Check robots.txt and sitemap.xml\n issues.push(...this.checkRobotsAndSitemap(files, projectRoot, context.packageJson));\n\n // 024-G: Check .env.example (already covered by RULE-021, skip here)\n\n return issues;\n }\n\n // ---------------------------------------------------------------------------\n // 024-A: Favicon Check\n // ---------------------------------------------------------------------------\n\n private checkFavicon(\n files: readonly ProjectFile[],\n projectRoot: string,\n framework: WebFramework,\n ): Issue[] {\n const faviconPaths = [\n 'public/favicon.ico',\n 'public/favicon.svg',\n 'app/favicon.ico',\n 'src/favicon.ico',\n 'static/favicon.ico',\n 'assets/favicon.ico',\n ];\n\n // Check if any favicon exists\n let faviconFound = false;\n let faviconPath = '';\n\n for (const fp of faviconPaths) {\n const fullPath = path.join(projectRoot, fp);\n if (fs.existsSync(fullPath)) {\n faviconFound = true;\n faviconPath = fullPath;\n break;\n }\n }\n\n // Also check in files array\n if (!faviconFound) {\n const faviconFile = files.find(f =>\n /favicon\\.(ico|svg|png)$/.test(f.path),\n );\n if (faviconFile) {\n faviconFound = true;\n }\n }\n\n if (!faviconFound) {\n return [\n this.createIssue({\n severity: SEVERITY.LOW,\n message: 'No favicon found',\n filePath: 'project',\n suggestion: [\n 'Add a custom favicon to public/favicon.ico or public/favicon.svg.',\n 'A favicon helps users identify your site in browser tabs and bookmarks.',\n '',\n 'Generate one at: https://favicon.io/ or https://realfavicongenerator.net/',\n ].join('\\n'),\n learnMoreUrl: 'https://web.dev/add-manifest/#icons',\n }),\n ];\n }\n\n // Check if it's a framework default\n if (faviconPath) {\n try {\n const stats = fs.statSync(faviconPath);\n const size = stats.size;\n\n // Check against known default sizes\n for (const [fw, sizes] of Object.entries(MissingProductionBasicsRule.DEFAULT_FAVICON_SIZES)) {\n if (sizes.some(s => Math.abs(size - s) < 500)) {\n return [\n this.createIssue({\n severity: SEVERITY.LOW,\n message: `Default framework favicon detected (${fw})`,\n filePath: faviconPath.replace(projectRoot + '/', ''),\n suggestion: [\n 'Replace the default favicon with your own branding.',\n 'The current favicon is the framework\\'s default logo.',\n '',\n 'Generate a custom favicon at: https://favicon.io/',\n ].join('\\n'),\n learnMoreUrl: 'https://web.dev/add-manifest/#icons',\n }),\n ];\n }\n }\n } catch {\n // Ignore stat errors\n }\n }\n\n return [];\n }\n\n // ---------------------------------------------------------------------------\n // 024-B: Meta Description Check\n // ---------------------------------------------------------------------------\n\n private checkMetaDescription(context: RuleContext): Issue[] {\n const layoutFiles = getLayoutFiles(context);\n const { files } = context;\n\n // Check for meta description in layout files\n for (const file of layoutFiles) {\n // HTML meta tag\n if (/<meta\\s+name\\s*=\\s*[\"']description[\"'][^>]*content\\s*=\\s*[\"']([^\"']+)[\"']/i.test(file.content)) {\n const match = file.content.match(/<meta\\s+name\\s*=\\s*[\"']description[\"'][^>]*content\\s*=\\s*[\"']([^\"']+)[\"']/i);\n const description = match?.[1]?.toLowerCase() ?? '';\n\n if (MissingProductionBasicsRule.DEFAULT_DESCRIPTIONS.has(description)) {\n return [\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: 'Default framework meta description detected',\n filePath: file.path,\n suggestion: [\n 'Replace the default description with a unique one for your project.',\n 'Meta descriptions affect search engine click-through rates.',\n 'Aim for 150-160 characters that describe your app\\'s value.',\n ].join('\\n'),\n learnMoreUrl: 'https://web.dev/meta-description/',\n }),\n ];\n }\n\n return []; // Has custom description\n }\n\n // Next.js metadata export\n if (/export\\s+const\\s+metadata[^=]*=\\s*\\{[\\s\\S]*description\\s*:/i.test(file.content)) {\n const match = file.content.match(/description\\s*:\\s*[\"']([^\"']+)[\"']/i);\n const description = match?.[1]?.toLowerCase() ?? '';\n\n if (MissingProductionBasicsRule.DEFAULT_DESCRIPTIONS.has(description)) {\n return [\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: 'Default framework meta description detected',\n filePath: file.path,\n suggestion: 'Replace the default description with a unique one for your project.',\n learnMoreUrl: 'https://web.dev/meta-description/',\n }),\n ];\n }\n\n return []; // Has custom description\n }\n\n // Next.js generateMetadata function\n if (/export\\s+(?:async\\s+)?function\\s+generateMetadata/i.test(file.content)) {\n return []; // Dynamic metadata, assume it's handled\n }\n }\n\n // Check index.html for SPAs\n const indexHtml = files.find(f => f.path === 'index.html' || f.path === 'public/index.html');\n if (indexHtml) {\n if (/<meta\\s+name\\s*=\\s*[\"']description[\"']/i.test(indexHtml.content)) {\n return []; // Has description\n }\n }\n\n return [\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: 'No meta description found',\n filePath: 'project',\n suggestion: [\n 'Add a meta description to your root layout or index.html.',\n 'Meta descriptions affect how your site appears in search results.',\n '',\n 'Next.js: export const metadata = { description: \"...\" }',\n 'HTML: <meta name=\"description\" content=\"...\" />',\n ].join('\\n'),\n learnMoreUrl: 'https://web.dev/meta-description/',\n }),\n ];\n }\n\n // ---------------------------------------------------------------------------\n // 024-C: Open Graph Tags Check\n // ---------------------------------------------------------------------------\n\n private checkOpenGraphTags(context: RuleContext): Issue[] {\n const layoutFiles = getLayoutFiles(context);\n const { files } = context;\n\n // Check for OG tags in layout files\n for (const file of layoutFiles) {\n // HTML OG meta tags\n if (/<meta\\s+property\\s*=\\s*[\"']og:/i.test(file.content)) {\n return []; // Has OG tags\n }\n\n // Next.js openGraph in metadata\n if (/openGraph\\s*:/i.test(file.content)) {\n return []; // Has OG config\n }\n }\n\n // Check index.html for SPAs\n const indexHtml = files.find(f => f.path === 'index.html' || f.path === 'public/index.html');\n if (indexHtml && /<meta\\s+property\\s*=\\s*[\"']og:/i.test(indexHtml.content)) {\n return []; // Has OG tags\n }\n\n return [\n this.createIssue({\n severity: SEVERITY.LOW,\n message: 'No Open Graph tags found',\n filePath: 'project',\n suggestion: [\n 'Add Open Graph meta tags for better social media sharing.',\n 'Without OG tags, shared links show generic previews with no image.',\n '',\n 'Add at minimum: og:title, og:description, og:image',\n '',\n 'Next.js: export const metadata = { openGraph: { ... } }',\n 'HTML: <meta property=\"og:title\" content=\"...\" />',\n ].join('\\n'),\n learnMoreUrl: 'https://ogp.me/',\n }),\n ];\n }\n\n // ---------------------------------------------------------------------------\n // 024-D: Page Title Check\n // ---------------------------------------------------------------------------\n\n private checkPageTitle(context: RuleContext): Issue[] {\n const layoutFiles = getLayoutFiles(context);\n const { files } = context;\n\n // Check for title in layout files\n for (const file of layoutFiles) {\n // HTML title tag\n const titleMatch = file.content.match(/<title>([^<]+)<\\/title>/i);\n if (titleMatch) {\n const title = titleMatch[1]?.toLowerCase().trim() ?? '';\n if (MissingProductionBasicsRule.DEFAULT_TITLES.has(title)) {\n return [\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: `Generic page title: \"${titleMatch[1]}\"`,\n filePath: file.path,\n suggestion: [\n 'Replace the default title with your project\\'s actual name.',\n 'The page title appears in browser tabs and search results.',\n ].join('\\n'),\n learnMoreUrl: 'https://web.dev/title/',\n }),\n ];\n }\n return []; // Has custom title\n }\n\n // Next.js metadata title\n const metadataMatch = file.content.match(/title\\s*:\\s*[\"']([^\"']+)[\"']/i);\n if (metadataMatch) {\n const title = metadataMatch[1]?.toLowerCase().trim() ?? '';\n if (MissingProductionBasicsRule.DEFAULT_TITLES.has(title)) {\n return [\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: `Generic page title: \"${metadataMatch[1]}\"`,\n filePath: file.path,\n suggestion: 'Replace the default title with your project\\'s actual name.',\n learnMoreUrl: 'https://web.dev/title/',\n }),\n ];\n }\n return []; // Has custom title\n }\n }\n\n // Check index.html for SPAs\n const indexHtml = files.find(f => f.path === 'index.html' || f.path === 'public/index.html');\n if (indexHtml) {\n const titleMatch = indexHtml.content.match(/<title>([^<]+)<\\/title>/i);\n if (titleMatch) {\n const title = titleMatch[1]?.toLowerCase().trim() ?? '';\n if (MissingProductionBasicsRule.DEFAULT_TITLES.has(title)) {\n return [\n this.createIssue({\n severity: SEVERITY.MEDIUM,\n message: `Generic page title: \"${titleMatch[1]}\"`,\n filePath: indexHtml.path,\n suggestion: 'Replace the default title with your project\\'s actual name.',\n learnMoreUrl: 'https://web.dev/title/',\n }),\n ];\n }\n return []; // Has custom title\n }\n }\n\n return [];\n }\n\n // ---------------------------------------------------------------------------\n // 024-E: 404 Page Check\n // ---------------------------------------------------------------------------\n\n private checkNotFoundPage(files: readonly ProjectFile[], framework: WebFramework): Issue[] {\n const notFoundPatterns: Record<WebFramework, RegExp[]> = {\n 'nextjs-app': [/^app\\/not-found\\.[jt]sx?$/, /^src\\/app\\/not-found\\.[jt]sx?$/],\n 'nextjs-pages': [/^pages\\/404\\.[jt]sx?$/, /^src\\/pages\\/404\\.[jt]sx?$/],\n 'remix': [/^app\\/routes\\/\\$\\.[jt]sx?$/],\n 'sveltekit': [/^src\\/routes\\/\\+error\\.svelte$/],\n 'astro': [/^src\\/pages\\/404\\.astro$/],\n 'nuxt': [/^pages\\/error\\.vue$/, /^error\\.vue$/],\n 'vite-react': [], // SPAs handle 404 differently\n 'vite-vue': [],\n 'cra': [],\n 'express': [],\n 'unknown': [],\n };\n\n const patterns = notFoundPatterns[framework];\n if (!patterns || patterns.length === 0) return [];\n\n const hasNotFound = files.some(f => patterns.some(p => p.test(f.path)));\n\n if (!hasNotFound) {\n return [\n this.createIssue({\n severity: SEVERITY.LOW,\n message: 'No custom 404 page found',\n filePath: 'project',\n suggestion: [\n 'Create a custom 404 page for a better user experience.',\n 'The default framework 404 looks unprofessional.',\n '',\n this.get404Suggestion(framework),\n ].join('\\n'),\n learnMoreUrl: 'https://web.dev/http-status-codes/#404-not-found',\n }),\n ];\n }\n\n return [];\n }\n\n private get404Suggestion(framework: WebFramework): string {\n switch (framework) {\n case 'nextjs-app':\n return 'Create: app/not-found.tsx';\n case 'nextjs-pages':\n return 'Create: pages/404.tsx';\n case 'remix':\n return 'Create: app/routes/$.tsx (catch-all route)';\n case 'sveltekit':\n return 'Create: src/routes/+error.svelte';\n case 'astro':\n return 'Create: src/pages/404.astro';\n case 'nuxt':\n return 'Create: error.vue or pages/error.vue';\n default:\n return 'Create a custom 404 page for your framework.';\n }\n }\n\n // ---------------------------------------------------------------------------\n // 024-F: robots.txt and sitemap.xml Check\n // ---------------------------------------------------------------------------\n\n private checkRobotsAndSitemap(\n files: readonly ProjectFile[],\n projectRoot: string,\n packageJson: import('@vibertest/shared').PackageJson | null,\n ): Issue[] {\n const issues: Issue[] = [];\n\n // Check robots.txt\n const robotsPaths = ['public/robots.txt', 'static/robots.txt', 'app/robots.ts', 'app/robots.tsx'];\n const hasRobots = robotsPaths.some(p => {\n const fullPath = path.join(projectRoot, p);\n return fs.existsSync(fullPath);\n }) || files.some(f => /robots\\.(txt|ts|tsx)$/.test(f.path));\n\n if (!hasRobots) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.LOW,\n message: 'No robots.txt found',\n filePath: 'project',\n suggestion: [\n 'Create a robots.txt file to control search engine crawling.',\n '',\n 'Basic robots.txt:',\n ' User-agent: *',\n ' Allow: /',\n ' Sitemap: https://yoursite.com/sitemap.xml',\n ].join('\\n'),\n learnMoreUrl: 'https://developers.google.com/search/docs/crawling-indexing/robots/intro',\n }),\n );\n }\n\n // Check sitemap.xml\n const sitemapPaths = ['public/sitemap.xml', 'static/sitemap.xml', 'app/sitemap.ts', 'app/sitemap.tsx'];\n const hasSitemap = sitemapPaths.some(p => {\n const fullPath = path.join(projectRoot, p);\n return fs.existsSync(fullPath);\n }) || files.some(f => /sitemap\\.(xml|ts|tsx)$/.test(f.path));\n\n // Check for sitemap plugins\n const deps = { ...packageJson?.dependencies, ...packageJson?.devDependencies };\n const hasSitemapPlugin = '@astrojs/sitemap' in deps || '@nuxtjs/sitemap' in deps;\n\n if (!hasSitemap && !hasSitemapPlugin) {\n issues.push(\n this.createIssue({\n severity: SEVERITY.LOW,\n message: 'No sitemap.xml found',\n filePath: 'project',\n suggestion: [\n 'Create a sitemap.xml for better search engine indexing.',\n '',\n 'Next.js: Create app/sitemap.ts that exports a sitemap function',\n 'Static: Create public/sitemap.xml with your page URLs',\n 'Astro: npm install @astrojs/sitemap',\n ].join('\\n'),\n learnMoreUrl: 'https://developers.google.com/search/docs/crawling-indexing/sitemaps/overview',\n }),\n );\n }\n\n return issues;\n }\n}\n","import type { AnalysisRule, Issue, RuleContext, RuleId } from '@vibertest/shared';\nimport { OversizedFilesRule } from './oversized-files.js';\nimport { DeadCodeRule } from './dead-code.js';\nimport { HardcodedSecretsRule } from './hardcoded-secrets.js';\nimport { UnusedDepsRule } from './unused-deps.js';\nimport { MissingTestsRule } from './missing-tests.js';\nimport { PatternInconsistencyRule } from './pattern-inconsistency.js';\nimport { PoorMaintainabilityRule } from './poor-maintainability.js';\nimport { MissingErrorHandlingRule } from './missing-error-handling.js';\nimport { AbandonedTodoRule } from './abandoned-todo.js';\nimport { BloatedBarrelRule } from './bloated-barrel.js';\nimport { StyleInconsistencyRule } from './style-inconsistency.js';\nimport { DuplicateDepsRule } from './duplicate-deps.js';\nimport { GodFileRule } from './god-file.js';\nimport { SeparationOfConcernsRule } from './separation-of-concerns.js';\nimport { ObsoletePatternsRule } from './obsolete-patterns.js';\nimport { AiSmellRule } from './ai-smell.js';\nimport { CodeDuplicationRule } from './code-duplication.js';\nimport { CircularDepsRule } from './circular-deps.js';\nimport { SecurityAntipatternsRule } from './security-antipatterns.js';\nimport { ReactPerformanceRule } from './react-performance.js';\nimport { MissingProjectStandardsRule } from './missing-project-standards.js';\n// Ship-Readiness Rules (022-024)\nimport { MissingComplianceRule } from './missing-compliance.js';\nimport { AccessibilityRule } from './accessibility.js';\nimport { MissingProductionBasicsRule } from './missing-production-basics.js';\n\n/**\n * Rule Registry - Manages all analysis rules.\n * Rules register themselves, and the engine runs them all.\n *\n * This is the Plugin Architecture from the design doc.\n * New rules can be added without modifying this file.\n */\nclass RuleRegistry {\n private readonly rules = new Map<RuleId, AnalysisRule>();\n\n /** Register a rule in the registry */\n register(rule: AnalysisRule): void {\n if (this.rules.has(rule.id)) {\n throw new Error(`Rule \"${rule.id}\" is already registered`);\n }\n this.rules.set(rule.id, rule);\n }\n\n /** Get a specific rule by ID */\n get(id: RuleId): AnalysisRule | undefined {\n return this.rules.get(id);\n }\n\n /** Get all registered rules */\n getAll(): AnalysisRule[] {\n return [...this.rules.values()];\n }\n\n /** Get only specific rules by ID */\n getByIds(ids: readonly RuleId[]): AnalysisRule[] {\n return ids\n .map((id) => this.rules.get(id))\n .filter((rule): rule is AnalysisRule => rule !== undefined);\n }\n\n /** Check if a rule is registered */\n has(id: RuleId): boolean {\n return this.rules.has(id);\n }\n\n /** Get count of registered rules */\n get size(): number {\n return this.rules.size;\n }\n}\n\n/** Singleton registry instance */\nexport const ruleRegistry = new RuleRegistry();\n\n// ---------------------------------------------------------------------------\n// Register all built-in rules\n// New rules: add import above + register here\n// ---------------------------------------------------------------------------\nruleRegistry.register(new OversizedFilesRule());\nruleRegistry.register(new DeadCodeRule());\nruleRegistry.register(new HardcodedSecretsRule());\nruleRegistry.register(new UnusedDepsRule());\nruleRegistry.register(new MissingTestsRule());\nruleRegistry.register(new PatternInconsistencyRule());\nruleRegistry.register(new PoorMaintainabilityRule());\nruleRegistry.register(new MissingErrorHandlingRule());\nruleRegistry.register(new AbandonedTodoRule());\nruleRegistry.register(new BloatedBarrelRule());\nruleRegistry.register(new StyleInconsistencyRule());\nruleRegistry.register(new DuplicateDepsRule());\nruleRegistry.register(new GodFileRule());\nruleRegistry.register(new SeparationOfConcernsRule());\nruleRegistry.register(new ObsoletePatternsRule());\nruleRegistry.register(new AiSmellRule());\nruleRegistry.register(new CodeDuplicationRule());\nruleRegistry.register(new CircularDepsRule());\nruleRegistry.register(new SecurityAntipatternsRule());\nruleRegistry.register(new ReactPerformanceRule());\nruleRegistry.register(new MissingProjectStandardsRule());\n// Ship-Readiness Rules (022-024)\nruleRegistry.register(new MissingComplianceRule());\nruleRegistry.register(new AccessibilityRule());\nruleRegistry.register(new MissingProductionBasicsRule());\n\n/** Callback for per-rule progress reporting */\nexport interface RuleProgressCallback {\n onRuleStart(ruleName: string): void;\n onRuleComplete(ruleName: string): void;\n}\n\n/**\n * Runs all enabled rules (or a subset) against the project context.\n * Executes sequentially to support progress reporting per rule.\n * Returns aggregated issues from all rules.\n */\nexport async function runRules(\n context: RuleContext,\n ruleIds?: readonly RuleId[],\n progress?: RuleProgressCallback,\n): Promise<Issue[]> {\n const rules = ruleIds\n ? ruleRegistry.getByIds(ruleIds)\n : ruleRegistry.getAll();\n\n const allIssues: Issue[] = [];\n\n for (const rule of rules) {\n try {\n progress?.onRuleStart(rule.name);\n const issues = await rule.run(context);\n allIssues.push(...issues);\n progress?.onRuleComplete(rule.name);\n } catch (error) {\n // Log but don't crash — one failing rule shouldn't stop the scan\n console.error(`Rule \"${rule.name}\" failed: ${error instanceof Error ? error.message : String(error)}`);\n progress?.onRuleComplete(rule.name);\n }\n }\n\n return allIssues;\n}\n\nexport { BaseRule } from './base-rule.js';\n","import {\n SEVERITY,\n GRADE,\n GRADE_LABEL,\n} from '@vibertest/shared';\nimport type {\n Issue,\n ScoreResult,\n SeverityBreakdown,\n ScorePenalty,\n Grade,\n RuleId,\n} from '@vibertest/shared';\n\n/**\n * Penalty points per severity level.\n * Critical issues hurt the most, info issues don't affect score.\n */\nconst SEVERITY_PENALTY = {\n [SEVERITY.CRITICAL]: 5,\n [SEVERITY.HIGH]: 3,\n [SEVERITY.MEDIUM]: 1,\n [SEVERITY.LOW]: 0.5,\n [SEVERITY.INFO]: 0,\n} as const;\n\n/**\n * Maximum penalty any single rule can contribute.\n * This prevents one problematic rule from tanking the entire score.\n * A project with issues spread across many rules shouldn't score 0.\n */\nconst MAX_PENALTY_PER_RULE = 15;\n\n/**\n * Minimum score floor. Even the worst projects get some credit.\n * This prevents frustration from seeing 0 on projects that are\n * \"bad but not hopeless\". A score of 0 should be reserved for\n * truly catastrophic codebases.\n */\nconst MINIMUM_SCORE = 10;\n\n/**\n * Severities that use DIMINISHING RETURNS scaling (logarithmic).\n *\n * Critical: every instance matters — linear penalty (security, secrets).\n * High/Medium/Low: logarithmic scaling — repetitive instances have diminishing impact.\n *\n * This prevents projects with many issues from being unfairly crushed\n * while keeping truly severe issues (critical) fully impactful.\n *\n * Scaling comparison for 100 issues:\n * Critical (linear): 5 × 100 = 500\n * High (log2): 3 × log2(101) ≈ 20\n * Medium (log2): 1 × log2(101) ≈ 6.7\n * Low (log2): 0.5 × log2(101) ≈ 3.3\n */\nconst DIMINISHING_SEVERITIES_LOG = new Set([SEVERITY.HIGH, SEVERITY.MEDIUM, SEVERITY.LOW, SEVERITY.INFO]);\n\n/**\n * Score ranges mapped to grades.\n * Score is 0-100, grade is A-F.\n */\nconst GRADE_THRESHOLDS = [\n { min: 90, grade: GRADE.A },\n { min: 75, grade: GRADE.B },\n { min: 60, grade: GRADE.C },\n { min: 40, grade: GRADE.D },\n { min: 0, grade: GRADE.F },\n] as const;\n\n/**\n * Calculates the health score from a list of issues.\n *\n * Formula:\n * For critical: linear penalty (base × count)\n * For high/medium/low: diminishing returns (base × log2(count + 1))\n * Per-rule cap: no single rule can exceed MAX_PENALTY_PER_RULE\n * Final score: Uses asymptotic scaling so it's harder to reach 0\n * score = max(MINIMUM_SCORE, 100 × e^(-penalty/80))\n *\n * The exponential decay means (with divisor 80):\n * - 0 penalty → 100 score\n * - 40 penalty → ~61 score\n * - 80 penalty → ~37 score\n * - 120 penalty → ~22 score\n * - 160 penalty → ~14 score (approaches MINIMUM_SCORE)\n */\nexport function calculateScore(issues: readonly Issue[]): ScoreResult {\n const breakdown = countBySeverity(issues);\n const penalties = calculatePenalties(issues);\n\n const totalPenalty = penalties.reduce((sum, p) => sum + p.penalty, 0);\n\n // Asymptotic scoring: harder to reach 0, easier to improve from bad scores\n // Uses exponential decay with a floor. Divisor of 80 (was 60) is less aggressive.\n const rawScore = 100 * Math.exp(-totalPenalty / 80);\n const score = Math.max(MINIMUM_SCORE, Math.min(100, Math.round(rawScore)));\n\n const grade = resolveGrade(score);\n const label = GRADE_LABEL[grade];\n\n return {\n score,\n grade,\n label,\n breakdown,\n penalties,\n };\n}\n\n/** Counts issues by severity level */\nfunction countBySeverity(issues: readonly Issue[]): SeverityBreakdown {\n const counts: SeverityBreakdown = {\n critical: 0,\n high: 0,\n medium: 0,\n low: 0,\n info: 0,\n };\n\n for (const issue of issues) {\n const key = issue.severity as keyof SeverityBreakdown;\n counts[key] = (counts[key] ?? 0) + 1;\n }\n\n return counts;\n}\n\n/**\n * Calculates penalty breakdown per rule, applying diminishing returns\n * and a per-rule cap to prevent any single rule from dominating.\n *\n * Within each rule group, issues are split by severity:\n * - Critical: linear penalty (each instance fully penalized)\n * - High/Medium/Low: base_penalty × log2(count + 1) per severity bucket\n * - Final penalty capped at MAX_PENALTY_PER_RULE\n *\n * Example: 15 medium issues from one rule\n * Linear: 15 × 1 = 15 points\n * Diminishing: 1 × log2(16) = 4 points\n */\nfunction calculatePenalties(issues: readonly Issue[]): ScorePenalty[] {\n const ruleGroups = new Map<RuleId, Issue[]>();\n\n for (const issue of issues) {\n const existing = ruleGroups.get(issue.ruleId) ?? [];\n existing.push(issue);\n ruleGroups.set(issue.ruleId, existing);\n }\n\n const penalties: ScorePenalty[] = [];\n\n for (const [ruleId, ruleIssues] of ruleGroups) {\n const rawPenalty = calculateRulePenalty(ruleIssues);\n // Cap penalty per rule to prevent one rule from tanking the score\n const cappedPenalty = Math.min(rawPenalty, MAX_PENALTY_PER_RULE);\n\n penalties.push({\n ruleId,\n count: ruleIssues.length,\n penalty: Number(cappedPenalty.toFixed(1)),\n });\n }\n\n return penalties.sort((a, b) => b.penalty - a.penalty);\n}\n\n/**\n * Calculates the penalty for a single rule's issues.\n * Groups by severity, applies linear (critical) or log2 (others) scaling.\n */\nfunction calculateRulePenalty(ruleIssues: readonly Issue[]): number {\n // Group issues by severity within this rule\n const bySeverity = new Map<string, number>();\n for (const issue of ruleIssues) {\n bySeverity.set(issue.severity, (bySeverity.get(issue.severity) ?? 0) + 1);\n }\n\n let penalty = 0;\n\n for (const [severity, count] of bySeverity) {\n const basePenalty = SEVERITY_PENALTY[severity];\n\n if (DIMINISHING_SEVERITIES_LOG.has(severity)) {\n // Logarithmic: log2(count + 1) grows very slowly\n // 1→1, 2→1.6, 5→2.6, 10→3.5, 15→4, 32→5, 100→6.7\n penalty += basePenalty * Math.log2(count + 1);\n } else {\n // Linear: every critical issue fully counts\n penalty += basePenalty * count;\n }\n }\n\n return penalty;\n}\n\n/** Maps a numeric score to a letter grade */\nfunction resolveGrade(score: number): Grade {\n for (const threshold of GRADE_THRESHOLDS) {\n if (score >= threshold.min) {\n return threshold.grade;\n }\n }\n return GRADE.F;\n}\n","import chalk from 'chalk';\nimport { SEVERITY } from '@vibertest/shared';\nimport type { ViberTestReport, Issue } from '@vibertest/shared';\nimport { BRAND, SEVERITY_STYLE, GRADE_COLOR, GRADE_ART } from './theme.js';\nimport { renderSummary } from './summary.js';\n\n// =============================================================================\n// Banner\n// =============================================================================\n\nexport function renderBanner(version: string): string {\n return [\n '',\n BRAND.primary(' ██╗ ██╗██╗██████╗ ███████╗██████╗ '),\n BRAND.primary(' ██║ ██║██║██╔══██╗██╔════╝██╔══██╗'),\n BRAND.primary(' ██║ ██║██║██████╔╝█████╗ ██████╔╝'),\n BRAND.primary(' ╚██╗ ██╔╝██║██╔══██╗██╔══╝ ██╔══██╗'),\n BRAND.primary(' ╚████╔╝ ██║██████╔╝███████╗██║ ██║'),\n BRAND.primary(' ╚═══╝ ╚═╝╚═════╝ ╚══════╝╚═╝ ╚═╝'),\n BRAND.secondary(' TEST'),\n '',\n ` ${chalk.dim('Your AI writes code.')}`,\n ` ${chalk.white.bold(\"ViberTest makes sure it doesn't suck.\")}`,\n ` ${chalk.dim(`v${version}`)}`,\n '',\n ].join('\\n');\n}\n\n// =============================================================================\n// Score Display\n// =============================================================================\n\nexport function renderScore(report: ViberTestReport): string {\n const { score, grade, label } = report.score;\n const gradeColor = GRADE_COLOR[grade];\n const art = GRADE_ART[grade];\n\n const barLength = 30;\n const filled = Math.round((score / 100) * barLength);\n const empty = barLength - filled;\n const bar = gradeColor('█'.repeat(filled)) + chalk.dim('░'.repeat(empty));\n\n const scoreStr = gradeColor.bold(`${score}`);\n const maxStr = chalk.dim('/100');\n\n // Centered art lines\n const artLines = art.map((line) => ` ${gradeColor(line)}`);\n\n return [\n '',\n ` ${chalk.bold('HEALTH SCORE')}`,\n '',\n ...artLines,\n '',\n ` ${scoreStr}${maxStr}`,\n ` ${bar}`,\n '',\n ` ${gradeColor.bold(label)}`,\n '',\n ].join('\\n');\n}\n\n// =============================================================================\n// Issues Display\n// =============================================================================\n\nexport function renderIssues(issues: readonly Issue[]): string {\n if (issues.length === 0) {\n return [\n '',\n ` ${chalk.green.bold('✓ No issues found!')} ${chalk.dim('Your code is clean.')}`,\n '',\n ].join('\\n');\n }\n\n const grouped = groupBySeverity(issues);\n const lines: string[] = [''];\n\n for (const [severity, severityIssues] of grouped) {\n const style = SEVERITY_STYLE[severity];\n if (!style) continue;\n\n lines.push(` ${style.color(style.icon)} ${style.color.bold(style.label)}${chalk.dim(` (${severityIssues.length})`)}`);\n lines.push('');\n\n const maxDisplay = Math.min(severityIssues.length, 10);\n for (let i = 0; i < maxDisplay; i++) {\n renderSingleIssue(lines, severityIssues[i]!, style, i === maxDisplay - 1);\n }\n\n if (severityIssues.length > 10) {\n lines.push(` ${chalk.dim(` ... and ${severityIssues.length - 10} more`)}`);\n }\n\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\n/** Renders a single issue's tree-style lines into the output array */\nfunction renderSingleIssue(\n lines: string[],\n issue: Issue,\n style: (typeof SEVERITY_STYLE)[string],\n isLast: boolean,\n): void {\n const connector = isLast ? '└' : '├';\n const pipe = isLast ? ' ' : '│';\n const location = issue.line ? chalk.dim(`:${issue.line}`) : '';\n\n lines.push(` ${chalk.dim(connector)}─ ${style.color(issue.ruleName)}`);\n lines.push(` ${chalk.dim(pipe)} ${issue.message}`);\n lines.push(` ${chalk.dim(pipe)} ${chalk.dim('at')} ${chalk.cyan(issue.filePath)}${location}`);\n\n if (issue.codeSnippet) {\n lines.push(` ${chalk.dim(pipe)} ${chalk.dim('→')} ${chalk.dim(issue.codeSnippet)}`);\n }\n\n const suggestionLine = issue.suggestion.split('\\n')[0] ?? '';\n lines.push(` ${chalk.dim(pipe)} ${chalk.dim('💡')} ${chalk.italic.dim(suggestionLine)}`);\n\n if (issue.learnMoreUrl) {\n lines.push(` ${chalk.dim(pipe)} ${chalk.dim('📖')} ${chalk.underline.dim(issue.learnMoreUrl)}`);\n }\n\n if (!isLast) lines.push(` ${chalk.dim(pipe)}`);\n}\n\n// =============================================================================\n// Full Report (no banner - CLI handles that separately)\n// =============================================================================\n\nexport function renderTerminalReport(report: ViberTestReport): string {\n return [\n renderIssues(report.issues),\n renderSummary(report),\n renderScore(report),\n ].join('\\n');\n}\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\nfunction groupBySeverity(issues: readonly Issue[]): Map<string, Issue[]> {\n const order = [SEVERITY.CRITICAL, SEVERITY.HIGH, SEVERITY.MEDIUM, SEVERITY.LOW, SEVERITY.INFO];\n const grouped = new Map<string, Issue[]>();\n\n for (const severity of order) {\n const filtered = issues.filter((i) => i.severity === severity);\n if (filtered.length > 0) {\n grouped.set(severity, filtered);\n }\n }\n\n return grouped;\n}\n","import chalk from 'chalk';\nimport { SEVERITY, GRADE } from '@vibertest/shared';\nimport type { Grade } from '@vibertest/shared';\n\n// =============================================================================\n// Brand Colors\n// =============================================================================\n\nexport const BRAND = {\n primary: chalk.hex('#8B5CF6'),\n secondary: chalk.hex('#A78BFA'),\n accent: chalk.hex('#C4B5FD'),\n dim: chalk.hex('#6B7280'),\n} as const;\n\n// =============================================================================\n// Severity Styles\n// =============================================================================\n\ninterface SeverityStyle {\n readonly color: typeof chalk;\n readonly icon: string;\n readonly label: string;\n}\n\nexport const SEVERITY_STYLE: Record<string, SeverityStyle> = {\n [SEVERITY.CRITICAL]: { color: chalk.red, icon: '●', label: 'CRITICAL' },\n [SEVERITY.HIGH]: { color: chalk.hex('#F97316'), icon: '●', label: 'HIGH' },\n [SEVERITY.MEDIUM]: { color: chalk.yellow, icon: '●', label: 'MEDIUM' },\n [SEVERITY.LOW]: { color: chalk.blue, icon: '●', label: 'LOW' },\n [SEVERITY.INFO]: { color: chalk.gray, icon: '○', label: 'INFO' },\n} as const;\n\n// =============================================================================\n// Grade Styles\n// =============================================================================\n\nexport const GRADE_COLOR: Record<Grade, typeof chalk> = {\n [GRADE.A]: chalk.green,\n [GRADE.B]: chalk.hex('#84CC16'),\n [GRADE.C]: chalk.yellow,\n [GRADE.D]: chalk.hex('#F97316'),\n [GRADE.F]: chalk.red,\n};\n\nexport const GRADE_ART: Record<Grade, readonly string[]> = {\n [GRADE.A]: [\n ' ██████╗ ',\n ' ██╔═══██╗',\n ' ███████╔╝',\n ' ██╔═══██╗',\n ' ██║ ██║',\n ' ╚═╝ ╚═╝',\n ],\n [GRADE.B]: [\n ' ██████╗ ',\n ' ██╔══██╗ ',\n ' ██████╔╝ ',\n ' ██╔══██╗ ',\n ' ██████╔╝ ',\n ' ╚═════╝ ',\n ],\n [GRADE.C]: [\n ' ██████╗ ',\n ' ██╔════╝ ',\n ' ██║ ',\n ' ██║ ',\n ' ╚██████╗ ',\n ' ╚═════╝ ',\n ],\n [GRADE.D]: [\n ' ██████╗ ',\n ' ██╔══██╗ ',\n ' ██║ ██║ ',\n ' ██║ ██║ ',\n ' ██████╔╝ ',\n ' ╚═════╝ ',\n ],\n [GRADE.F]: [\n ' ███████╗ ',\n ' ██╔════╝ ',\n ' █████╗ ',\n ' ██╔══╝ ',\n ' ██║ ',\n ' ╚═╝ ',\n ],\n};\n","import chalk from 'chalk';\nimport { SEVERITY } from '@vibertest/shared';\nimport type { ViberTestReport, Issue } from '@vibertest/shared';\nimport { BRAND, SEVERITY_STYLE } from './theme.js';\n\n/** Column width for aligning stat labels in the summary */\nconst SUMMARY_LABEL_WIDTH = 20;\n\n// =============================================================================\n// Summary\n// =============================================================================\n\nexport function renderSummary(report: ViberTestReport): string {\n const { summary, scanDuration } = report;\n const { breakdown } = report.score;\n\n const lines: string[] = [\n ` ${BRAND.secondary.bold('─── Summary ───────────────────────────────────')}`,\n '',\n ];\n\n const stats: [string, string][] = [\n ['Files scanned', String(summary.totalFiles)],\n ['Issues found', summary.totalIssues > 0 ? chalk.bold(String(summary.totalIssues)) : chalk.green('0')],\n [' Critical', breakdown.critical > 0 ? chalk.red(String(breakdown.critical)) : chalk.dim('0')],\n [' High', breakdown.high > 0 ? chalk.hex('#F97316')(String(breakdown.high)) : chalk.dim('0')],\n [' Medium', breakdown.medium > 0 ? chalk.yellow(String(breakdown.medium)) : chalk.dim('0')],\n [' Low', breakdown.low > 0 ? chalk.blue(String(breakdown.low)) : chalk.dim('0')],\n ['Scan time', `${scanDuration.toFixed(2)}s`],\n ];\n\n for (const [label, value] of stats) {\n lines.push(` ${chalk.dim(label)}${' '.repeat(Math.max(0, SUMMARY_LABEL_WIDTH - label.length))}${value}`);\n }\n\n const topFiles = getTopProblematicFiles(report.issues, 5);\n if (topFiles.length > 0) {\n lines.push('');\n lines.push(` ${BRAND.secondary.bold('─── Most Problematic Files ────────────────────')}`);\n lines.push('');\n\n for (let i = 0; i < topFiles.length; i++) {\n const { filePath, count, severity } = topFiles[i]!;\n const rank = chalk.dim(`${i + 1}.`);\n const severityColor = SEVERITY_STYLE[severity]?.color ?? chalk.white;\n const plural = count === 1 ? 'issue' : 'issues';\n lines.push(` ${rank} ${chalk.cyan(filePath)} ${severityColor(`(${count} ${plural})`)}`);\n }\n }\n\n lines.push('');\n return lines.join('\\n');\n}\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\ninterface TopFile {\n filePath: string;\n count: number;\n severity: string;\n}\n\nfunction getTopProblematicFiles(issues: readonly Issue[], limit: number): TopFile[] {\n const fileCounts = new Map<string, { count: number; worstSeverity: string }>();\n const severityOrder = [SEVERITY.CRITICAL, SEVERITY.HIGH, SEVERITY.MEDIUM, SEVERITY.LOW, SEVERITY.INFO];\n\n for (const issue of issues) {\n if (issue.filePath === 'project' || issue.filePath === 'package.json') continue;\n\n const existing = fileCounts.get(issue.filePath);\n if (existing) {\n existing.count++;\n const currentIdx = severityOrder.indexOf(existing.worstSeverity);\n const newIdx = severityOrder.indexOf(issue.severity);\n if (newIdx < currentIdx) existing.worstSeverity = issue.severity;\n } else {\n fileCounts.set(issue.filePath, { count: 1, worstSeverity: issue.severity });\n }\n }\n\n return [...fileCounts.entries()]\n .map(([filePath, { count, worstSeverity }]) => ({ filePath, count, severity: worstSeverity }))\n .sort((a, b) => b.count - a.count)\n .slice(0, limit);\n}\n","import { writeFile } from 'node:fs/promises';\nimport { resolve } from 'node:path';\nimport type { ViberTestReport } from '@vibertest/shared';\n\nconst DEFAULT_OUTPUT = 'vibertest-report.json';\n\n/**\n * Generates a JSON report file from the scan results.\n * Pretty-printed for readability.\n */\nexport async function writeJsonReport(\n report: ViberTestReport,\n outputPath?: string,\n): Promise<string> {\n const filePath = resolve(outputPath ?? DEFAULT_OUTPUT);\n const content = JSON.stringify(report, null, 2);\n\n try {\n await writeFile(filePath, content, 'utf-8');\n } catch (error) {\n throw new Error(`Failed to write report to ${filePath}: ${error instanceof Error ? error.message : String(error)}`);\n }\n\n return filePath;\n}\n","import chalk from 'chalk';\nimport ora from 'ora';\nimport { loadCredentials, saveCredentials, deleteCredentials } from './credentials.js';\nimport {\n createCliSession,\n pollCliSession,\n whoami as whoamiApi,\n CloudApiError,\n} from './api.js';\nimport type { WhoamiResponse } from './api.js';\n\n// =============================================================================\n// Auth Flow Orchestrator\n// =============================================================================\n// Handles login (browser OAuth + polling), logout, and whoami for the CLI.\n// =============================================================================\n\nconst POLL_INTERVAL_MS = 2000;\nconst POLL_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes (matches server session TTL)\n\nconst DEFAULT_CLOUD_URL = 'http://localhost:3000';\n\n// -----------------------------------------------------------------------------\n// Login\n// -----------------------------------------------------------------------------\n\n/**\n * Interactive login flow:\n * 1. POST /api/auth/cli → get sessionId + authUrl\n * 2. Open browser at authUrl\n * 3. Poll GET /api/auth/cli?session=xxx until API key is returned\n * 4. Save credentials to ~/.vibertest/credentials.json\n */\nexport async function login(cloudUrl?: string): Promise<void> {\n const url = cloudUrl ?? DEFAULT_CLOUD_URL;\n\n // Check if already logged in\n const existing = await loadCredentials();\n if (existing) {\n console.log(chalk.yellow('\\n ⚠ Already logged in.'));\n console.log(chalk.dim(' Run'), chalk.cyan('vibertest logout'), chalk.dim('first to switch accounts.\\n'));\n return;\n }\n\n const spinner = ora({ color: 'magenta', indent: 2 });\n\n try {\n // Step 1: Create CLI session\n spinner.start('Creating auth session...');\n const session = await createCliSession(url);\n spinner.succeed('Auth session created');\n\n // Step 2: Open browser\n console.log(\n chalk.dim('\\n Opening browser for authentication...\\n'),\n );\n console.log(` ${chalk.cyan(session.authUrl)}\\n`);\n\n await openBrowser(session.authUrl);\n\n console.log(chalk.dim(' If the browser didn\\'t open, copy the URL above.\\n'));\n\n // Step 3: Poll for completion\n spinner.start('Waiting for authentication...');\n const apiKey = await pollForApiKey(url, session.sessionId, spinner);\n\n // Step 4: Save credentials\n await saveCredentials({ apiKey, cloudUrl: url });\n\n spinner.succeed('Authenticated successfully');\n console.log(chalk.green('\\n ✓ Logged in to ViberTest Cloud'));\n console.log(chalk.dim(' Credentials saved to ~/.vibertest/credentials.json\\n'));\n } catch (error) {\n spinner.fail('Authentication failed');\n\n if (error instanceof CloudApiError) {\n console.error(chalk.red(`\\n ✗ ${error.apiError}\\n`));\n } else {\n const message = error instanceof Error ? error.message : String(error);\n console.error(chalk.red(`\\n ✗ ${message}\\n`));\n }\n\n process.exit(1);\n }\n}\n\n// -----------------------------------------------------------------------------\n// Logout\n// -----------------------------------------------------------------------------\n\n/**\n * Deletes stored credentials.\n */\nexport async function logout(): Promise<void> {\n const deleted = await deleteCredentials();\n\n if (deleted) {\n console.log(chalk.green('\\n ✓ Logged out of ViberTest Cloud'));\n console.log(chalk.dim(' Credentials removed from ~/.vibertest/credentials.json\\n'));\n } else {\n console.log(chalk.yellow('\\n ⚠ Not logged in.\\n'));\n }\n}\n\n// -----------------------------------------------------------------------------\n// Whoami\n// -----------------------------------------------------------------------------\n\n/**\n * Shows the currently authenticated user's profile.\n */\nexport async function whoami(): Promise<void> {\n const credentials = await loadCredentials();\n\n if (!credentials) {\n console.log(chalk.yellow('\\n ⚠ Not logged in.'));\n console.log(chalk.dim(' Run'), chalk.cyan('vibertest login'), chalk.dim('to authenticate.\\n'));\n return;\n }\n\n const spinner = ora({ color: 'magenta', indent: 2 });\n\n try {\n spinner.start('Fetching profile...');\n const profile = await whoamiApi(credentials.cloudUrl, credentials.apiKey);\n spinner.stop();\n\n printProfile(profile);\n } catch (error) {\n spinner.fail('Failed to fetch profile');\n\n if (error instanceof CloudApiError && error.statusCode === 401) {\n console.error(chalk.red('\\n ✗ Invalid or expired API key.'));\n console.error(chalk.dim(' Run'), chalk.cyan('vibertest logout'), chalk.dim('then'), chalk.cyan('vibertest login'), chalk.dim('to re-authenticate.\\n'));\n } else {\n const message = error instanceof Error ? error.message : String(error);\n console.error(chalk.red(`\\n ✗ ${message}\\n`));\n }\n\n process.exit(1);\n }\n}\n\n// -----------------------------------------------------------------------------\n// Helpers\n// -----------------------------------------------------------------------------\n\n/**\n * Polls the CLI session endpoint until the API key is returned or timeout.\n */\nasync function pollForApiKey(\n cloudUrl: string,\n sessionId: string,\n spinner: ReturnType<typeof ora>,\n): Promise<string> {\n const startTime = Date.now();\n\n while (Date.now() - startTime < POLL_TIMEOUT_MS) {\n const result = await pollCliSession(cloudUrl, sessionId);\n\n if (result.status === 'complete' && result.apiKey) {\n return result.apiKey;\n }\n\n // Update spinner with elapsed time\n const elapsed = Math.round((Date.now() - startTime) / 1000);\n spinner.text = `Waiting for authentication... (${elapsed}s)`;\n\n await sleep(POLL_INTERVAL_MS);\n }\n\n throw new Error('Authentication timed out. Please try again.');\n}\n\n/**\n * Opens a URL in the default browser.\n * Uses platform-specific commands (macOS: open, Linux: xdg-open, Windows: start).\n */\nasync function openBrowser(url: string): Promise<void> {\n const { exec } = await import('node:child_process');\n const { platform } = await import('node:os');\n\n const command = getBrowserCommand(platform(), url);\n\n return new Promise((resolve) => {\n exec(command, (error) => {\n // Don't fail if browser can't open — user can copy the URL\n if (error) {\n console.log(chalk.dim(' Could not open browser automatically.'));\n }\n resolve();\n });\n });\n}\n\nfunction getBrowserCommand(os: string, url: string): string {\n switch (os) {\n case 'darwin':\n return `open \"${url}\"`;\n case 'win32':\n return `start \"\" \"${url}\"`;\n default:\n return `xdg-open \"${url}\"`;\n }\n}\n\nfunction printProfile(profile: WhoamiResponse): void {\n const planColor = profile.plan === 'free' ? chalk.dim : chalk.yellow;\n\n console.log('');\n console.log(chalk.bold(' ViberTest Cloud'));\n console.log(chalk.dim(' ─────────────────────'));\n console.log(` ${chalk.dim('User:')} ${chalk.white(profile.username)}`);\n\n if (profile.displayName) {\n console.log(` ${chalk.dim('Name:')} ${profile.displayName}`);\n }\n\n console.log(` ${chalk.dim('Plan:')} ${planColor(profile.plan)}`);\n console.log('');\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n","import { readFile, writeFile, mkdir, unlink, access } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\n// =============================================================================\n// Credentials Manager\n// =============================================================================\n// Reads/writes/deletes ~/.vibertest/credentials.json\n// Stores the API key and cloud URL for CLI-to-Cloud communication.\n// =============================================================================\n\nconst CREDENTIALS_DIR = '.vibertest';\nconst CREDENTIALS_FILE = 'credentials.json';\n\nconst DEFAULT_CLOUD_URL = 'http://localhost:3000';\n\n// -----------------------------------------------------------------------------\n// Types\n// -----------------------------------------------------------------------------\n\nexport interface CloudCredentials {\n readonly apiKey: string;\n readonly cloudUrl: string;\n}\n\n// -----------------------------------------------------------------------------\n// Path Helpers\n// -----------------------------------------------------------------------------\n\nfunction getCredentialsDir(): string {\n return join(homedir(), CREDENTIALS_DIR);\n}\n\nfunction getCredentialsPath(): string {\n return join(getCredentialsDir(), CREDENTIALS_FILE);\n}\n\n// -----------------------------------------------------------------------------\n// Public API\n// -----------------------------------------------------------------------------\n\n/**\n * Read stored credentials from ~/.vibertest/credentials.json.\n * Returns null if the file doesn't exist or is malformed.\n */\nexport async function loadCredentials(): Promise<CloudCredentials | null> {\n try {\n const raw = await readFile(getCredentialsPath(), 'utf-8');\n const parsed: unknown = JSON.parse(raw);\n\n if (!isValidCredentials(parsed)) {\n return null;\n }\n\n return parsed;\n } catch {\n return null;\n }\n}\n\n/**\n * Save credentials to ~/.vibertest/credentials.json.\n * Creates the directory if it doesn't exist.\n */\nexport async function saveCredentials(credentials: CloudCredentials): Promise<void> {\n const dir = getCredentialsDir();\n\n try {\n await access(dir);\n } catch {\n await mkdir(dir, { recursive: true });\n }\n\n const content = JSON.stringify(\n {\n apiKey: credentials.apiKey,\n cloudUrl: credentials.cloudUrl,\n },\n null,\n 2,\n );\n\n await writeFile(getCredentialsPath(), content, { encoding: 'utf-8', mode: 0o600 });\n}\n\n/**\n * Delete the credentials file. Returns true if deleted, false if it didn't exist.\n */\nexport async function deleteCredentials(): Promise<boolean> {\n try {\n await unlink(getCredentialsPath());\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Check if credentials exist without reading the full file.\n */\nexport async function hasCredentials(): Promise<boolean> {\n try {\n await access(getCredentialsPath());\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Get the cloud URL from credentials, or the default if not logged in.\n */\nexport async function getCloudUrl(): Promise<string> {\n const creds = await loadCredentials();\n return creds?.cloudUrl ?? DEFAULT_CLOUD_URL;\n}\n\n// -----------------------------------------------------------------------------\n// Type Guard\n// -----------------------------------------------------------------------------\n\nfunction isValidCredentials(value: unknown): value is CloudCredentials {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'apiKey' in value &&\n typeof (value as Record<string, unknown>)['apiKey'] === 'string' &&\n 'cloudUrl' in value &&\n typeof (value as Record<string, unknown>)['cloudUrl'] === 'string'\n );\n}\n","import type { ViberTestReport } from '@vibertest/shared';\n\n// =============================================================================\n// Cloud API Client\n// =============================================================================\n// HTTP client for ViberTest Cloud endpoints.\n// Uses native fetch (Node 20+). No external dependencies.\n// =============================================================================\n\n// -----------------------------------------------------------------------------\n// Response Types\n// -----------------------------------------------------------------------------\n\nexport interface CliSessionResponse {\n readonly sessionId: string;\n readonly authUrl: string;\n readonly expiresIn: number;\n}\n\nconst CLI_SESSION_STATUS = {\n PENDING: 'pending',\n COMPLETE: 'complete',\n} as const;\n\ntype CliSessionStatus = (typeof CLI_SESSION_STATUS)[keyof typeof CLI_SESSION_STATUS];\n\nexport interface CliSessionPollResponse {\n readonly status: CliSessionStatus;\n readonly apiKey?: string;\n}\n\nexport interface WhoamiResponse {\n readonly username: string;\n readonly displayName: string | null;\n readonly avatarUrl: string | null;\n readonly plan: string;\n}\n\nexport interface ScanUploadResponse {\n readonly success: boolean;\n readonly scan: {\n readonly id: string;\n readonly projectId: string;\n readonly projectSlug: string;\n readonly score: number;\n readonly grade: string;\n readonly totalIssues: number;\n readonly createdAt: string;\n };\n readonly url: string;\n}\n\nexport interface GitContext {\n readonly branch?: string;\n readonly commitSha?: string;\n readonly prNumber?: string;\n}\n\nexport interface ApiError {\n readonly error: string;\n readonly details?: unknown;\n}\n\n// -----------------------------------------------------------------------------\n// Error Class\n// -----------------------------------------------------------------------------\n\nexport class CloudApiError extends Error {\n readonly statusCode: number;\n readonly apiError: string;\n\n constructor(statusCode: number, apiError: string) {\n super(`Cloud API error (${statusCode}): ${apiError}`);\n this.name = 'CloudApiError';\n this.statusCode = statusCode;\n this.apiError = apiError;\n }\n}\n\n// -----------------------------------------------------------------------------\n// API Functions\n// -----------------------------------------------------------------------------\n\n/**\n * POST /api/auth/cli\n * Creates a new CLI auth session. Returns session ID + browser URL.\n */\nexport async function createCliSession(cloudUrl: string): Promise<CliSessionResponse> {\n const response = await fetch(`${cloudUrl}/api/auth/cli`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n });\n\n if (!response.ok) {\n const body = await parseErrorBody(response);\n throw new CloudApiError(response.status, body);\n }\n\n return response.json() as Promise<CliSessionResponse>;\n}\n\n/**\n * GET /api/auth/cli?session=xxx\n * Polls for CLI session completion. Returns API key when the user finishes OAuth.\n */\nexport async function pollCliSession(\n cloudUrl: string,\n sessionId: string,\n): Promise<CliSessionPollResponse> {\n const url = new URL('/api/auth/cli', cloudUrl);\n url.searchParams.set('session', sessionId);\n\n const response = await fetch(url.toString(), {\n method: 'GET',\n });\n\n if (!response.ok) {\n const body = await parseErrorBody(response);\n throw new CloudApiError(response.status, body);\n }\n\n return response.json() as Promise<CliSessionPollResponse>;\n}\n\n/**\n * GET /api/auth/whoami\n * Returns the authenticated user's profile. Uses API key for auth.\n */\nexport async function whoami(cloudUrl: string, apiKey: string): Promise<WhoamiResponse> {\n const response = await fetch(`${cloudUrl}/api/auth/whoami`, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n },\n });\n\n if (!response.ok) {\n const body = await parseErrorBody(response);\n throw new CloudApiError(response.status, body);\n }\n\n return response.json() as Promise<WhoamiResponse>;\n}\n\n/**\n * POST /api/scans\n * Uploads a scan report to ViberTest Cloud.\n */\nexport async function uploadScan(\n cloudUrl: string,\n apiKey: string,\n report: ViberTestReport,\n gitContext?: GitContext,\n): Promise<ScanUploadResponse> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey}`,\n };\n\n if (gitContext?.branch) {\n headers['x-vibertest-branch'] = gitContext.branch;\n }\n if (gitContext?.commitSha) {\n headers['x-vibertest-commit'] = gitContext.commitSha;\n }\n if (gitContext?.prNumber) {\n headers['x-vibertest-pr'] = gitContext.prNumber;\n }\n\n const response = await fetch(`${cloudUrl}/api/scans`, {\n method: 'POST',\n headers,\n body: JSON.stringify(report),\n });\n\n if (!response.ok) {\n const body = await parseErrorBody(response);\n throw new CloudApiError(response.status, body);\n }\n\n return response.json() as Promise<ScanUploadResponse>;\n}\n\n// -----------------------------------------------------------------------------\n// Helpers\n// -----------------------------------------------------------------------------\n\nasync function parseErrorBody(response: Response): Promise<string> {\n try {\n const body: unknown = await response.json();\n if (typeof body === 'object' && body !== null && 'error' in body) {\n return String((body as ApiError).error);\n }\n return response.statusText;\n } catch {\n return response.statusText;\n }\n}\n","import { createProgram } from './cli.js';\n\nconst program = createProgram();\nprogram.parse();\n"],"mappings":"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","names":["chalk","ora","readFile","resolve","join","match","match","MissingComplianceRule","fs","ruleIds","resolve","readFile","join","chalk","chalk","chalk","chalk","resolve","chalk","readFile","writeFile","join","join","readFile","writeFile","chalk","whoami","resolve","VERSION","program","path","whoami","chalk","ruleIds","ora","writeFile","resolve","DEFAULT_CONFIG"]}