@ry-krystal/kicad-converter
Version:
专业的KiCad符号文件与JSON互转工具
227 lines (226 loc) • 7.98 kB
JavaScript
/**
* 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;
}
}