All files / packages/cli/src/commands create.js

11% Statements 11/100
100% Branches 0/0
100% Functions 0/0
11% Lines 11/100

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 1251x 1x 1x                     1x 1x 1x 1x 1x 1x 1x                                                                                                                                                                                                                 1x
/**
 * Create command - Scaffolds new Coherent.js projects
 */
 
import { Command } from 'commander';
import prompts from 'prompts';
import ora from 'ora';
import picocolors from 'picocolors';
import { existsSync, mkdirSync } from 'fs';
import { join, resolve } from 'path';
import { scaffoldProject } from '../generators/project-scaffold.js';
import { validateProjectName } from '../utils/validation.js';
 
export const createCommand = new Command('create')
  .description('Create a new Coherent.js project')
  .argument('[name]', 'project name')
  .option('-t, --template <template>', 'project template', 'basic')
  .option('--skip-install', 'skip npm install')
  .option('--skip-git', 'skip git initialization')
  .action(async (name, options) => {
    let projectName = name;
 
    // Interactive project name if not provided
    if (!projectName) {
      const response = await prompts({
        type: 'text',
        name: 'name',
        message: 'What is your project name?',
        initial: 'my-coherent-app',
        validate: validateProjectName
      });
 
      if (!response.name) {
        console.log(picocolors.yellow('👋 Project creation cancelled'));
        process.exit(0);
      }
      
      projectName = response.name;
    }
 
    // Validate project name
    const nameValidation = validateProjectName(projectName);
    if (nameValidation !== true) {
      console.error(picocolors.red('❌ Invalid project name:'), nameValidation);
      process.exit(1);
    }
 
    const projectPath = resolve(projectName);
 
    // Check if directory exists
    if (existsSync(projectPath)) {
      console.error(picocolors.red('❌ Directory already exists:'), projectName);
      process.exit(1);
    }
 
    console.log();
    console.log(picocolors.cyan('🚀 Creating Coherent.js project...'));
    console.log(picocolors.gray('📁 Project:'), picocolors.bold(projectName));
    console.log(picocolors.gray('📍 Location:'), projectPath);
    console.log();
 
    // Template selection
    let template = options.template;
    if (!template || template === 'basic') {
      const response = await prompts({
        type: 'select',
        name: 'template',
        message: 'Which template would you like to use?',
        choices: [
          { title: '🏃‍♂️ Basic App', value: 'basic', description: 'Simple Coherent.js app with routing' },
          { title: '🌐 Full Stack', value: 'fullstack', description: 'API + SSR with database integration' },
          { title: '⚡ Express Integration', value: 'express', description: 'Coherent.js with Express.js' },
          { title: '🚀 Fastify Integration', value: 'fastify', description: 'Coherent.js with Fastify' },
          { title: '📱 Component Library', value: 'components', description: 'Reusable component library' }
        ],
        initial: 0
      });
 
      if (!response.template) {
        console.log(picocolors.yellow('👋 Project creation cancelled'));
        process.exit(0);
      }
 
      template = response.template;
    }
 
    const spinner = ora('Scaffolding project...').start();
 
    try {
      // Create project directory
      mkdirSync(projectPath, { recursive: true });
 
      // Scaffold project
      await scaffoldProject(projectPath, {
        name: projectName,
        template,
        skipInstall: options.skipInstall,
        skipGit: options.skipGit
      });
 
      spinner.succeed('Project created successfully!');
 
      // Success message
      console.log();
      console.log(picocolors.green('✅ Project created successfully!'));
      console.log();
      console.log(picocolors.cyan('Next steps:'));
      console.log(picocolors.gray('  cd'), picocolors.bold(projectName));
      
      if (!options.skipInstall) {
        console.log(picocolors.gray('  npm run dev'));
      } else {
        console.log(picocolors.gray('  npm install'));
        console.log(picocolors.gray('  npm run dev'));
      }
      
      console.log();
      console.log(picocolors.gray('Happy coding! 🎉'));
 
    } catch (error) {
      spinner.fail('Failed to create project');
      console.error(picocolors.red('❌ Error:'), error.message);
      process.exit(1);
    }
  });