UNPKG

@typecad/schematic

Version:

Generate KiCAD schematics from your typeCAD project

114 lines (95 loc) 4.54 kB
import { Schematic, Component, Node } from './types'; import { KiCAD } from "./kicad"; import fs from "node:fs"; import SExpr from "s-expression.js"; import Handlebars from "handlebars"; import { randomUUID } from "node:crypto"; import { SymbolLibraryManager } from "./symbol-library-manager"; import { KiCADSchematic, schematic_template as main_schematic_template, GRID_UNIT_MM, PAGE_WIDTH_MM, PAGE_HEIGHT_MM, label_template as main_label_template } from "./kicad-schematic"; const S = new SExpr(); function generateSymLibTable(sheetname: string): void { try { // Check if build/lib directory exists and get all .kicad_sym files const libDir = './build/lib'; if (!fs.existsSync(libDir)) { console.log('📚 No lib directory found, skipping sym-lib-table generation'); return; } const files = fs.readdirSync(libDir); const kicadSymFiles = files.filter(file => file.endsWith('.kicad_sym')); if (kicadSymFiles.length === 0) { console.log('📚 No .kicad_sym files found, skipping sym-lib-table generation'); return; } // Generate sym-lib-table content let symLibTableContent = '(sym_lib_table\n\t(version 7)\n'; for (const symFile of kicadSymFiles) { const symbolName = symFile.replace('.kicad_sym', ''); symLibTableContent += `\t(lib\n`; symLibTableContent += `\t\t(name "${symbolName}")\n`; symLibTableContent += `\t\t(type "KiCad")\n`; symLibTableContent += `\t\t(uri "\${KIPRJMOD}/lib/${symFile}")\n`; symLibTableContent += `\t\t(options "")\n`; symLibTableContent += `\t\t(descr "")\n`; symLibTableContent += `\t)\n`; } symLibTableContent += ')'; // Write sym-lib-table file in the same directory as the schematic const symLibTablePath = `./build/sym-lib-table`; fs.writeFileSync(symLibTablePath, symLibTableContent); // console.log(`📚 Symbol library table written to ${symLibTablePath} (${kicadSymFiles.length} libraries)`); } catch (err) { console.error("Error generating sym-lib-table:", err); } } export async function schematic(schematicData: Schematic) { // Initialize the Symbol Library Manager ONCE new KiCAD(); // Call constructor first to set kicad_path const symbolManager = new SymbolLibraryManager(); // Now symbolManager can read the path const kicad = new KiCADSchematic(symbolManager); // Pass the manager instance kicad.sheetname = schematicData.Sheetname; // Set sheetname // Deduplicate components by reference to avoid processing the same component twice const processedReferences = new Set<string>(); const uniqueComponents = schematicData.Components.filter(component => { if (!component.reference || processedReferences.has(component.reference)) { return false; } processedReferences.add(component.reference); return true; }); // Update components and collect library symbols implicitly uniqueComponents.forEach(component => { if (component.symbol && !component.dnp) { // Skip DNP components early const symbolInstanceData = kicad.update(component, S); // Pass SExpr instance S if (symbolInstanceData) { // Only push if update was successful kicad.symbols.push(symbolInstanceData); } } }); // Generate labels for nets sequentially for (const node of schematicData.Nodes) { await kicad.net(node); // Wait for each net calculation to complete } // Process no_connect pins kicad.processNoConnectPins(schematicData.Components); let template = Handlebars.compile(main_schematic_template, { noEscape: true }); let output_schematic_data = { lib_symbols: kicad.lib_symbols, symbols: kicad.symbols, labels: kicad.labels, no_connects: kicad.no_connects, uuid: kicad.uuid }; let _schematic = template(output_schematic_data); try { fs.writeFileSync(`./build/${schematicData.Sheetname}.kicad_sch`, _schematic); console.log(`🔣 Schematic written to ./build/${schematicData.Sheetname}.kicad_sch`); // Generate sym-lib-table file generateSymLibTable(schematicData.Sheetname); } catch (err) { console.error("Error writing schematic:", err); process.exit(1); return false; } return true; }