UNPKG

create-esmx

Version:

A scaffold tool for creating Esmx projects

205 lines (174 loc) 5.57 kB
import { cancel, intro, isCancel, note, outro, select, text } from '@clack/prompts'; import minimist from 'minimist'; import color from 'picocolors'; import { createProjectFromTemplate } from './project'; import { getAvailableTemplates, getEsmxVersion } from './template'; import type { CliOptions } from './types'; import { formatProjectName, getCommand } from './utils/index'; /** * Display help information */ function showHelp(userAgent?: string): void { const createCmd = getCommand('create', userAgent); console.log(` ${color.reset(color.bold(color.blue('🚀 Create Esmx Project')))} ${color.bold('Usage:')} ${createCmd} [project-name] ${createCmd} [project-name] [options] ${color.bold('Options:')} -t, --template <template> Template to use (default: vue2-csr) -n, --name <name> Project name or path -f, --force Force overwrite existing directory -h, --help Show help information -v, --version Show version number ${color.bold('Examples:')} ${createCmd} my-project ${createCmd} my-project -t vue2-csr ${createCmd} my-project --force ${createCmd} . -f -t vue2-csr ${color.bold('Available Templates:')} ${getAvailableTemplates() .map((t) => ` ${t.folder.padEnd(25)} ${t.description}`) .join('\n')} For more information, visit: ${color.cyan('https://esmnext.com')} `); } /** * Get project name from arguments or prompt user */ async function getProjectName( argName?: string, positionalName?: string ): Promise<string | symbol> { const providedName = argName || positionalName; if (providedName) { return providedName; } const projectName = await text({ message: 'Project name or path:', placeholder: 'my-esmx-project', validate: (value: string) => { if (!value.trim()) { return 'Project name or path is required'; } if (!/^[a-zA-Z0-9_.\/@-]+$/.test(value.trim())) { return 'Project name or path should only contain letters, numbers, hyphens, underscores, dots, and slashes'; } } }); return String(projectName).trim(); } /** * Get template type from arguments or prompt user */ async function getTemplateType(argTemplate?: string): Promise<string> { const availableTemplates = getAvailableTemplates(); if ( argTemplate && availableTemplates.some((t) => t.folder === argTemplate) ) { return argTemplate; } const options = availableTemplates.map((t) => ({ label: color.reset(color.gray(`${t.folder} - `) + color.bold(t.name)), value: t.folder, hint: t.description })); const template = await select({ message: 'Select a template:', options: options }); return String(template); } /** * Main function to create a project */ export async function cli(options: CliOptions = {}): Promise<void> { const { argv, cwd, userAgent, version } = options; const commandLineArgs = argv || process.argv.slice(2); const workingDir = cwd || process.cwd(); const parsedArgs = minimist(commandLineArgs, { string: ['template', 'name'], boolean: ['help', 'version', 'force'], alias: { t: 'template', n: 'name', f: 'force', h: 'help', v: 'version' } }); if (parsedArgs.help) { showHelp(userAgent); return; } if (parsedArgs.version) { console.log(getEsmxVersion()); return; } console.log(); intro( color.reset( color.bold(color.blue('🚀 Welcome to Esmx Project Creator!')) ) ); const projectNameInput = await getProjectName( parsedArgs.name, parsedArgs._[0] ); if (isCancel(projectNameInput)) { cancel('Operation cancelled'); return; } const { name, root } = formatProjectName(projectNameInput, workingDir); const templateType = await getTemplateType(parsedArgs.template); if (isCancel(templateType)) { cancel('Operation cancelled'); return; } const installCommand = getCommand('install', userAgent); const devCommand = getCommand('dev', userAgent); const buildCommand = getCommand('build', userAgent); const startCommand = getCommand('start', userAgent); const buildTypeCommand = getCommand('build:type', userAgent); const lintTypeCommand = getCommand('lint:type', userAgent); await createProjectFromTemplate( root, templateType, workingDir, parsedArgs.force, { projectName: name, esmxVersion: version || getEsmxVersion(), installCommand, devCommand, buildCommand, startCommand, buildTypeCommand, lintTypeCommand } ); const installCmd = installCommand; const devCmd = devCommand; const targetDirForDisplay = projectNameInput === '.' ? '.' : projectNameInput; const steps = [ projectNameInput !== '.' ? `cd ${targetDirForDisplay}` : null, installCmd, `git init ${color.gray('(optional)')}`, devCmd ].filter(Boolean); const nextSteps = steps.map((step, index) => { return color.reset(`${index + 1}. ${color.cyan(step)}`); }); note(nextSteps.join('\n'), 'Next steps'); outro(color.reset(color.green('Happy coding! 🎉'))); }