Commit c66f287

Ansari <ping@ansari.wtf>
2026-08-24 10:34:14
making connections ;)
1 parent 385d856
internal/component.go
@@ -11,6 +11,7 @@ type Circuit struct {
 	Version               string      `yaml:"cddx2yamlVersion"`
 	CircuitDiagramVersion string      `yaml:"circuitDiagramVersion"`
 	Components            []Component `yaml:"components"`
+	Connections           [][]string  `yaml:"connections"`
 }
 
 type Component struct {
@@ -34,12 +35,18 @@ func documentFromXML(c *xmlCircuit) *Circuit {
 	counters := make(idCounters)
 	components := make([]Component, 0, len(c.Components))
 	for _, xc := range c.Components {
-		components = append(components, xc.toComponent(types, counters))
+		comp := xc.toComponent(types, counters)
+		for _, cn := range xc.Conns {
+			comp.addPin(xc.resolvePin(cn.Pin))
+		}
+		components = append(components, comp)
 	}
+
 	return &Circuit{
 		Version:               "0.1",
 		CircuitDiagramVersion: c.Version,
 		Components:            components,
+		Connections:           collectConnections(c.Components, components),
 	}
 }
 
@@ -74,7 +81,7 @@ func (c xmlComponent) toComponent(types typeCatalog, counters idCounters) Compon
 	return Component{
 		ID:    counters.next(idPrefix(typeName)),
 		Type:  typeName,
-		Label: label, 
+		Label: label,
 		Value: c.electricalValue(),
 		Pins:  c.pins(),
 	}
@@ -100,7 +107,7 @@ func (c xmlComponent) electricalValue() string {
 func (c xmlComponent) pins() []string {
 	pinByIndex := make(map[int]string)
 	for _, p := range c.Props {
-		idx, ok := pinIndexFromPropKey(p.Key)
+		idx, ok := pinIndex(p.Key)
 		if !ok {
 			continue
 		}
@@ -118,6 +125,7 @@ func (c xmlComponent) pins() []string {
 	for _, idx := range indices {
 		name := pinByIndex[idx]
 		if seen[name] {
+			fmt.Printf("Warning: duplicate pin name %q for component %q\n", name, c.DefinitionID)
 			continue
 		}
 		seen[name] = true
@@ -126,8 +134,8 @@ func (c xmlComponent) pins() []string {
 	return pins
 }
 
-func pinIndexFromPropKey(key string) (int, bool) {
-	for _, prefix := range []string{"p", "#"} {
+func pinIndex(key string) (int, bool) {
+	for _, prefix := range []string{"pin", "p", "#"} {
 		rest, ok := strings.CutPrefix(key, prefix)
 		if !ok {
 			continue
internal/connections.go
@@ -0,0 +1,71 @@
+package internal
+
+import (
+	"fmt"
+	"slices"
+	"strconv"
+)
+
+type netRef struct {
+	componentID string
+	pin         string
+}
+
+func (r netRef) String() string {
+	return r.componentID + "." + r.pin
+}
+
+func (c xmlComponent) resolvePin(pt string) string {
+	idx, ok := pinIndex(pt)
+	if !ok {
+		return pt
+	}
+	if v, ok := c.prop("p" + strconv.Itoa(idx)); ok && v != "" {
+		return v
+	}
+	if v, ok := c.prop("#" + strconv.Itoa(idx)); ok && v != "" {
+		return v
+	}
+	return pt
+}
+
+func (c *Component) addPin(name string) {
+	if name == "" {
+		return
+	}
+	if slices.Contains(c.Pins, name) {
+		return
+	}
+	c.Pins = append(c.Pins, name)
+}
+
+func collectConnections(xmlComps []xmlComponent, components []Component) [][]string {
+	nets := make(map[string][]netRef)
+	var order []string
+
+	for i, xc := range xmlComps {
+		id := components[i].ID
+		for _, cn := range xc.Conns {
+			pin := xc.resolvePin(cn.Pin)
+			if _, seen := nets[cn.ID]; !seen {
+				order = append(order, cn.ID)
+			}
+			nets[cn.ID] = append(nets[cn.ID], netRef{componentID: id, pin: pin})
+		}
+	}
+
+	connections := make([][]string, 0, len(order))
+	for _, netID := range order {
+		refs := nets[netID]
+		if len(refs) < 2 {
+			fmt.Printf("Warning: Circuit has a dangling connection %v\n", refs)
+			continue
+		}
+		row := make([]string, len(refs))
+		for i, ref := range refs {
+			row[i] = ref.String()
+		}
+		connections = append(connections, row)
+	}
+	return connections
+}
internal/utils.go
@@ -1,9 +0,0 @@
-package internal
-
-func Set(items ...string) map[string]bool {
-	m := make(map[string]bool, len(items))
-	for _, it := range items {
-		m[it] = true
-	}
-	return m
-}
go.mod
@@ -1,3 +1,5 @@
 module cddx2yaml
 
 go 1.26.5
+
+require gopkg.in/yaml.v3 v3.0.1
go.sum
@@ -0,0 +1,4 @@
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=