@aiwanna-team/repo-start
Version:
一个交互式的项目模板选择和初始化CLI工具
145 lines (144 loc) • 5.32 kB
JavaScript
import { Command } from "commander";
import inquirer from "inquirer";
import chalk from "chalk";
import ora from "ora";
import { execSync } from "child_process";
import { readFileSync } from "fs";
import { fileURLToPath } from "url";
import { dirname, join } from "path";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const templatesPath = join(__dirname, "../templates.json");
let templates;
try {
const templatesData = readFileSync(templatesPath, "utf8");
templates = JSON.parse(templatesData);
} catch (error) {
console.error(chalk.red("❌ 无法读取模板配置文件"));
console.error(error);
process.exit(1);
}
const packagePath = join(__dirname, "../package.json");
let version = "0.0.0";
try {
const packageData = readFileSync(packagePath, "utf8");
const packageJson = JSON.parse(packageData);
version = packageJson.version;
} catch (error) {
console.warn(chalk.yellow("⚠️ 无法读取package.json,使用默认版本号"));
}
const program = new Command();
program.name("repo-start").description("🚀 交互式项目模板选择和初始化工具").version(version);
program.command("create").description("创建新项目").argument("[project-name]", "项目名称").action(async (projectName) => {
console.log(chalk.blue.bold("\n🎯 欢迎使用 repo-start 项目初始化工具!\n"));
try {
if (!projectName) {
const nameAnswer = await inquirer.prompt([
{
type: "input",
name: "projectName",
message: "请输入项目名称:",
validate: (input) => {
if (!input.trim()) {
return "项目名称不能为空";
}
if (!/^[a-zA-Z0-9-_]+$/.test(input)) {
return "项目名称只能包含字母、数字、连字符和下划线";
}
return true;
}
}
]);
projectName = nameAnswer.projectName;
}
const templateChoices = templates.map((template) => ({
name: `${chalk.green(template.name)} - ${chalk.dim(template.description)}`,
value: template,
short: template.name
}));
const { selectedTemplate } = await inquirer.prompt([
{
type: "list",
name: "selectedTemplate",
message: "请选择一个项目模板:",
choices: templateChoices
}
]);
const { confirm } = await inquirer.prompt([
{
type: "confirm",
name: "confirm",
message: `确认要使用 "${selectedTemplate.name}" 模板创建项目 "${projectName}" 吗?`,
default: true
}
]);
if (!confirm) {
console.log(chalk.yellow("👋 操作已取消"));
return;
}
const spinner = ora(`正在从 ${selectedTemplate.repository} 克隆模板...`).start();
try {
const cloneCommand = `git clone ${selectedTemplate.repository} ${projectName}`;
execSync(cloneCommand, { stdio: "pipe" });
spinner.succeed(chalk.green(`✅ 成功克隆模板到 ${projectName} 目录`));
if (selectedTemplate.installCommand) {
const { shouldInstall } = await inquirer.prompt([
{
type: "confirm",
name: "shouldInstall",
message: `是否要执行安装命令: ${selectedTemplate.installCommand}?`,
default: true
}
]);
if (shouldInstall) {
const installSpinner = ora("正在安装依赖...").start();
try {
execSync(selectedTemplate.installCommand, {
cwd: projectName,
stdio: "pipe"
});
installSpinner.succeed(chalk.green("✅ 依赖安装完成"));
} catch (error) {
installSpinner.fail(chalk.red("❌ 依赖安装失败"));
console.log(chalk.yellow(`💡 你可以手动进入 ${projectName} 目录执行: ${selectedTemplate.installCommand}`));
}
}
}
console.log(chalk.green.bold("\n🎉 项目创建成功!"));
console.log(chalk.cyan("\n📝 下一步操作:"));
console.log(chalk.white(` cd ${projectName}`));
if (selectedTemplate.startCommand) {
console.log(chalk.white(` ${selectedTemplate.startCommand}`));
}
if (selectedTemplate.tips) {
console.log(chalk.yellow(`
💡 提示: ${selectedTemplate.tips}`));
}
} catch (error) {
spinner.fail(chalk.red("❌ 克隆模板失败"));
console.error(chalk.red(`错误详情: ${error.message}`));
process.exit(1);
}
} catch (error) {
console.error(chalk.red("❌ 发生错误:"), error.message);
process.exit(1);
}
});
program.command("list").description("显示所有可用模板").action(() => {
console.log(chalk.blue.bold("\n📋 可用模板列表:\n"));
templates.forEach((template, index) => {
console.log(chalk.green(`${index + 1}. ${template.name}`));
console.log(chalk.dim(` 描述: ${template.description}`));
console.log(chalk.dim(` 仓库: ${template.repository}`));
if (template.tags && template.tags.length > 0) {
console.log(chalk.dim(` 标签: ${template.tags.join(", ")}`));
}
console.log();
});
});
if (process.argv.length === 2) {
program.help();
}
program.parse();
//# sourceMappingURL=index.js.map