UNPKG

@ry-krystal/kicad-converter

Version:

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

227 lines (226 loc) 7.98 kB
/** * JSON转换器 - 核心版本 * 负责在JSON和KiCad数据结构之间进行转换 */ import { performance } from 'perf_hooks'; /** * JSON转换器类 */ export class JsonConverter { /** * 将KiCad数据结构转换为格式化的JSON字符串 * @param symbolLib KiCad符号库数据 * @param options 转换选项 * @returns JSON字符串 */ toJson(symbolLib, options = {}) { const startTime = performance.now(); try { // 数据验证(如果启用) if (options.validateOutput) { const validation = this.validateSymbolLib(symbolLib); if (!validation.isValid) { return { success: false, errors: validation.errors, warnings: validation.warnings }; } } // 数据优化(如果启用) let processedLib = symbolLib; if (options.optimizeOutput) { processedLib = this.optimizeSymbolLib(symbolLib); } // 转换为JSON const jsonString = JSON.stringify(processedLib, null, 2); const endTime = performance.now(); return { success: true, data: jsonString, errors: [], warnings: [], statistics: { processingTime: endTime - startTime, inputSize: this.calculateDataSize(symbolLib), outputSize: jsonString.length, symbolCount: symbolLib.symbols.length, pinCount: symbolLib.symbols.reduce((sum, s) => sum + s.pins.length, 0), propertyCount: symbolLib.symbols.reduce((sum, s) => sum + s.properties.length, 0) } }; } catch (error) { return { success: false, data: undefined, errors: [`JSON转换失败: ${error instanceof Error ? error.message : String(error)}`], warnings: [] }; } } /** * 从JSON字符串解析为KiCad数据结构 * @param jsonString JSON字符串 * @param options 转换选项 * @returns KiCad符号库数据 */ fromJson(jsonString, options = {}) { const startTime = performance.now(); try { // 解析JSON const symbolLib = JSON.parse(jsonString); // 数据验证(如果启用) if (options.validateOutput) { const validation = this.validateSymbolLib(symbolLib); if (!validation.isValid) { return { success: false, errors: validation.errors, warnings: validation.warnings }; } } const endTime = performance.now(); return { success: true, data: symbolLib, errors: [], warnings: [], statistics: { processingTime: endTime - startTime, inputSize: jsonString.length, outputSize: this.calculateDataSize(symbolLib), symbolCount: symbolLib.symbols.length, pinCount: symbolLib.symbols.reduce((sum, s) => sum + s.pins.length, 0), propertyCount: symbolLib.symbols.reduce((sum, s) => sum + s.properties.length, 0) } }; } catch (error) { return { success: false, data: undefined, errors: [`JSON解析失败: ${error instanceof Error ? error.message : String(error)}`], warnings: [] }; } } /** * 验证符号库数据结构 */ validateSymbolLib(symbolLib) { const errors = []; const warnings = []; // 验证基本结构 if (!symbolLib.version) { errors.push('缺少版本信息'); } if (!symbolLib.generator) { warnings.push('缺少生成器信息'); } if (!Array.isArray(symbolLib.symbols)) { errors.push('符号数组无效'); return { isValid: false, errors, warnings }; } // 验证每个符号 symbolLib.symbols.forEach((symbol, index) => { if (!symbol.name) { errors.push(`符号[${index}]缺少名称`); } if (!Array.isArray(symbol.properties)) { errors.push(`符号[${index}]属性数组无效`); } if (!Array.isArray(symbol.pins)) { errors.push(`符号[${index}]引脚数组无效`); } if (!Array.isArray(symbol.graphics)) { errors.push(`符号[${index}]图形数组无效`); } // 验证必需属性 const requiredProps = ['Reference', 'Value']; const propNames = symbol.properties.map(p => p.name); requiredProps.forEach(prop => { if (!propNames.includes(prop)) { warnings.push(`符号[${index}]缺少必需属性: ${prop}`); } }); }); return { isValid: errors.length === 0, errors, warnings }; } /** * 优化符号库数据 */ optimizeSymbolLib(symbolLib) { return { ...symbolLib, symbols: symbolLib.symbols // 按名称排序符号 .sort((a, b) => a.name.localeCompare(b.name)) .map(symbol => ({ ...symbol, // 按名称排序属性 properties: symbol.properties.sort((a, b) => a.name.localeCompare(b.name)), // 按编号排序引脚 pins: symbol.pins.sort((a, b) => { const aNum = parseInt(a.number.text) || 0; const bNum = parseInt(b.number.text) || 0; return aNum - bNum; }) })) }; } /** * 计算数据大小(简化估算) */ calculateDataSize(data) { return JSON.stringify(data).length; } /** * 格式化JSON输出 */ formatJson(data, indent = 2) { return JSON.stringify(data, null, indent); } /** * 压缩JSON输出 */ compactJson(data) { return JSON.stringify(data); } /** * 提取符号统计信息 */ getStatistics(symbolLib) { const stats = { symbolCount: symbolLib.symbols.length, totalPins: 0, totalProperties: 0, totalGraphics: 0, averagePinsPerSymbol: 0, averagePropertiesPerSymbol: 0, pinTypeDistribution: {}, propertyDistribution: {} }; symbolLib.symbols.forEach(symbol => { stats.totalPins += symbol.pins.length; stats.totalProperties += symbol.properties.length; stats.totalGraphics += symbol.graphics.length; // 统计引脚类型分布 symbol.pins.forEach(pin => { stats.pinTypeDistribution[pin.type] = (stats.pinTypeDistribution[pin.type] || 0) + 1; }); // 统计属性分布 symbol.properties.forEach(prop => { stats.propertyDistribution[prop.name] = (stats.propertyDistribution[prop.name] || 0) + 1; }); }); stats.averagePinsPerSymbol = stats.symbolCount > 0 ? stats.totalPins / stats.symbolCount : 0; stats.averagePropertiesPerSymbol = stats.symbolCount > 0 ? stats.totalProperties / stats.symbolCount : 0; return stats; } }