UNPKG

@sprouted/create-vibes

Version:
112 lines • 4.58 kB
import { TemplateEngine } from '../template-engine/index.js'; import path from 'path'; import fs from 'fs-extra'; import chalk from 'chalk'; import inquirer from 'inquirer'; import { fileURLToPath } from 'url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); export class CreateFeatureCommand { constructor() { this.engine = new TemplateEngine(); } async execute(options) { const projectRoot = options.projectRoot || process.cwd(); const featuresDir = path.join(projectRoot, 'features'); // Convert feature name to kebab-case const featureName = options.name.toLowerCase().replace(/\s+/g, '-'); // Check for spec first (spec-driven development) const specPath = path.join(projectRoot, 'specs/features', `${featureName}.md`); const hasSpec = await fs.pathExists(specPath); if (!hasSpec) { console.log(chalk.yellow('\nšŸ“‹ No specification found for this feature!')); console.log(chalk.cyan('šŸ’” Create a spec first with:')); console.log(chalk.cyan(` vibe spec ${featureName}\n`)); console.log(chalk.yellow('Spec-driven development ensures clarity before implementation.\n')); process.exit(1); } // Ensure features directory exists await fs.ensureDir(featuresDir); const featurePath = path.join(featuresDir, featureName); // Check if feature already exists if (await fs.pathExists(featurePath)) { throw new Error(`Feature '${featureName}' already exists!`); } console.log(chalk.blue(`🌊 Creating feature: ${featureName}`)); // Get template path const templatePath = path.join(__dirname, '../../templates/features/todo'); // Prepare variables const variables = { featureName, includeApi: options.includeApi ?? true, includeUi: options.includeUi ?? true, uiFramework: options.uiFramework || 'react', features: options.features || [] }; try { // Generate from template await this.engine.generateFromTemplate(templatePath, variables, { outputPath: featurePath }); console.log(chalk.green(`āœ… Feature '${featureName}' created successfully!`)); console.log('\nNext steps:'); console.log(chalk.cyan(` 1. cd features/${featureName}`)); console.log(chalk.cyan(` 2. pnpm install`)); console.log(chalk.cyan(` 3. Start coding! šŸš€`)); } catch (error) { console.error(chalk.red('Failed to create feature:'), error); throw error; } } async interactivePrompt() { const answers = await inquirer.prompt([ { type: 'input', name: 'name', message: '🌊 What should we call this feature?', validate: (input) => { if (!input.trim()) return 'Feature name is required'; if (!/^[a-zA-Z0-9-\s]+$/.test(input)) { return 'Feature name can only contain letters, numbers, hyphens, and spaces'; } return true; } }, { type: 'confirm', name: 'includeApi', message: 'Include API layer?', default: true }, { type: 'confirm', name: 'includeUi', message: 'Include UI layer?', default: true }, { type: 'list', name: 'uiFramework', message: 'Which UI framework?', choices: ['react', 'react-native'], default: 'react', when: (answers) => answers.includeUi }, { type: 'checkbox', name: 'features', message: 'Additional features to include:', choices: [ { name: 'React Router', value: 'react-router' }, { name: 'Expo Router', value: 'expo-router' }, { name: 'Tailwind CSS', value: 'tailwindcss' }, { name: 'NativeWind', value: 'nativewind' } ], when: (answers) => answers.includeUi } ]); return answers; } } //# sourceMappingURL=create-feature.js.map