circuit-json-to-tscircuit 0.0.52 → 0.0.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-YC65LHVL.js → chunk-OFR6QZ6I.js} +36 -16
- package/dist/cli/main.js +6 -5
- package/dist/lib/index.js +1 -1
- package/lib/generate-footprint-tsx/convert-vias.ts +34 -0
- package/lib/generate-footprint-tsx.tsx +2 -0
- package/package.json +5 -4
- package/tests/fixtures/create-ti-evm-roundtrip.ts +7 -0
- package/tests/plated-hole-board-layers.test.ts +47 -0
- package/tests/support-pcb-vias.test.tsx +91 -0
- package/tests/ti-evms/__snapshots__/ti-drv8307evm-roundtrip-pcb-comparison.snap.svg +1 -1
- package/tests/ti-evms/__snapshots__/ti-drv8307evm-roundtrip-schematic-comparison.snap.svg +2 -2
- package/tests/ti-evms/__snapshots__/ti-lm251772evm-pd-roundtrip-pcb-comparison.snap.svg +1 -1
- package/tests/ti-evms/__snapshots__/ti-lm251772evm-pd-roundtrip-schematic-comparison.snap.svg +3 -3
- package/tests/ti-evms/__snapshots__/ti-lm5155evm-fly-roundtrip-pcb-comparison.snap.svg +1 -1
- package/tests/ti-evms/__snapshots__/ti-lm5155evm-fly-roundtrip-schematic-comparison.snap.svg +2 -2
- package/tests/ti-evms/__snapshots__/ti-lmg342x-bb-evm-roundtrip-pcb-comparison.snap.svg +1 -1
- package/tests/ti-evms/__snapshots__/ti-lmg342x-bb-evm-roundtrip-schematic-comparison.snap.svg +2 -2
- package/tests/ti-evms/ti-drv8307evm-roundtrip.test.tsx +360 -0
- package/tests/ti-evms/ti-lm251772evm-pd-roundtrip.test.tsx +261 -0
- package/tests/ti-evms/ti-lm5155evm-fly-roundtrip.test.tsx +109 -0
- package/tests/ti-evms/ti-lmg342x-bb-evm-roundtrip.test.tsx +411 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// lib/get-board-using-template.ts
|
|
2
|
-
import { mmStr as
|
|
3
|
-
import { su as
|
|
2
|
+
import { mmStr as mmStr8 } from "@tscircuit/mm";
|
|
3
|
+
import { su as su13 } from "@tscircuit/soup-util";
|
|
4
4
|
|
|
5
5
|
// lib/generate-footprint-tsx/convert-copper-text.ts
|
|
6
6
|
import { su } from "@tscircuit/soup-util";
|
|
@@ -579,11 +579,31 @@ var convertSmtPads = (circuitJson) => {
|
|
|
579
579
|
return elementStrings;
|
|
580
580
|
};
|
|
581
581
|
|
|
582
|
+
// lib/generate-footprint-tsx/convert-vias.ts
|
|
583
|
+
import { mmStr as mmStr7 } from "@tscircuit/mm";
|
|
584
|
+
import { su as su12 } from "@tscircuit/soup-util";
|
|
585
|
+
var convertVias = (circuitJson) => {
|
|
586
|
+
return su12(circuitJson).pcb_via.list().map((via) => {
|
|
587
|
+
const fromLayer = via.from_layer ?? via.layers[0];
|
|
588
|
+
const toLayer = via.to_layer ?? via.layers[via.layers.length - 1];
|
|
589
|
+
if (!fromLayer || !toLayer) {
|
|
590
|
+
throw new Error(`Via ${via.pcb_via_id} has no copper layer endpoints`);
|
|
591
|
+
}
|
|
592
|
+
const legacyTented = "is_tented" in via && typeof via.is_tented === "boolean" ? via.is_tented : void 0;
|
|
593
|
+
const tentedOnTop = via.tented_on_top ?? legacyTented;
|
|
594
|
+
const tentedOnBottom = via.tented_on_bottom ?? legacyTented;
|
|
595
|
+
const tented = tentedOnTop && tentedOnBottom ? "both_sides" : tentedOnTop ? "top_tented" : tentedOnBottom ? "bottom_tented" : "exposed";
|
|
596
|
+
const tentedAttr = tentedOnTop !== void 0 || tentedOnBottom !== void 0 ? ` tented="${tented}"` : "";
|
|
597
|
+
return `<via pcbX="${mmStr7(via.x)}" pcbY="${mmStr7(via.y)}" holeDiameter="${mmStr7(via.hole_diameter)}" outerDiameter="${mmStr7(via.outer_diameter)}" fromLayer="${fromLayer}" toLayer="${toLayer}"${tentedAttr} />`;
|
|
598
|
+
});
|
|
599
|
+
};
|
|
600
|
+
|
|
582
601
|
// lib/generate-footprint-tsx.tsx
|
|
583
602
|
var generateFootprintTsx = (circuitJson) => {
|
|
584
603
|
const converters = [
|
|
585
604
|
convertHoles,
|
|
586
605
|
convertPlatedHoles,
|
|
606
|
+
convertVias,
|
|
587
607
|
convertSmtPads,
|
|
588
608
|
convertSilkscreen,
|
|
589
609
|
convertFabrication,
|
|
@@ -610,21 +630,21 @@ var getBoardUsingTemplate = ({
|
|
|
610
630
|
circuitJson,
|
|
611
631
|
componentName
|
|
612
632
|
}) => {
|
|
613
|
-
const pcbBoard =
|
|
633
|
+
const pcbBoard = su13(circuitJson).pcb_board.list()[0];
|
|
614
634
|
const boardProps = [];
|
|
615
635
|
if (pcbBoard) {
|
|
616
636
|
if (pcbBoard.width !== void 0) {
|
|
617
|
-
boardProps.push(`width="${
|
|
637
|
+
boardProps.push(`width="${mmStr8(pcbBoard.width)}"`);
|
|
618
638
|
}
|
|
619
639
|
if (pcbBoard.height !== void 0) {
|
|
620
|
-
boardProps.push(`height="${
|
|
640
|
+
boardProps.push(`height="${mmStr8(pcbBoard.height)}"`);
|
|
621
641
|
}
|
|
622
642
|
if (pcbBoard.outline && pcbBoard.outline.length > 0) {
|
|
623
643
|
const points = pcbBoard.outline.map((p) => `{ x: ${p.x}, y: ${p.y} }`).join(", ");
|
|
624
644
|
boardProps.push(`outline={[${points}]}`);
|
|
625
645
|
}
|
|
626
646
|
if (pcbBoard.thickness !== void 0) {
|
|
627
|
-
boardProps.push(`thickness="${
|
|
647
|
+
boardProps.push(`thickness="${mmStr8(pcbBoard.thickness)}"`);
|
|
628
648
|
}
|
|
629
649
|
if (pcbBoard.num_layers !== void 0) {
|
|
630
650
|
boardProps.push(`layers={${pcbBoard.num_layers}}`);
|
|
@@ -661,18 +681,18 @@ ${componentName ? `export default ${componentName}` : ""}
|
|
|
661
681
|
};
|
|
662
682
|
|
|
663
683
|
// lib/generate-symbol-tsx.ts
|
|
664
|
-
import { su as
|
|
684
|
+
import { su as su14 } from "@tscircuit/soup-util";
|
|
665
685
|
var escapeJsxText2 = (text) => text.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
666
686
|
var generateSymbolTsx = (circuitJson) => {
|
|
667
|
-
const schematicArcs =
|
|
668
|
-
const schematicLines =
|
|
669
|
-
const schematicPaths =
|
|
670
|
-
const schematicTexts =
|
|
671
|
-
const schematicCircles =
|
|
672
|
-
const schematicBoxes =
|
|
673
|
-
const schematicRects =
|
|
674
|
-
const schematicTables =
|
|
675
|
-
const schematicTableCells =
|
|
687
|
+
const schematicArcs = su14(circuitJson).schematic_arc.list();
|
|
688
|
+
const schematicLines = su14(circuitJson).schematic_line.list();
|
|
689
|
+
const schematicPaths = su14(circuitJson).schematic_path.list();
|
|
690
|
+
const schematicTexts = su14(circuitJson).schematic_text.list();
|
|
691
|
+
const schematicCircles = su14(circuitJson).schematic_circle.list();
|
|
692
|
+
const schematicBoxes = su14(circuitJson).schematic_box.list();
|
|
693
|
+
const schematicRects = su14(circuitJson).schematic_rect.list();
|
|
694
|
+
const schematicTables = su14(circuitJson).schematic_table.list();
|
|
695
|
+
const schematicTableCells = su14(circuitJson).schematic_table_cell.list();
|
|
676
696
|
const elementStrings = [];
|
|
677
697
|
for (const arc of schematicArcs) {
|
|
678
698
|
const center = arc.center ?? { x: 0, y: 0 };
|
package/dist/cli/main.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
convertCircuitJsonToTscircuit
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-OFR6QZ6I.js";
|
|
5
5
|
|
|
6
6
|
// cli/main.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -16,7 +16,7 @@ var package_default = {
|
|
|
16
16
|
"./cli": "./dist/cli/main.js"
|
|
17
17
|
},
|
|
18
18
|
type: "module",
|
|
19
|
-
version: "0.0.
|
|
19
|
+
version: "0.0.53",
|
|
20
20
|
repository: {
|
|
21
21
|
type: "git",
|
|
22
22
|
url: "https://github.com/tscircuit/circuit-json-to-tscircuit.git"
|
|
@@ -37,14 +37,15 @@ var package_default = {
|
|
|
37
37
|
"@types/react": "18",
|
|
38
38
|
"@types/react-dom": "18",
|
|
39
39
|
"bun-match-svg": "^0.0.15",
|
|
40
|
-
"circuit-json": "^0.0.
|
|
40
|
+
"circuit-json": "^0.0.507",
|
|
41
41
|
"circuit-to-svg": "^0.0.353",
|
|
42
42
|
commander: "^13.1.0",
|
|
43
43
|
prettier: "^3.9.5",
|
|
44
44
|
shiki: "^4.3.1",
|
|
45
45
|
"stack-svgs": "^0.0.1",
|
|
46
|
-
tscircuit: "^0.0.
|
|
47
|
-
tsup: "^8.3.5"
|
|
46
|
+
tscircuit: "^0.0.2696",
|
|
47
|
+
tsup: "^8.3.5",
|
|
48
|
+
zod: "^3.25.76"
|
|
48
49
|
},
|
|
49
50
|
peerDependencies: {
|
|
50
51
|
typescript: "^5.0.0"
|
package/dist/lib/index.js
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { mmStr } from "@tscircuit/mm"
|
|
2
|
+
import { su } from "@tscircuit/soup-util"
|
|
3
|
+
import type { FootprintElementConverter } from "./converter-types"
|
|
4
|
+
|
|
5
|
+
export const convertVias: FootprintElementConverter = (circuitJson) => {
|
|
6
|
+
return su(circuitJson)
|
|
7
|
+
.pcb_via.list()
|
|
8
|
+
.map((via) => {
|
|
9
|
+
const fromLayer = via.from_layer ?? via.layers[0]
|
|
10
|
+
const toLayer = via.to_layer ?? via.layers[via.layers.length - 1]
|
|
11
|
+
if (!fromLayer || !toLayer) {
|
|
12
|
+
throw new Error(`Via ${via.pcb_via_id} has no copper layer endpoints`)
|
|
13
|
+
}
|
|
14
|
+
const legacyTented =
|
|
15
|
+
"is_tented" in via && typeof via.is_tented === "boolean"
|
|
16
|
+
? via.is_tented
|
|
17
|
+
: undefined
|
|
18
|
+
const tentedOnTop = via.tented_on_top ?? legacyTented
|
|
19
|
+
const tentedOnBottom = via.tented_on_bottom ?? legacyTented
|
|
20
|
+
const tented =
|
|
21
|
+
tentedOnTop && tentedOnBottom
|
|
22
|
+
? "both_sides"
|
|
23
|
+
: tentedOnTop
|
|
24
|
+
? "top_tented"
|
|
25
|
+
: tentedOnBottom
|
|
26
|
+
? "bottom_tented"
|
|
27
|
+
: "exposed"
|
|
28
|
+
const tentedAttr =
|
|
29
|
+
tentedOnTop !== undefined || tentedOnBottom !== undefined
|
|
30
|
+
? ` tented="${tented}"`
|
|
31
|
+
: ""
|
|
32
|
+
return `<via pcbX="${mmStr(via.x)}" pcbY="${mmStr(via.y)}" holeDiameter="${mmStr(via.hole_diameter)}" outerDiameter="${mmStr(via.outer_diameter)}" fromLayer="${fromLayer}" toLayer="${toLayer}"${tentedAttr} />`
|
|
33
|
+
})
|
|
34
|
+
}
|
|
@@ -11,6 +11,7 @@ import { convertPlatedHoles } from "./generate-footprint-tsx/convert-plated-hole
|
|
|
11
11
|
import { convertSilkscreen } from "./generate-footprint-tsx/convert-silkscreen"
|
|
12
12
|
import { convertSilkscreenText } from "./generate-footprint-tsx/convert-silkscreen-text"
|
|
13
13
|
import { convertSmtPads } from "./generate-footprint-tsx/convert-smt-pads"
|
|
14
|
+
import { convertVias } from "./generate-footprint-tsx/convert-vias"
|
|
14
15
|
|
|
15
16
|
export const generateFootprintTsx = (
|
|
16
17
|
circuitJson: AnyCircuitElement[],
|
|
@@ -18,6 +19,7 @@ export const generateFootprintTsx = (
|
|
|
18
19
|
const converters: FootprintElementConverter[] = [
|
|
19
20
|
convertHoles,
|
|
20
21
|
convertPlatedHoles,
|
|
22
|
+
convertVias,
|
|
21
23
|
convertSmtPads,
|
|
22
24
|
convertSilkscreen,
|
|
23
25
|
convertFabrication,
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"./cli": "./dist/cli/main.js"
|
|
7
7
|
},
|
|
8
8
|
"type": "module",
|
|
9
|
-
"version": "0.0.
|
|
9
|
+
"version": "0.0.54",
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
12
12
|
"url": "https://github.com/tscircuit/circuit-json-to-tscircuit.git"
|
|
@@ -27,14 +27,15 @@
|
|
|
27
27
|
"@types/react": "18",
|
|
28
28
|
"@types/react-dom": "18",
|
|
29
29
|
"bun-match-svg": "^0.0.15",
|
|
30
|
-
"circuit-json": "^0.0.
|
|
30
|
+
"circuit-json": "^0.0.507",
|
|
31
31
|
"circuit-to-svg": "^0.0.353",
|
|
32
32
|
"commander": "^13.1.0",
|
|
33
33
|
"prettier": "^3.9.5",
|
|
34
34
|
"shiki": "^4.3.1",
|
|
35
35
|
"stack-svgs": "^0.0.1",
|
|
36
|
-
"tscircuit": "^0.0.
|
|
37
|
-
"tsup": "^8.3.5"
|
|
36
|
+
"tscircuit": "^0.0.2696",
|
|
37
|
+
"tsup": "^8.3.5",
|
|
38
|
+
"zod": "^3.25.76"
|
|
38
39
|
},
|
|
39
40
|
"peerDependencies": {
|
|
40
41
|
"typescript": "^5.0.0"
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { expect } from "bun:test"
|
|
1
2
|
import { readFile } from "node:fs/promises"
|
|
2
3
|
import { join } from "node:path"
|
|
3
4
|
import { gunzipSync } from "node:zlib"
|
|
@@ -36,6 +37,12 @@ export async function createTiEvmRoundtrip({
|
|
|
36
37
|
generatedTscircuit,
|
|
37
38
|
)) as CircuitJson
|
|
38
39
|
|
|
40
|
+
expect(
|
|
41
|
+
renderedCircuitJson.filter((element) => element.type === "pcb_via"),
|
|
42
|
+
).toHaveLength(
|
|
43
|
+
sourceCircuitJson.filter((element) => element.type === "pcb_via").length,
|
|
44
|
+
)
|
|
45
|
+
|
|
39
46
|
const sourcePcbSvg = convertCircuitJsonToPcbSvg(sourceCircuitJson, {
|
|
40
47
|
matchBoardAspectRatio: true,
|
|
41
48
|
})
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { convertCircuitJsonToTscircuit } from "lib"
|
|
3
|
+
import { runTscircuitCode } from "tscircuit"
|
|
4
|
+
|
|
5
|
+
test("through-hole ports use only layers present in the converted board", async () => {
|
|
6
|
+
for (const num_layers of [2, 4, 6, 10]) {
|
|
7
|
+
const layers = [
|
|
8
|
+
"top",
|
|
9
|
+
...Array.from({ length: num_layers - 2 }, (_, i) => `inner${i + 1}`),
|
|
10
|
+
"bottom",
|
|
11
|
+
]
|
|
12
|
+
const circuitJson = [
|
|
13
|
+
{
|
|
14
|
+
type: "pcb_board",
|
|
15
|
+
pcb_board_id: "board",
|
|
16
|
+
center: { x: 0, y: 0 },
|
|
17
|
+
width: 10,
|
|
18
|
+
height: 10,
|
|
19
|
+
num_layers,
|
|
20
|
+
thickness: 1.6,
|
|
21
|
+
material: "fr4",
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
type: "pcb_plated_hole",
|
|
25
|
+
pcb_plated_hole_id: "hole",
|
|
26
|
+
pcb_component_id: "component",
|
|
27
|
+
shape: "circle",
|
|
28
|
+
x: 0,
|
|
29
|
+
y: 0,
|
|
30
|
+
outer_diameter: 2,
|
|
31
|
+
hole_diameter: 1,
|
|
32
|
+
layers,
|
|
33
|
+
port_hints: ["1"],
|
|
34
|
+
},
|
|
35
|
+
] as any
|
|
36
|
+
const tsx = convertCircuitJsonToTscircuit(circuitJson, {
|
|
37
|
+
componentName: "LayerBoard",
|
|
38
|
+
})
|
|
39
|
+
const rendered = await runTscircuitCode(tsx)
|
|
40
|
+
const ports = rendered.filter((el) => el.type === "pcb_port")
|
|
41
|
+
expect(ports).toHaveLength(1)
|
|
42
|
+
expect(ports[0].layers.map(String).sort()).toEqual([...layers].sort())
|
|
43
|
+
expect(rendered.filter((el) => el.type === "pcb_board")[0].num_layers).toBe(
|
|
44
|
+
num_layers,
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
}, 15000)
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import type { CircuitJson, PcbVia } from "circuit-json"
|
|
3
|
+
import { convertCircuitJsonToTscircuit } from "lib"
|
|
4
|
+
import { runTscircuitCode } from "tscircuit"
|
|
5
|
+
import { convertVias } from "../lib/generate-footprint-tsx/convert-vias"
|
|
6
|
+
|
|
7
|
+
test("preserves via geometry, copper layers and tenting", async () => {
|
|
8
|
+
const vias: (PcbVia & { is_tented?: boolean })[] = [
|
|
9
|
+
{
|
|
10
|
+
type: "pcb_via",
|
|
11
|
+
pcb_via_id: "through",
|
|
12
|
+
x: -2,
|
|
13
|
+
y: 3,
|
|
14
|
+
hole_diameter: 0.3,
|
|
15
|
+
outer_diameter: 0.6,
|
|
16
|
+
layers: ["top", "inner1", "inner2", "bottom"],
|
|
17
|
+
is_tented: true,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
type: "pcb_via",
|
|
21
|
+
pcb_via_id: "blind",
|
|
22
|
+
x: 4,
|
|
23
|
+
y: -1,
|
|
24
|
+
hole_diameter: 0.2,
|
|
25
|
+
outer_diameter: 0.5,
|
|
26
|
+
layers: ["top", "inner1"],
|
|
27
|
+
tented_on_top: true,
|
|
28
|
+
tented_on_bottom: false,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
type: "pcb_via",
|
|
32
|
+
pcb_via_id: "buried",
|
|
33
|
+
x: 1,
|
|
34
|
+
y: 2,
|
|
35
|
+
hole_diameter: 0.25,
|
|
36
|
+
outer_diameter: 0.55,
|
|
37
|
+
layers: ["inner1", "inner2"],
|
|
38
|
+
is_tented: false,
|
|
39
|
+
},
|
|
40
|
+
]
|
|
41
|
+
const circuitJson: CircuitJson = [
|
|
42
|
+
{
|
|
43
|
+
type: "pcb_board",
|
|
44
|
+
pcb_board_id: "board",
|
|
45
|
+
center: { x: 0, y: 0 },
|
|
46
|
+
width: 20,
|
|
47
|
+
height: 20,
|
|
48
|
+
num_layers: 4,
|
|
49
|
+
thickness: 1.6,
|
|
50
|
+
material: "fr4",
|
|
51
|
+
},
|
|
52
|
+
...vias,
|
|
53
|
+
]
|
|
54
|
+
const generatedTscircuit = convertCircuitJsonToTscircuit(circuitJson, {
|
|
55
|
+
componentName: "ViaBoard",
|
|
56
|
+
})
|
|
57
|
+
const renderedCircuitJson = (await runTscircuitCode(
|
|
58
|
+
generatedTscircuit,
|
|
59
|
+
)) as CircuitJson
|
|
60
|
+
const renderedVias = renderedCircuitJson.filter(
|
|
61
|
+
(element) => element.type === "pcb_via",
|
|
62
|
+
)
|
|
63
|
+
expect(renderedVias).toHaveLength(vias.length)
|
|
64
|
+
for (const [index, via] of vias.entries()) {
|
|
65
|
+
expect(renderedVias[index]).toMatchObject({
|
|
66
|
+
x: via.x,
|
|
67
|
+
y: via.y,
|
|
68
|
+
hole_diameter: via.hole_diameter,
|
|
69
|
+
outer_diameter: via.outer_diameter,
|
|
70
|
+
layers: via.layers,
|
|
71
|
+
tented_on_top: via.tented_on_top ?? via.is_tented,
|
|
72
|
+
tented_on_bottom: via.tented_on_bottom ?? via.is_tented,
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
test("rejects vias without copper layer endpoints", () => {
|
|
78
|
+
expect(() =>
|
|
79
|
+
convertVias([
|
|
80
|
+
{
|
|
81
|
+
type: "pcb_via",
|
|
82
|
+
pcb_via_id: "missing_layers",
|
|
83
|
+
x: 0,
|
|
84
|
+
y: 0,
|
|
85
|
+
hole_diameter: 0.3,
|
|
86
|
+
outer_diameter: 0.6,
|
|
87
|
+
layers: [],
|
|
88
|
+
},
|
|
89
|
+
]),
|
|
90
|
+
).toThrow("Via missing_layers has no copper layer endpoints")
|
|
91
|
+
})
|