import fs from 'node:fs'; import path from 'node:path'; import { detectJsPackageManager, hasDependency, installCommandFor, readPackageJson, runScriptCommandFor, } from './packageManager.js'; function detectBundler(root, pkg) { if (hasDependency(pkg, 'next') || fileExists(root, ['next.config.js', 'next.config.mjs', 'next.config.ts'])) { return 'next'; } if (fileExists(root, ['vite.config.js', 'vite.config.ts', 'vite.config.mjs'])) return 'vite'; if (hasDependency(pkg, 'react-scripts')) return 'create-react-app'; return 'unknown'; } function detectNextRouter(root) { const appLayouts = [ path.join(root, 'app', 'layout.tsx'), path.join(root, 'app', 'layout.jsx'), path.join(root, 'src', 'app', 'layout.tsx'), path.join(root, 'src', 'app', 'layout.jsx'), ]; if (appLayouts.some((p) => fs.existsSync(p))) return 'app'; const pagesIndexes = [ path.join(root, 'pages', 'index.tsx'), path.join(root, 'pages', 'index.jsx'), path.join(root, 'pages', 'index.js'), path.join(root, 'src', 'pages', 'index.tsx'), path.join(root, 'src', 'pages', 'index.jsx'), ]; if (pagesIndexes.some((p) => fs.existsSync(p))) return 'pages'; return 'unknown'; } function fileExists(root, names) { return names.some((name) => fs.existsSync(path.join(root, name))); } export class ReactAdapter { root; kind = 'react'; label; packageManager; pkg; bundler; nextRouter; constructor(root) { this.root = root; this.pkg = readPackageJson(root); this.packageManager = detectJsPackageManager(root); this.bundler = detectBundler(root, this.pkg); this.nextRouter = this.bundler === 'next' ? detectNextRouter(root) : 'unknown'; this.label = `React (${this.bundler})`; } installCommand() { const { command, args } = installCommandFor(this.packageManager); return { command, args, cwd: this.root }; } devCommand() { const script = this.findScript(['dev', 'start']); if (!script) { throw new Error(`No "dev" or "start" script found in package.json at "${this.root}".`); } const { command, args } = runScriptCommandFor(this.packageManager, script); return { command, args, cwd: this.root }; } buildCommand() { return this.scriptCommandOrNull(['build']); } testCommand(extraArgs = []) { return this.scriptCommandOrNull(['test'], extraArgs); } lintCommand(fix = false) { return this.scriptCommandOrNull(fix ? ['format', 'lint:fix'] : ['lint']); } readyPattern() { switch (this.bundler) { case 'vite': return /Local:\s+(https?:\/\/\S+)/i; case 'next': return /(?:Local|ready)[^:]*:\s*(https?:\/\/\S+)|started server on[^,]*,\s*url:\s*(https?:\/\/\S+)/i; case 'create-react-app': return /Local:\s+(https?:\/\/\S+)|Compiled successfully/i; default: return /(https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)[:\d]*\S*)/i; } } describe() { const isNext = this.bundler === 'next'; return { kind: this.kind, label: this.label, root: this.root, packageManager: this.packageManager, bundler: this.bundler, router: isNext ? this.nextRouter : null, rsc: isNext && this.nextRouter === 'app', reactVersion: this.pkg?.dependencies?.react ?? this.pkg?.devDependencies?.react ?? null, typescript: hasDependency(this.pkg, 'typescript') || fileExists(this.root, ['tsconfig.json']), scripts: this.pkg?.scripts ?? {}, }; } findScript(candidates) { return candidates.find((name) => this.pkg?.scripts?.[name]); } scriptCommandOrNull(candidates, extraArgs = []) { const script = this.findScript(candidates); if (!script) return null; const { command, args } = runScriptCommandFor(this.packageManager, script, extraArgs); return { command, args, cwd: this.root }; } } //# sourceMappingURL=react.js.map