UNPKG

@sprouted/create-vibes

Version:
247 lines 9.49 kB
import * as path from 'path'; import * as fs from 'fs/promises'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; import inquirer from 'inquirer'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); export class CreateAppCommand { constructor(engine) { this.engine = engine; } async execute(options) { const finalOptions = await this.promptMissingOptions(options); const templatePath = path.join(__dirname, '../../../templates/typescript/apps', finalOptions.type); const targetPath = path.join(process.cwd(), 'apps', finalOptions.name); // Ensure the apps directory exists await fs.mkdir(path.join(process.cwd(), 'apps'), { recursive: true }); await this.engine.generateFromTemplate(templatePath, { appName: finalOptions.name, displayName: finalOptions.displayName, appId: finalOptions.appId, framework: finalOptions.framework, includeRouter: finalOptions.includeRouter, includeTailwind: finalOptions.includeTailwind, includeNavigator: finalOptions.includeNavigator, includeAuth: finalOptions.includeAuth, includeApiClient: finalOptions.includeApiClient, port: finalOptions.port, includeDatabase: finalOptions.includeDatabase, includeValidation: finalOptions.includeValidation, includeSwagger: finalOptions.includeSwagger, includeGraphQL: finalOptions.includeGraphQL, includeAutoUpdater: finalOptions.includeAutoUpdater, includeSystemTray: finalOptions.includeSystemTray, includeMenuBar: finalOptions.includeMenuBar, includeIpc: finalOptions.includeIpc, includeDarkMode: finalOptions.includeDarkMode }, { outputPath: targetPath, dryRun: false }); console.log(`✨ Created ${finalOptions.type} app: ${finalOptions.name}`); console.log(`📁 Location: ${targetPath}`); console.log('\nNext steps:'); console.log(` cd apps/${finalOptions.name}`); console.log(' pnpm install'); console.log(finalOptions.type === 'mobile' ? ' pnpm start' : ' pnpm dev'); } async promptMissingOptions(options) { const questions = []; if (!options.name) { questions.push({ type: 'input', name: 'name', message: 'App name:', validate: (input) => { if (!input.trim()) return 'App name is required'; if (!/^[a-z0-9-]+$/.test(input)) { return 'App name must be lowercase alphanumeric with dashes'; } return true; } }); } if (options.type === 'web') { if (options.framework === undefined) { questions.push({ type: 'list', name: 'framework', message: 'Choose a framework:', choices: [ { name: 'Vite + React', value: 'vite-react' }, { name: 'Next.js', value: 'nextjs' } ], default: 'vite-react' }); } if (options.includeRouter === undefined) { questions.push({ type: 'confirm', name: 'includeRouter', message: 'Include React Router?', default: true }); } if (options.includeTailwind === undefined) { questions.push({ type: 'confirm', name: 'includeTailwind', message: 'Include Tailwind CSS?', default: false }); } } if (options.type === 'mobile') { if (options.displayName === undefined) { questions.push({ type: 'input', name: 'displayName', message: 'Display name (shown to users):', default: options.name || 'Vibes App' }); } if (options.includeNavigator === undefined) { questions.push({ type: 'confirm', name: 'includeNavigator', message: 'Include React Navigation?', default: true }); } if (options.includeAuth === undefined) { questions.push({ type: 'confirm', name: 'includeAuth', message: 'Include authentication setup?', default: false }); } if (options.includeApiClient === undefined) { questions.push({ type: 'confirm', name: 'includeApiClient', message: 'Include API client?', default: true }); } } if (options.type === 'api') { if (options.port === undefined) { questions.push({ type: 'number', name: 'port', message: 'Port number:', default: 3001 }); } if (options.includeDatabase === undefined) { questions.push({ type: 'confirm', name: 'includeDatabase', message: 'Include database (PostgreSQL with Prisma)?', default: true }); } if (options.includeAuth === undefined) { questions.push({ type: 'confirm', name: 'includeAuth', message: 'Include authentication (JWT)?', default: true }); } if (options.includeValidation === undefined) { questions.push({ type: 'confirm', name: 'includeValidation', message: 'Include request validation (Zod)?', default: true }); } if (options.includeSwagger === undefined) { questions.push({ type: 'confirm', name: 'includeSwagger', message: 'Include Swagger documentation?', default: false }); } if (options.includeGraphQL === undefined) { questions.push({ type: 'confirm', name: 'includeGraphQL', message: 'Include GraphQL support?', default: false }); } } if (options.type === 'desktop') { if (options.displayName === undefined) { questions.push({ type: 'input', name: 'displayName', message: 'Display name (shown to users):', default: options.name || 'Vibes Desktop' }); } if (options.appId === undefined) { questions.push({ type: 'input', name: 'appId', message: 'Application ID:', default: `com.vibes.${options.name || 'desktop'}` }); } if (options.includeAutoUpdater === undefined) { questions.push({ type: 'confirm', name: 'includeAutoUpdater', message: 'Include auto-updater?', default: true }); } if (options.includeSystemTray === undefined) { questions.push({ type: 'confirm', name: 'includeSystemTray', message: 'Include system tray support?', default: false }); } if (options.includeMenuBar === undefined) { questions.push({ type: 'confirm', name: 'includeMenuBar', message: 'Include custom menu bar?', default: true }); } if (options.includeIpc === undefined) { questions.push({ type: 'confirm', name: 'includeIpc', message: 'Include IPC communication examples?', default: true }); } if (options.includeDarkMode === undefined) { questions.push({ type: 'confirm', name: 'includeDarkMode', message: 'Include dark mode support?', default: true }); } } const answers = questions.length > 0 ? await inquirer.prompt(questions) : {}; return { ...options, ...answers }; } } //# sourceMappingURL=create-app.js.map