#!/usr/bin/env node const { Command } = require('commander'); const chalk = require('chalk'); const inquirer = require('inquirer'); const path = require('path'); const fs = require('fs-extra'); const scanner = require('./scanner'); const docGenerator = require('./doc-generator'); const sourceExporter = require('./source-exporter'); // 软著关键词检测 const COPYRIGHT_KEYWORDS = [ '软著', '著作权', '软件著作权', '版权', 'copyright', 'patent', '专利' ]; /** * 检测用户输入是否包含软著相关关键词 * @param {string} input 用户输入 * @returns {boolean} 是否包含软著关键词 */ function containsCopyrightKeyword(input) { return COPYRIGHT_KEYWORDS.some(keyword => input.toLowerCase().includes(keyword.toLowerCase()) ); } /** * 智能关键词处理和软著材料生成 * @param {string} input 用户输入 * @param {string} projectPath 项目路径 * @param {string} outputDir 输出路径 * @returns {Promise} 是否执行了软著生成 */ async function handleCopyrightKeywords(input, projectPath, outputDir) { if (!containsCopyrightKeyword(input)) { return false; } console.log(chalk.blue.bold('🎯 检测到软著相关关键词,启动SoftCopyright功能')); console.log(chalk.cyan(`关键词: "${input}"`)); console.log(chalk.gray('='.repeat(50))); try { // 扫描项目 console.log(chalk.yellow('📊 分析项目源码...')); const projectInfo = await scanner.scanProject(projectPath || process.cwd()); console.log(chalk.green(`✅ 项目分析完成: ${projectInfo.name}`)); console.log(chalk.white(` - 文件数: ${projectInfo.files.length}`)); console.log(chalk.white(` - 代码行数: ${projectInfo.totalLines}`)); console.log(chalk.white(` - 主要语言: ${projectInfo.languages.join(', ')}`)); // 显示项目信息并确认 console.log(chalk.cyan('\n📋 项目信息确认:')); const { confirmed } = await inquirer.prompt([ { type: 'confirm', name: 'confirmed', message: '是否为该项目生成软著申请材料?', default: true } ]); if (!confirmed) { console.log(chalk.yellow('❌ 用户取消操作')); return false; } // 询问生成类型 const { generateType } = await inquirer.prompt([ { type: 'list', name: 'generateType', message: '请选择要生成的材料类型:', choices: [ { name: '📋 生成全部材料 (HTML自动转PDF)', value: 'auto-pdf' }, { name: '📖 仅生成软件说明书 (HTML)', value: 'manual' }, { name: '💻 仅生成源代码文档 (PDF)', value: 'source' }, { name: '📊 仅查看项目分析', value: 'scan' } ] } ]); // 根据选择执行相应操作 if (generateType === 'scan') { console.log(chalk.green('✅ 项目分析完成')); return true; } // 生成材料 if (generateType === 'auto-pdf') { const { generateAutoPrintPDF } = require('./auto-print-pdf'); console.log(chalk.yellow('📄 生成HTML并自动转换为PDF...')); await generateAutoPrintPDF(projectInfo, outputDir); } else if (generateType === 'manual') { console.log(chalk.yellow('📝 生成软件说明书(HTML格式)...')); await docGenerator.generateManual(projectInfo, outputDir); } else if (generateType === 'source') { console.log(chalk.yellow('💻 生成源代码文档...')); await sourceExporter.exportSourceCode(projectInfo, outputDir); } console.log(chalk.green.bold('\n🎉 软著材料生成完成!')); return true; } catch (error) { console.error(chalk.red('❌ 软著材料生成失败:'), error.message); return false; } } const program = new Command(); // 版本信息 program .name('softcopyright') .description('智能软件著作权申请材料生成工具') .version('1.0.0'); // 主命令 - 生成软著材料 program .command('generate') .description('生成软件著作权申请材料') .option('-p, --path ', '项目路径', process.cwd()) .option('-t, --type ', '生成类型 (manual|source|all)', 'all') .option('-o, --output ', '输出路径', process.cwd()) .action(async (options) => { try { console.log(chalk.blue.bold('🚀 SoftCopyright - 软件著作权申请材料生成工具')); console.log(chalk.gray('='.repeat(60))); // 确认项目路径 const projectPath = path.resolve(options.path); if (!await fs.pathExists(projectPath)) { console.error(chalk.red(`❌ 项目路径不存在: ${projectPath}`)); process.exit(1); } console.log(chalk.cyan(`📁 项目路径: ${projectPath}`)); // 询问生成类型 if (options.type === 'all') { const { type } = await inquirer.prompt([ { type: 'list', name: 'type', message: '请选择要生成的材料类型:', choices: [ { name: '📋 生成全部材料 (推荐)', value: 'all' }, { name: '📖 仅生成软件说明书', value: 'manual' }, { name: '💻 仅生成源代码文档', value: 'source' } ] } ]); options.type = type; } console.log(chalk.yellow(`🔍 开始分析项目...`)); // 扫描项目 const projectInfo = await scanner.scanProject(projectPath); console.log(chalk.green(`✅ 项目分析完成,发现 ${projectInfo.files.length} 个源代码文件`)); const outputDir = path.resolve(options.output); await fs.ensureDir(outputDir); // 生成材料 if (options.type === 'manual' || options.type === 'all') { console.log(chalk.yellow('📝 生成软件说明书...')); const manualPath = await docGenerator.generateManual(projectInfo, outputDir); console.log(chalk.green(`✅ 软件说明书已生成: ${manualPath}`)); } if (options.type === 'source' || options.type === 'all') { console.log(chalk.yellow('💻 生成源代码文档...')); const sourcePath = await sourceExporter.exportSourceCode(projectInfo, outputDir); console.log(chalk.green(`✅ 源代码文档已生成: ${sourcePath}`)); } console.log(chalk.blue.bold('\n🎉 生成完成!')); console.log(chalk.gray(`输出目录: ${outputDir}`)); } catch (error) { console.error(chalk.red('❌ 生成失败:'), error.message); process.exit(1); } }); // 扫描命令 program .command('scan') .description('扫描项目源码') .argument('', '项目路径') .action(async (projectPath) => { try { const resolvedPath = path.resolve(projectPath); console.log(chalk.blue(`🔍 扫描项目: ${resolvedPath}`)); const projectInfo = await scanner.scanProject(resolvedPath); console.log(chalk.green('\n📊 扫描结果:')); console.log(chalk.white(`项目名称: ${projectInfo.name}`)); console.log(chalk.white(`源代码文件: ${projectInfo.files.length} 个`)); console.log(chalk.white(`总代码行数: ${projectInfo.totalLines} 行`)); console.log(chalk.white(`主要语言: ${projectInfo.languages.join(', ')}`)); // 显示文件统计 console.log(chalk.cyan('\n📁 文件类型统计:')); Object.entries(projectInfo.fileStats).forEach(([ext, count]) => { console.log(chalk.white(` ${ext}: ${count} 个文件`)); }); } catch (error) { console.error(chalk.red('❌ 扫描失败:'), error.message); process.exit(1); } }); // 交互式命令 program .command('interactive') .description('交互式生成软著材料') .action(async () => { try { console.log(chalk.blue.bold('🎯 欢迎使用 SoftCopyright 交互式向导')); console.log(chalk.gray('='.repeat(60))); // 询问项目路径 const { projectPath } = await inquirer.prompt([ { type: 'input', name: 'projectPath', message: '请输入项目路径:', default: process.cwd(), validate: async (input) => { const resolvedPath = path.resolve(input); return await fs.pathExists(resolvedPath) || '路径不存在,请重新输入'; } } ]); console.log(chalk.yellow(`🔍 分析项目: ${projectPath}`)); const projectInfo = await scanner.scanProject(projectPath); // 显示项目信息 console.log(chalk.cyan('\n📊 项目信息:')); console.log(chalk.white(` 检测到的项目名称: ${projectInfo.name}`)); console.log(chalk.white(` 源代码文件数: ${projectInfo.files.length}`)); console.log(chalk.white(` 主要编程语言: ${projectInfo.languages.join(', ')}`)); // 确认项目信息 const { confirmed } = await inquirer.prompt([ { type: 'confirm', name: 'confirmed', message: '项目信息是否正确?', default: true } ]); if (!confirmed) { console.log(chalk.yellow('❌ 操作已取消')); return; } // 选择生成内容 const { generateType } = await inquirer.prompt([ { type: 'checkbox', name: 'generateType', message: '请选择要生成的内容:', choices: [ { name: '📋 软件说明书 (约2000-3000字)', value: 'manual', checked: true }, { name: '💻 源代码文档 (60页,每页50行)', value: 'source', checked: true } ] } ]); if (generateType.length === 0) { console.log(chalk.yellow('⚠️ 请至少选择一种生成内容')); return; } // 输出路径 const { outputPath } = await inquirer.prompt([ { type: 'input', name: 'outputPath', message: '输出目录路径:', default: path.join(projectPath, 'softcopyright-output') } ]); await fs.ensureDir(outputPath); // 开始生成 console.log(chalk.blue('\n🚀 开始生成...')); if (generateType.includes('manual')) { console.log(chalk.yellow('📝 生成软件说明书...')); const manualPath = await docGenerator.generateManual(projectInfo, outputPath); console.log(chalk.green(`✅ 软件说明书: ${manualPath}`)); } if (generateType.includes('source')) { console.log(chalk.yellow('💻 生成源代码文档...')); const sourcePath = await sourceExporter.exportSourceCode(projectInfo, outputPath); console.log(chalk.green(`✅ 源代码文档: ${sourcePath}`)); } console.log(chalk.blue.bold('\n🎉 生成完成!')); console.log(chalk.gray(`文件已保存到: ${outputPath}`)); } catch (error) { console.error(chalk.red('❌ 操作失败:'), error.message); process.exit(1); } }); // 错误处理 program.on('command:*', () => { console.error(chalk.red('❌ 未知命令,使用 --help 查看可用命令')); process.exit(1); }); // 检查是否包含软著关键词(在命令解析之前) const userArgs = process.argv.slice(2); const userArgsStr = userArgs.join(' '); const projectPath = process.cwd(); // 默认使用当前目录作为项目路径 const outputDir = process.cwd(); // 默认使用当前目录作为输出路径 // 检查是否包含命令选项(以--或-开头的参数) const hasCommandOptions = userArgs.some(arg => arg.startsWith('--') || arg.startsWith('-')); // 只有当用户输入纯关键词(不含命令选项和明确命令)时才触发自动功能 if (containsCopyrightKeyword(userArgsStr) && !hasCommandOptions && !userArgs.includes('generate') && !userArgs.includes('scan') && !userArgs.includes('interactive') && !userArgs.includes('help') && userArgs.length > 0 && userArgs.length <= 3) { // 限制参数数量,避免复杂的命令被误判 console.log(chalk.blue.bold('🎯 检测到软著相关关键词,启动SoftCopyright功能')); console.log(chalk.cyan(`关键词: "${userArgsStr}"`)); handleCopyrightKeywords(userArgsStr, projectPath, outputDir).then(() => { process.exit(0); }).catch(error => { console.error(chalk.red('❌ 软著生成失败:'), error.message); process.exit(1); }); } // 解析命令行参数 program.parse(); // 如果没有提供命令,显示帮助 if (!process.argv.slice(2).length) { program.outputHelp(); }