1import chalk from 'chalk'; 2import fs from 'fs'; 3import path from 'path'; 4import prompts from 'prompts'; 5 6import * as Template from './Template'; 7import { Log } from './log'; 8import { formatSelfCommand } from './resolvePackageManager'; 9import { getConflictsForDirectory } from './utils/dir'; 10 11export function assertValidName(folderName: string) { 12 const validation = Template.validateName(folderName); 13 if (typeof validation === 'string') { 14 Log.exit(chalk`{red Cannot create an app named {bold "${folderName}"}. ${validation}}`, 1); 15 } 16 const isFolderNameForbidden = Template.isFolderNameForbidden(folderName); 17 if (isFolderNameForbidden) { 18 Log.exit( 19 chalk`{red Cannot create an app named {bold "${folderName}"} because it would conflict with a dependency of the same name.}`, 20 1 21 ); 22 } 23} 24 25export function assertFolderEmpty(projectRoot: string, folderName: string) { 26 const conflicts = getConflictsForDirectory(projectRoot); 27 if (conflicts.length) { 28 Log.log(chalk`The directory {cyan ${folderName}} has files that might be overwritten:`); 29 Log.log(); 30 for (const file of conflicts) { 31 Log.log(` ${file}`); 32 } 33 Log.log(); 34 Log.exit('Try using a new directory name, or moving these files.\n'); 35 } 36} 37 38export async function resolveProjectRootAsync(input: string): Promise<string> { 39 let name = input?.trim(); 40 41 if (!name) { 42 const { answer } = await prompts({ 43 type: 'text', 44 name: 'answer', 45 message: 'What is your app named?', 46 initial: 'my-app', 47 validate: (name) => { 48 const validation = Template.validateName(path.basename(path.resolve(name))); 49 if (typeof validation === 'string') { 50 return 'Invalid project name: ' + validation; 51 } 52 return true; 53 }, 54 }); 55 56 if (typeof answer === 'string') { 57 name = answer.trim(); 58 } 59 } 60 61 if (!name) { 62 const selfCmd = formatSelfCommand(); 63 Log.log(); 64 Log.log('Please choose your app name:'); 65 Log.log(chalk` {dim $} {cyan ${selfCmd} <name>}`); 66 Log.log(); 67 Log.log(`For more info, run:`); 68 Log.log(chalk` {dim $} {cyan ${selfCmd} --help}`); 69 Log.log(); 70 Log.exit(''); 71 } 72 73 const projectRoot = path.resolve(name); 74 const folderName = path.basename(projectRoot); 75 76 assertValidName(folderName); 77 78 await fs.promises.mkdir(projectRoot, { recursive: true }); 79 80 assertFolderEmpty(projectRoot, folderName); 81 82 return projectRoot; 83} 84