UNPKG

@ry-krystal/kicad-converter

Version:

专业的KiCad符号文件与JSON互转工具

287 lines (274 loc) 9.35 kB
#!/usr/bin/env node /** * KiCad转换器命令行工具主入口 * 提供统一的CLI界面和智能转换选择 */ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs'; import { join, extname, basename, dirname } from 'path'; import { fileURLToPath } from 'url'; import { performance } from 'perf_hooks'; // 导入核心转换器 import { convertKiCadToJson, convertJsonToKicad } from '../core/index.js'; // 导入增强版转换器 import { enhancedKicadToJson, enhancedJsonToKicad } from '../enhanced/index.js'; // 导入工具函数 import { parseCliArgs, createLogger } from './utils/index.js'; import { batchCommand } from './commands/batch.js'; import { validateCommand } from './commands/validate.js'; /** * 显示帮助信息 */ function showHelp() { console.log(` KiCad转换器 - 专业的KiCad符号文件与JSON互转工具 使用方法: kicad-converter [选项] [输入文件] 选项: -i, --input <文件> 输入文件路径 -o, --output <文件> 输出文件路径 -m, --mode <模式> 转换模式: auto|to-json|to-kicad (默认: auto) -e, --engine <引擎> 转换引擎: core|enhanced|auto (默认: auto) 转换选项: -b, --batch 批量处理模式 -r, --recursive 递归处理子目录 --validate 启用数据验证 --optimize 启用输出优化 --stats 显示详细统计信息 输出选项: -v, --verbose 详细输出模式 -q, --quiet 静默模式 -h, --help 显示此帮助信息 --version 显示版本信息 示例: # 自动检测并转换单个文件 kicad-converter input.kicad_sym # KiCad转JSON (指定输出文件) kicad-converter -i input.kicad_sym -o output.json # JSON转KiCad (指定模式) kicad-converter -m to-kicad input.json # 批量转换目录 kicad-converter --batch ./symbols/ # 使用增强版引擎并显示统计 kicad-converter -e enhanced --stats input.kicad_sym # 验证文件 kicad-converter --validate input.kicad_sym # 递归批量处理子目录 kicad-converter --batch --recursive ./project/symbols/ 开发模式 (项目内使用): npm run convert # 通用转换命令 npm run kicad-to-json # KiCad转JSON npm run json-to-kicad # JSON转KiCad npm run batch # 批量处理 npm run validate # 验证文件 npm run stats # 显示统计 `); } /** * 显示版本信息 */ function showVersion() { const currentDir = dirname(fileURLToPath(import.meta.url)); const packagePath = join(currentDir, '../../package.json'); try { const pkg = JSON.parse(readFileSync(packagePath, 'utf8')); console.log(`KiCad转换器 v${pkg.version}`); console.log(`Node.js ${process.version}`); } catch { console.log('KiCad转换器'); } } /** * 智能选择转换引擎 */ function selectEngine(options) { if (options.engine === 'core') return 'core'; if (options.engine === 'enhanced') return 'enhanced'; // 自动选择:复杂操作使用增强版,简单操作使用核心版 if (options.batch || options.optimize || options.stats) { return 'enhanced'; } return 'core'; // 默认使用核心版,更稳定 } /** * 自动检测文件类型和转换模式 */ function detectMode(inputFile, mode) { if (mode === 'to-json') return 'to-json'; if (mode === 'to-kicad') return 'to-kicad'; const ext = extname(inputFile).toLowerCase(); if (ext === '.kicad_sym') return 'to-json'; if (ext === '.json') return 'to-kicad'; // 默认转换为JSON return 'to-json'; } /** * 生成输出文件路径 */ function generateOutputPath(inputFile, mode, outputFile) { if (outputFile) return outputFile; const dir = dirname(inputFile); const name = basename(inputFile, extname(inputFile)); if (mode === 'to-json') { return join(dir, `${name}.json`); } else { return join(dir, `${name}.kicad_sym`); } } /** * 单文件转换 */ async function convertSingleFile(options) { if (!options.input) { console.error('错误: 缺少输入文件'); return false; } if (!existsSync(options.input)) { console.error(`错误: 输入文件不存在: ${options.input}`); return false; } const logger = createLogger(options.verbose, options.quiet); const startTime = performance.now(); try { // 检测转换模式 const mode = detectMode(options.input, options.mode); const engine = selectEngine(options); const outputPath = generateOutputPath(options.input, mode, options.output); logger.info(`使用${engine === 'enhanced' ? '增强版' : '核心版'}引擎`); logger.info(`转换模式: ${mode === 'to-json' ? 'KiCad→JSON' : 'JSON→KiCad'}`); logger.info(`输入文件: ${options.input}`); logger.info(`输出文件: ${outputPath}`); // 读取输入文件 const content = readFileSync(options.input, 'utf8'); // 执行转换 let result; if (mode === 'to-json') { if (engine === 'enhanced') { result = await enhancedKicadToJson(content, { validateOutput: options.validate, optimizeOutput: options.optimize, verbose: options.verbose, quiet: options.quiet }); } else { result = await convertKiCadToJson(content, { validateOutput: options.validate, optimizeOutput: options.optimize, verbose: options.verbose, quiet: options.quiet }); } } else { if (engine === 'enhanced') { result = await enhancedJsonToKicad(content, { validateOutput: options.validate, verbose: options.verbose, quiet: options.quiet }); } else { result = await convertJsonToKicad(content, { validateOutput: options.validate, verbose: options.verbose, quiet: options.quiet }); } } // 检查转换结果 if (!result.success) { console.error('转换失败:'); result.errors.forEach(err => console.error(` - ${err}`)); return false; } // 确保输出目录存在 const outputDir = dirname(outputPath); if (!existsSync(outputDir)) { mkdirSync(outputDir, { recursive: true }); } // 写入输出文件 writeFileSync(outputPath, result.data); const endTime = performance.now(); const duration = ((endTime - startTime) / 1000).toFixed(2); logger.success(`转换完成! 耗时: ${duration}秒`); // 显示统计信息 if (options.stats && result.statistics) { const stats = result.statistics; console.log('\\n📊 统计信息:'); console.log(` 处理时间: ${stats.processingTime.toFixed(2)}ms`); console.log(` 输入大小: ${stats.inputSize} 字节`); console.log(` 输出大小: ${stats.outputSize} 字节`); if (stats.symbolCount) { console.log(` 符号数量: ${stats.symbolCount}`); console.log(` 引脚数量: ${stats.pinCount}`); console.log(` 属性数量: ${stats.propertyCount}`); } } // 显示警告 if (result.warnings.length > 0) { console.log('\\n⚠️ 警告:'); result.warnings.forEach(warn => console.log(` - ${warn}`)); } return true; } catch (error) { console.error(`转换过程中发生错误: ${error instanceof Error ? error.message : String(error)}`); return false; } } /** * 主函数 */ async function main() { const options = parseCliArgs(); // 处理特殊命令 if (options.help) { showHelp(); process.exit(0); } if (options.version) { showVersion(); process.exit(0); } // 路由到相应的命令处理器 let success = false; try { if (options.batch) { success = await batchCommand(options); } else if (options.validate && !options.input) { success = await validateCommand(options); } else { success = await convertSingleFile(options); } } catch (error) { console.error(`执行失败: ${error instanceof Error ? error.message : String(error)}`); success = false; } process.exit(success ? 0 : 1); } // 处理未捕获的异常 process.on('uncaughtException', (error) => { console.error('未捕获的异常:', error); process.exit(1); }); process.on('unhandledRejection', (reason, _promise) => { console.error('未处理的Promise拒绝:', reason); process.exit(1); }); // 运行主函数 if (import.meta.url === `file://${process.argv[1]}`) { main().catch(console.error); } export { main };