UNPKG

browser-plugin-creator

Version:

A modern scaffolding tool for creating browser extensions with ease

142 lines (141 loc) 5.8 kB
import path from 'path'; import fs from 'fs-extra'; import { execSync } from 'child_process'; import ora from 'ora'; import chalk from 'chalk'; import { TemplateRenderer } from './template'; export class ProjectGenerator { constructor(config) { this.config = config; this.templateRenderer = new TemplateRenderer(config); } async generateProject(options) { const spinner = ora('正在创建项目...').start(); try { // 1. 检查项目目录 await this.checkProjectDirectory(options.name); // 2. 创建项目目录 const projectPath = path.resolve(process.cwd(), options.name); await fs.ensureDir(projectPath); spinner.text = '正在复制模板文件...'; // 3. 复制模板文件 await this.templateRenderer.copyTemplate(options.template, projectPath, options); // 4. 初始化Git仓库 if (options.useGit) { spinner.text = '正在初始化Git仓库...'; await this.initGitRepository(projectPath); } // 5. 安装依赖 if (options.autoInstall) { spinner.text = '正在安装依赖...'; await this.installDependencies(projectPath, options.packageManager); } // 6. 生成最终报告 await this.generateFinalReport(projectPath, options); spinner.succeed(chalk.green(`项目 ${options.name} 创建成功!`)); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); spinner.fail(chalk.red(`项目创建失败: ${errorMessage}`)); throw error; } } async checkProjectDirectory(projectName) { const projectPath = path.resolve(process.cwd(), projectName); if (await fs.pathExists(projectPath)) { const files = await fs.readdir(projectPath); if (files.length > 0) { throw new Error(`目录 ${projectName} 已存在且不为空`); } } // 检查目录名是否有效 if (!/^[a-zA-Z0-9-_]+$/.test(projectName)) { throw new Error('项目名称只能包含字母、数字、连字符和下划线'); } } async initGitRepository(projectPath) { try { execSync('git init', { cwd: projectPath, stdio: 'pipe' }); execSync('git add .', { cwd: projectPath, stdio: 'pipe' }); execSync('git commit -m "Initial commit: Browser extension created with browser-plugin-creator"', { cwd: projectPath, stdio: 'pipe' }); } catch (error) { console.warn(chalk.yellow('Git初始化失败,请手动初始化')); } } async installDependencies(projectPath, packageManager) { try { const command = this.getInstallCommand(packageManager); execSync(command, { cwd: projectPath, stdio: 'pipe' }); } catch (error) { console.warn(chalk.yellow(`依赖安装失败,请手动运行 ${packageManager} install`)); } } getInstallCommand(packageManager) { switch (packageManager) { case 'yarn': return 'yarn install'; case 'pnpm': return 'pnpm install'; default: return 'npm install'; } } async generateFinalReport(projectPath, options) { const report = { name: options.name, template: options.template, path: projectPath, features: options.features, browserSupport: options.browserSupport, nextSteps: [ `cd ${options.name}`, options.autoInstall ? '' : `${options.packageManager} install`, `${options.packageManager} run dev`, '在浏览器中加载扩展进行测试' ].filter(Boolean) }; await fs.writeJson(path.join(projectPath, '.browser-plugin-creator.json'), report, { spaces: 2 }); } async validateTemplate(templateName) { const config = this.config; const templatesPath = config.templatesPath || path.join(__dirname, '../../templates'); const templatePath = path.join(templatesPath, templateName); try { const manifestPath = path.join(templatePath, 'manifest.json'); return await fs.pathExists(manifestPath); } catch { return false; } } async getTemplateInfo(templateName) { const config = this.config; const templatesPath = config.templatesPath || path.join(__dirname, '../../templates'); const templatePath = path.join(templatesPath, templateName); try { const manifestPath = path.join(templatePath, 'manifest.json'); const readmePath = path.join(templatePath, 'README.md'); const [manifest, readme] = await Promise.all([ fs.readJson(manifestPath), await fs.pathExists(readmePath) ? fs.readFile(readmePath, 'utf8') : Promise.resolve('') ]); return { name: templateName, displayName: manifest.name || templateName, description: manifest.description || '', version: manifest.version || '1.0.0', permissions: manifest.permissions || [], readme: readme }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); throw new Error(`无法读取模板信息: ${errorMessage}`); } } }