diff --git a/lib/convert-easyeda-json-to-tscircuit-soup-json.ts b/lib/convert-easyeda-json-to-tscircuit-soup-json.ts index c9d763d1..df0e3881 100644 --- a/lib/convert-easyeda-json-to-tscircuit-soup-json.ts +++ b/lib/convert-easyeda-json-to-tscircuit-soup-json.ts @@ -438,14 +438,43 @@ export const convertEasyEdaJsonToCircuitJson = ( (shape): shape is z.infer => shape.type === "PAD", ) const pins = easyEdaJson.dataStr.shape.filter((shape) => shape.type === "PIN") + const footprintPinNumbers = new Set( + pads.map((pad) => String(pad.number ?? "").trim()), + ) + + const matchedPinsByPad = pads.map((pad) => { + const padNumber = String(pad.number ?? "").trim() + const exactPinNumberMatch = pins.find( + (pin) => String(pin.pinNumber).trim() === padNumber, + ) + if (exactPinNumberMatch) return exactPinNumberMatch + + // Some EasyEDA footprints use a functional pad name (for example "CD") + // where the symbol uses a numeric pin with that label. + if (!padNumber || /^\d+$/.test(padNumber)) return undefined + + const normalizedPadNumber = normalizeSymbolName(padNumber) + const pinLabelMatches = pins.filter( + (pin) => normalizeSymbolName(pin.label) === normalizedPadNumber, + ) + if (pinLabelMatches.length !== 1) return undefined + + const matchedPinNumber = String(pinLabelMatches[0]!.pinNumber).trim() + if (!/^\d+$/.test(matchedPinNumber)) return undefined + if (footprintPinNumbers.has(matchedPinNumber)) return undefined + + return pinLabelMatches[0] + }) // Prepare pin labels for normalization - const pinLabelSets = pads.map((pad) => { + const pinLabelSets = pads.map((pad, index) => { const labels = [] - if (pad.number) labels.push(pad.number.toString()) + const matchedPin = matchedPinsByPad[index] + + if (matchedPin) labels.push(matchedPin.pinNumber.toString()) + else if (pad.number) labels.push(pad.number.toString()) - const pin = pins.find((p) => p.pinNumber === pad.number) - if (pin) labels.push(normalizeSymbolName(pin.label)) + if (matchedPin) labels.push(normalizeSymbolName(matchedPin.label)) return labels }) @@ -453,7 +482,9 @@ export const convertEasyEdaJsonToCircuitJson = ( // Repeated EasyEDA pad numbers are multiple copper geometries for one // logical pin. Unnumbered pads remain independent. const padNumberKeys = pads.map((pad, index) => { - const padNumber = String(pad.number ?? "").trim() + const padNumber = String( + matchedPinsByPad[index]?.pinNumber ?? pad.number ?? "", + ).trim() return padNumber ? `number:${padNumber}` : `index:${index}` }) const uniquePinLabelSets: string[][] = [] diff --git a/tests/convert-to-ts/C393941-card-detect-pin-mapping-repro.test.ts b/tests/convert-to-ts/C393941-card-detect-pin-mapping-repro.test.ts new file mode 100644 index 00000000..d5c5f419 --- /dev/null +++ b/tests/convert-to-ts/C393941-card-detect-pin-mapping-repro.test.ts @@ -0,0 +1,45 @@ +import { expect, test } from "bun:test" +import { convertCircuitJsonToSchematicSvg } from "circuit-to-svg" +import { EasyEdaJsonSchema } from "lib/schemas/easy-eda-json-schema" +import { convertBetterEasyToTsx } from "lib/websafe/convert-to-typescript-component" +import { runTscircuitCode } from "tscircuit" +import chipRawEasy from "../assets/C393941.raweasy.json" +import { wrapTsxWithBoardFor3dSnapshot } from "../fixtures/wrap-tsx-with-board-for-3d-snapshot" + +test("keeps the C393941 card-detect pad mapped to schematic pin 9", async () => { + const betterEasy = EasyEdaJsonSchema.parse(chipRawEasy) + const schematicCardDetectPin = betterEasy.dataStr.shape.find( + (shape) => + shape.type === "PIN" && shape.pinNumber === 9 && shape.label === "CD", + ) + const footprintCardDetectPad = betterEasy.packageDetail.dataStr.shape.find( + (shape) => shape.type === "PAD" && shape.number === "CD", + ) + + expect(schematicCardDetectPin).toBeDefined() + expect(footprintCardDetectPad).toBeDefined() + + const result = await convertBetterEasyToTsx({ betterEasy }) + const circuitJson = await runTscircuitCode( + wrapTsxWithBoardFor3dSnapshot(result), + ) + const sourcePorts = circuitJson.filter( + (element) => element.type === "source_port", + ) + + expect(convertCircuitJsonToSchematicSvg(circuitJson)).toMatchSvgSnapshot( + import.meta.path, + "C393941-card-detect-pin-mapping-repro", + ) + + expect(result).toContain('pin9: ["CD"]') + expect(result).not.toContain('pin14: ["CD"]') + expect(result).toContain(' port.port_hints?.includes("CD")), + ).toMatchObject({ + name: "CD", + pin_number: 9, + }) + expect(sourcePorts.find((port) => port.pin_number === 14)).toBeUndefined() +}, 50000) diff --git a/tests/convert-to-ts/C393941-to-ts.test.ts b/tests/convert-to-ts/C393941-to-ts.test.ts index 3c034c45..a4f8868e 100644 --- a/tests/convert-to-ts/C393941-to-ts.test.ts +++ b/tests/convert-to-ts/C393941-to-ts.test.ts @@ -33,11 +33,11 @@ it("should convert C393941 into typescript file", async () => { pin6: ["VSS"], pin7: ["DAT0"], pin8: ["DAT1"], + pin9: ["CD"], pin10: ["pin10"], pin11: ["pin11"], pin12: ["pin12"], - pin13: ["pin13"], - pin14: ["CD"] + pin13: ["pin13"] } as const const pinAttributes = { @@ -67,7 +67,7 @@ it("should convert C393941 into typescript file", async () => { - + diff --git a/tests/convert-to-ts/__snapshots__/C393941-card-detect-pin-mapping-repro.snap.svg b/tests/convert-to-ts/__snapshots__/C393941-card-detect-pin-mapping-repro.snap.svg new file mode 100644 index 00000000..faa821b2 --- /dev/null +++ b/tests/convert-to-ts/__snapshots__/C393941-card-detect-pin-mapping-repro.snap.svg @@ -0,0 +1,12 @@ +TF PUSH1DAT223CMD4VDD5CLX6VSS7DAT08DAT19CD10111213