import { z } from 'zod'; import fs from 'fs/promises'; import path from 'path'; import { intro, outro, text, select, isCancel, cancel, group } from '@clack/prompts'; const ConfigSchema = z.object({ name: z.string().min(1, { message: "应用名称不能为空" }), version: z.string().regex(/^\d+\.\d+\.\d+$/, { message: "版本号格式必须为 x.x.x" }), description: z.string().min(1, { message: "应用描述不能为空" }), author: z.object({ name: z.string().min(1, { message: "作者名称不能为空" }), email: z.string().email({ message: "作者邮箱格式不正确" }) }), homeUrl: z.string().url({ message: "URL格式不正确" }), appId: z.string().min(1, { message: "应用ID不能为空" }).regex(/^[a-zA-Z0-9._-]+$/, { message: "应用ID只能包含字母、数字、点、下划线和横线" }), packType: z.enum(['release', 'debug'], { errorMap: () => ({ message: "打包类型必须是 release 或 debug" }) }), pushEmail: z.string().email({ message: "邮箱格式不正确" }) }); type Config = z.infer; async function main() { intro('欢迎使用Cali配置工具'); const config = await group( { name: () => text({ message: '请输入应用名称', validate(value) { if (!value.length) return '应用名称不能为空'; }, }), version: () => text({ message: '请输入应用版本号', validate(value) { if (!/^\d+\.\d+\.\d+$/.test(value)) { return '请输入正确的版本号,例如: 1.0.0'; } }, }), description: () => text({ message: '请输入应用描述', validate(value) { if (!value.length) return '应用描述不能为空'; }, }), authorName: () => text({ message: '请输入作者名称', validate(value) { if (!value.length) return '作者名称不能为空'; }, }), authorEmail: () => text({ message: '请输入作者邮箱', validate(value) { if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) { return '请输入正确的邮箱地址'; } }, }), homeUrl: () => text({ message: '请输入主页URL', validate(value) { try { new URL(value); } catch { return '请输入正确的网址'; } }, }), appId: () => text({ message: '请输入应用ID', validate(value) { if (!value.length) return '应用ID不能为空'; if (!/^[a-zA-Z0-9._-]+$/.test(value)) { return '应用ID只能包含字母、数字、点、下划线和横线'; } }, }), packType: () => select({ message: '请选择打包类型', options: [ { value: 'release', label: 'release' }, { value: 'debug', label: 'debug' }, ], }), pushEmail: () => text({ message: '请输入推送邮箱', validate(value) { if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) { return '请输入正确的邮箱地址'; } }, }), }, { onCancel: () => { cancel('操作已取消'); process.exit(0); }, } ); // 检查是否有任何输入被取消 for (const [key, value] of Object.entries(config)) { if (isCancel(value)) { cancel('操作已取消'); process.exit(0); } } // 重构配置对象以匹配所需格式 const formattedConfig = { name: config.name, version: config.version, description: config.description, author: { name: config.authorName, email: config.authorEmail }, homeUrl: config.homeUrl, appId: config.appId, packType: config.packType, pushEmail: config.pushEmail }; try { // 使用zod验证配置 const result = ConfigSchema.safeParse(formattedConfig); if (!result.success) { cancel('配置验证失败'); result.error.errors.forEach(error => { console.error((` ${error.path.join('.')}: ${error.message} `)); }); process.exit(1); } await fs.writeFile( path.join(process.cwd(), 'config.json'), JSON.stringify(result.data, null, 2) ); outro('配置文件保存成功!'); } catch (error) { cancel('保存配置文件时出错'); if (error instanceof Error) { console.error((` ${error.message} `)); } process.exit(1); } } main().catch(error => { cancel('发生意外错误'); if (error instanceof Error) { console.error((` ${error.message} `)); } process.exit(1); });