circuit-json-to-tscircuit 0.0.26 → 0.0.28
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-O4VVQUKW.js → chunk-N6A3XIVV.js} +312 -232
- package/dist/cli/main.js +2 -2
- package/dist/lib/index.js +1 -1
- package/lib/generate-footprint-tsx/convert-copper-text.ts +41 -0
- package/lib/generate-footprint-tsx/convert-courtyard.ts +49 -0
- package/lib/generate-footprint-tsx/convert-cutouts.ts +33 -0
- package/lib/generate-footprint-tsx/convert-fabrication.ts +127 -0
- package/lib/generate-footprint-tsx/convert-holes.ts +31 -0
- package/lib/generate-footprint-tsx/convert-notes.ts +114 -0
- package/lib/generate-footprint-tsx/convert-plated-holes.ts +48 -0
- package/lib/generate-footprint-tsx/convert-silkscreen-text.ts +21 -0
- package/lib/generate-footprint-tsx/convert-silkscreen.ts +77 -0
- package/lib/generate-footprint-tsx/convert-smt-pads.ts +34 -0
- package/lib/generate-footprint-tsx/converter-types.ts +5 -0
- package/lib/generate-footprint-tsx/helpers.ts +15 -0
- package/lib/generate-footprint-tsx.tsx +24 -512
- package/package.json +1 -1
- package/tests/__snapshots__/test9-support-plated-hole-shapes-pcb.snap.svg +1 -0
- package/tests/test9-support-plated-hole-shapes.test.tsx +131 -0
- package/tests/test9-support-pill-plated-hole-rotation.test.tsx +0 -64
|
@@ -1,137 +1,127 @@
|
|
|
1
|
-
// lib/generate-footprint-tsx.
|
|
2
|
-
import { mmStr } from "@tscircuit/mm";
|
|
1
|
+
// lib/generate-footprint-tsx/convert-copper-text.ts
|
|
3
2
|
import { su } from "@tscircuit/soup-util";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
3
|
+
|
|
4
|
+
// lib/generate-footprint-tsx/helpers.ts
|
|
5
|
+
import { mmStr } from "@tscircuit/mm";
|
|
6
|
+
var escapeJsxText = (value) => String(value ?? "").replace(/"/g, '\\"');
|
|
7
|
+
var formatMm = (value) => mmStr(value ?? 0);
|
|
8
|
+
var formatPcbRotationAttr = (rotation, attrName = "pcbRotation") => {
|
|
9
|
+
if (rotation === void 0) return "";
|
|
10
|
+
const formatted = typeof rotation === "number" ? `${rotation}deg` : rotation;
|
|
11
|
+
return ` ${attrName}="${formatted}"`;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// lib/generate-footprint-tsx/convert-copper-text.ts
|
|
15
|
+
var convertCopperText = (circuitJson) => {
|
|
16
16
|
const copperTexts = su(circuitJson).pcb_copper_text.list();
|
|
17
|
-
const silkscreenTexts = su(circuitJson).pcb_silkscreen_text.list();
|
|
18
|
-
const pcbCutouts = su(circuitJson).pcb_cutout.list();
|
|
19
|
-
const noteTexts = su(circuitJson).pcb_note_text.list();
|
|
20
|
-
const noteRects = su(circuitJson).pcb_note_rect.list();
|
|
21
|
-
const notePaths = su(circuitJson).pcb_note_path.list();
|
|
22
|
-
const noteLines = su(circuitJson).pcb_note_line.list();
|
|
23
|
-
const noteDimensions = su(circuitJson).pcb_note_dimension.list();
|
|
24
|
-
const courtyardOutlines = su(circuitJson).pcb_courtyard_outline.list();
|
|
25
|
-
const courtyardRects = su(circuitJson).pcb_courtyard_rect.list();
|
|
26
|
-
const courtyardCircles = su(circuitJson).pcb_courtyard_circle.list();
|
|
27
17
|
const elementStrings = [];
|
|
28
|
-
for (const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const pcbRotation = "ccw_rotation" in hole && hole.ccw_rotation !== void 0 ? ` pcbRotation="${typeof hole.ccw_rotation === "number" ? `${hole.ccw_rotation}deg` : hole.ccw_rotation}"` : "";
|
|
39
|
-
elementStrings.push(
|
|
40
|
-
`<hole pcbX="${mmStr(hole.x)}" pcbY="${mmStr(hole.y)}" width="${mmStr(hole.hole_width)}" height="${mmStr(hole.hole_height)}" shape="pill"${pcbRotation} />`
|
|
41
|
-
);
|
|
18
|
+
for (const copperText of copperTexts) {
|
|
19
|
+
const anchorPosition = copperText.anchor_position ?? { x: 0, y: 0 };
|
|
20
|
+
const attrs = [
|
|
21
|
+
`pcbX={${anchorPosition.x}}`,
|
|
22
|
+
`pcbY={${anchorPosition.y}}`,
|
|
23
|
+
`anchorAlignment="${copperText.anchor_alignment ?? "center"}"`,
|
|
24
|
+
`text="${escapeJsxText(copperText.text)}"`
|
|
25
|
+
];
|
|
26
|
+
if (copperText.font !== void 0) {
|
|
27
|
+
attrs.push(`font="${copperText.font}"`);
|
|
42
28
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (platedHole.shape === "oval" || platedHole.shape === "pill") {
|
|
46
|
-
const pcbRotation = "ccw_rotation" in platedHole && platedHole.ccw_rotation !== void 0 ? ` pcbRotation="${typeof platedHole.ccw_rotation === "number" ? `${platedHole.ccw_rotation}deg` : platedHole.ccw_rotation}"` : "";
|
|
47
|
-
elementStrings.push(
|
|
48
|
-
`<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr(platedHole.x)}" pcbY="${mmStr(platedHole.y)}" outerHeight="${mmStr(platedHole.outer_height)}" outerWidth="${mmStr(platedHole.outer_width)}" holeHeight="${mmStr(platedHole.hole_height)}" holeWidth="${mmStr(platedHole.hole_width)}" height="${mmStr(platedHole.hole_height)}" shape="${platedHole.shape}"${pcbRotation} />`
|
|
49
|
-
);
|
|
50
|
-
} else if (platedHole.shape === "circle") {
|
|
51
|
-
elementStrings.push(
|
|
52
|
-
`<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr(platedHole.x)}" pcbY="${mmStr(platedHole.y)}" outerDiameter="${mmStr(platedHole.outer_diameter)}" holeDiameter="${mmStr(platedHole.hole_diameter)}" shape="circle" />`
|
|
53
|
-
);
|
|
29
|
+
if (copperText.font_size !== void 0) {
|
|
30
|
+
attrs.push(`fontSize={${copperText.font_size}}`);
|
|
54
31
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (smtPad.shape === "circle") {
|
|
58
|
-
elementStrings.push(
|
|
59
|
-
`<smtpad portHints={${JSON.stringify(smtPad.port_hints)}} pcbX="${mmStr(smtPad.x)}" pcbY="${mmStr(smtPad.y)}" radius="${mmStr(smtPad.radius)}" shape="circle" />`
|
|
60
|
-
);
|
|
61
|
-
} else if (smtPad.shape === "rect") {
|
|
62
|
-
elementStrings.push(
|
|
63
|
-
`<smtpad portHints={${JSON.stringify(smtPad.port_hints)}} pcbX="${mmStr(smtPad.x)}" pcbY="${mmStr(smtPad.y)}" width="${mmStr(smtPad.width)}" height="${mmStr(smtPad.height)}" shape="rect" />`
|
|
64
|
-
);
|
|
65
|
-
} else if (smtPad.shape === "pill") {
|
|
66
|
-
elementStrings.push(
|
|
67
|
-
`<smtpad portHints={${JSON.stringify(smtPad.port_hints)}} pcbX="${mmStr(smtPad.x)}" pcbY="${mmStr(smtPad.y)}" width="${mmStr(smtPad.width)}" height="${mmStr(smtPad.height)}" radius="${mmStr(smtPad.radius)}" shape="pill" />`
|
|
68
|
-
);
|
|
69
|
-
} else if (smtPad.shape === "polygon") {
|
|
70
|
-
elementStrings.push(
|
|
71
|
-
`<smtpad portHints={${JSON.stringify(smtPad.port_hints)}} shape="polygon" points={${JSON.stringify(smtPad.points)}} />`
|
|
72
|
-
);
|
|
73
|
-
} else if (smtPad.shape === "rotated_rect") {
|
|
74
|
-
elementStrings.push(
|
|
75
|
-
`<smtpad portHints={${JSON.stringify(smtPad.port_hints)}} pcbX="${mmStr(smtPad.x)}" pcbY="${mmStr(smtPad.y)}" width="${mmStr(smtPad.width)}" height="${mmStr(smtPad.height)}" ccwRotation={${smtPad.ccw_rotation}} shape="rotated_rect" />`
|
|
76
|
-
);
|
|
32
|
+
if (copperText.ccw_rotation !== void 0) {
|
|
33
|
+
attrs.push(`pcbRotation="${copperText.ccw_rotation}deg"`);
|
|
77
34
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
elementStrings.push(
|
|
81
|
-
`<silkscreenpath route={${JSON.stringify(silkscreenPath.route)}} />`
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
for (const silkscreenRect of silkscreenRects) {
|
|
85
|
-
const center = silkscreenRect.center ?? { x: 0, y: 0 };
|
|
86
|
-
const attrs = [
|
|
87
|
-
`pcbX={${center.x}}`,
|
|
88
|
-
`pcbY={${center.y}}`,
|
|
89
|
-
`width={${silkscreenRect.width ?? 0}}`,
|
|
90
|
-
`height={${silkscreenRect.height ?? 0}}`,
|
|
91
|
-
`layer="${silkscreenRect.layer}"`
|
|
92
|
-
];
|
|
93
|
-
if (silkscreenRect.stroke_width !== void 0) {
|
|
94
|
-
attrs.push(`strokeWidth={${silkscreenRect.stroke_width}}`);
|
|
35
|
+
if (copperText.is_knockout !== void 0) {
|
|
36
|
+
attrs.push(`knockout={${copperText.is_knockout}}`);
|
|
95
37
|
}
|
|
96
|
-
if (
|
|
97
|
-
attrs.push(`
|
|
38
|
+
if (copperText.is_mirrored !== void 0) {
|
|
39
|
+
attrs.push(`mirrored={${copperText.is_mirrored}}`);
|
|
98
40
|
}
|
|
99
|
-
if (
|
|
100
|
-
attrs.push(`
|
|
41
|
+
if (copperText.layer !== void 0 && copperText.layer !== "top") {
|
|
42
|
+
attrs.push(`layer="${copperText.layer}"`);
|
|
101
43
|
}
|
|
102
|
-
elementStrings.push(`<
|
|
44
|
+
elementStrings.push(`<coppertext ${attrs.join(" ")} />`);
|
|
103
45
|
}
|
|
104
|
-
|
|
105
|
-
|
|
46
|
+
return elementStrings;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// lib/generate-footprint-tsx/convert-courtyard.ts
|
|
50
|
+
import { su as su2 } from "@tscircuit/soup-util";
|
|
51
|
+
var convertCourtyard = (circuitJson) => {
|
|
52
|
+
const courtyardOutlines = su2(circuitJson).pcb_courtyard_outline.list();
|
|
53
|
+
const courtyardRects = su2(circuitJson).pcb_courtyard_rect.list();
|
|
54
|
+
const courtyardCircles = su2(circuitJson).pcb_courtyard_circle.list();
|
|
55
|
+
const elementStrings = [];
|
|
56
|
+
for (const courtyardOutline of courtyardOutlines) {
|
|
106
57
|
const attrs = [
|
|
107
|
-
`
|
|
108
|
-
`pcbY={${center.y}}`,
|
|
109
|
-
`radius={${silkscreenCircle.radius ?? 0}}`,
|
|
110
|
-
`layer="${silkscreenCircle.layer}"`
|
|
58
|
+
`outline={${JSON.stringify(courtyardOutline.outline ?? [])}}`
|
|
111
59
|
];
|
|
112
|
-
if (
|
|
113
|
-
attrs.push(`
|
|
60
|
+
if (courtyardOutline.layer !== void 0) {
|
|
61
|
+
attrs.push(`layer="${courtyardOutline.layer}"`);
|
|
114
62
|
}
|
|
115
|
-
|
|
116
|
-
|
|
63
|
+
elementStrings.push(`<courtyardoutline ${attrs.join(" ")} />`);
|
|
64
|
+
}
|
|
65
|
+
for (const courtyardRect of courtyardRects) {
|
|
66
|
+
const attrs = [
|
|
67
|
+
`pcbX={${courtyardRect.center?.x ?? 0}}`,
|
|
68
|
+
`pcbY={${courtyardRect.center?.y ?? 0}}`,
|
|
69
|
+
`width={${courtyardRect.width ?? 0}}`,
|
|
70
|
+
`height={${courtyardRect.height ?? 0}}`
|
|
71
|
+
];
|
|
72
|
+
if (courtyardRect.layer !== void 0) {
|
|
73
|
+
attrs.push(`layer="${courtyardRect.layer}"`);
|
|
117
74
|
}
|
|
118
|
-
elementStrings.push(`<
|
|
75
|
+
elementStrings.push(`<courtyardrect ${attrs.join(" ")} />`);
|
|
119
76
|
}
|
|
120
|
-
for (const
|
|
77
|
+
for (const courtyardCircle of courtyardCircles) {
|
|
121
78
|
const attrs = [
|
|
122
|
-
`
|
|
123
|
-
`
|
|
124
|
-
`
|
|
125
|
-
`y2={${silkscreenLine.y2 ?? 0}}`
|
|
79
|
+
`pcbX={${courtyardCircle.center?.x ?? 0}}`,
|
|
80
|
+
`pcbY={${courtyardCircle.center?.y ?? 0}}`,
|
|
81
|
+
`radius={${courtyardCircle.radius ?? 0}}`
|
|
126
82
|
];
|
|
127
|
-
if (
|
|
128
|
-
attrs.push(`
|
|
83
|
+
if (courtyardCircle.layer !== void 0) {
|
|
84
|
+
attrs.push(`layer="${courtyardCircle.layer}"`);
|
|
129
85
|
}
|
|
130
|
-
|
|
131
|
-
|
|
86
|
+
elementStrings.push(`<courtyardcircle ${attrs.join(" ")} />`);
|
|
87
|
+
}
|
|
88
|
+
return elementStrings;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// lib/generate-footprint-tsx/convert-cutouts.ts
|
|
92
|
+
import { su as su3 } from "@tscircuit/soup-util";
|
|
93
|
+
var convertCutouts = (circuitJson) => {
|
|
94
|
+
const pcbCutouts = su3(circuitJson).pcb_cutout.list();
|
|
95
|
+
const elementStrings = [];
|
|
96
|
+
for (const cutout of pcbCutouts) {
|
|
97
|
+
if (cutout.shape === "rect") {
|
|
98
|
+
const rotation = cutout.rotation !== void 0 ? ` pcbRotation="${formatMm(cutout.rotation)}"` : "";
|
|
99
|
+
elementStrings.push(
|
|
100
|
+
`<cutout shape="rect" pcbX="${formatMm(cutout.center.x)}" pcbY="${formatMm(cutout.center.y)}" width="${formatMm(cutout.width)}" height="${formatMm(cutout.height)}"${rotation} />`
|
|
101
|
+
);
|
|
102
|
+
} else if (cutout.shape === "circle") {
|
|
103
|
+
elementStrings.push(
|
|
104
|
+
`<cutout shape="circle" pcbX="${formatMm(cutout.center.x)}" pcbY="${formatMm(cutout.center.y)}" radius="${formatMm(cutout.radius)}" />`
|
|
105
|
+
);
|
|
106
|
+
} else if (cutout.shape === "polygon") {
|
|
107
|
+
elementStrings.push(
|
|
108
|
+
`<cutout shape="polygon" points={${JSON.stringify(cutout.points)}} />`
|
|
109
|
+
);
|
|
110
|
+
} else {
|
|
111
|
+
console.warn(`Unhandled pcb_cutout shape: ${cutout.shape}`);
|
|
132
112
|
}
|
|
133
|
-
elementStrings.push(`<silkscreenline ${attrs.join(" ")} />`);
|
|
134
113
|
}
|
|
114
|
+
return elementStrings;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// lib/generate-footprint-tsx/convert-fabrication.ts
|
|
118
|
+
import { su as su4 } from "@tscircuit/soup-util";
|
|
119
|
+
var convertFabrication = (circuitJson) => {
|
|
120
|
+
const fabricationNotePaths = su4(circuitJson).pcb_fabrication_note_path.list();
|
|
121
|
+
const fabricationNoteTexts = su4(circuitJson).pcb_fabrication_note_text.list();
|
|
122
|
+
const fabricationNoteRects = su4(circuitJson).pcb_fabrication_note_rect.list();
|
|
123
|
+
const fabricationNoteDimensions = su4(circuitJson).pcb_fabrication_note_dimension.list();
|
|
124
|
+
const elementStrings = [];
|
|
135
125
|
for (const fabPath of fabricationNotePaths) {
|
|
136
126
|
const attrs = [`route={${JSON.stringify(fabPath.route)}}`];
|
|
137
127
|
if ("stroke_width" in fabPath && fabPath.stroke_width !== void 0) {
|
|
@@ -147,14 +137,11 @@ var generateFootprintTsx = (circuitJson) => {
|
|
|
147
137
|
}
|
|
148
138
|
for (const fabText of fabricationNoteTexts) {
|
|
149
139
|
const anchorPosition = fabText.anchor_position ?? { x: 0, y: 0 };
|
|
150
|
-
const anchorAlignment = fabText.anchor_alignment ?? "center";
|
|
151
|
-
const rawText = String(fabText.text ?? "");
|
|
152
|
-
const escapedText = rawText.replace(/"/g, '\\"');
|
|
153
140
|
const attrs = [
|
|
154
141
|
`pcbX={${anchorPosition.x}}`,
|
|
155
142
|
`pcbY={${anchorPosition.y}}`,
|
|
156
|
-
`anchorAlignment="${
|
|
157
|
-
`text="${
|
|
143
|
+
`anchorAlignment="${fabText.anchor_alignment ?? "center"}"`,
|
|
144
|
+
`text="${escapeJsxText(fabText.text)}"`
|
|
158
145
|
];
|
|
159
146
|
if (fabText.font !== void 0) {
|
|
160
147
|
attrs.push(`font="${fabText.font}"`);
|
|
@@ -209,8 +196,7 @@ var generateFootprintTsx = (circuitJson) => {
|
|
|
209
196
|
`to={{ x: ${toPoint.x}, y: ${toPoint.y} }}`
|
|
210
197
|
];
|
|
211
198
|
if (fabDimension.text !== void 0) {
|
|
212
|
-
|
|
213
|
-
attrs.push(`text="${escapedText}"`);
|
|
199
|
+
attrs.push(`text="${escapeJsxText(fabDimension.text)}"`);
|
|
214
200
|
}
|
|
215
201
|
if (fabDimension.font !== void 0) {
|
|
216
202
|
attrs.push(`font="${fabDimension.font}"`);
|
|
@@ -234,95 +220,57 @@ var generateFootprintTsx = (circuitJson) => {
|
|
|
234
220
|
}
|
|
235
221
|
elementStrings.push(`<fabricationnotedimension ${attrs.join(" ")} />`);
|
|
236
222
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
if (copperText.font !== void 0) {
|
|
249
|
-
attrs.push(`font="${copperText.font}"`);
|
|
250
|
-
}
|
|
251
|
-
if (copperText.font_size !== void 0) {
|
|
252
|
-
attrs.push(`fontSize={${copperText.font_size}}`);
|
|
253
|
-
}
|
|
254
|
-
if (copperText.ccw_rotation !== void 0) {
|
|
255
|
-
attrs.push(`pcbRotation="${copperText.ccw_rotation}deg"`);
|
|
256
|
-
}
|
|
257
|
-
if (copperText.is_knockout !== void 0) {
|
|
258
|
-
attrs.push(`knockout={${copperText.is_knockout}}`);
|
|
259
|
-
}
|
|
260
|
-
if (copperText.is_mirrored !== void 0) {
|
|
261
|
-
attrs.push(`mirrored={${copperText.is_mirrored}}`);
|
|
262
|
-
}
|
|
263
|
-
if (copperText.layer !== void 0 && copperText.layer !== "top") {
|
|
264
|
-
attrs.push(`layer="${copperText.layer}"`);
|
|
265
|
-
}
|
|
266
|
-
elementStrings.push(`<coppertext ${attrs.join(" ")} />`);
|
|
267
|
-
}
|
|
268
|
-
for (const stext of silkscreenTexts) {
|
|
269
|
-
const pcbX = stext.anchor_position?.x ?? 0;
|
|
270
|
-
const pcbY = stext.anchor_position?.y ?? 0;
|
|
271
|
-
const anchorAlignment = stext.anchor_alignment;
|
|
272
|
-
const fontSize = stext.font_size;
|
|
273
|
-
const rawText = String(stext.text ?? "");
|
|
274
|
-
const escapedText = rawText.replace(/"/g, '\\"');
|
|
275
|
-
elementStrings.push(
|
|
276
|
-
`<silkscreentext pcbX={${pcbX}} pcbY={${pcbY}} anchorAlignment="${anchorAlignment}" fontSize={${fontSize}} text="${escapedText}" />`
|
|
277
|
-
);
|
|
278
|
-
}
|
|
279
|
-
for (const cutout of pcbCutouts) {
|
|
280
|
-
if (cutout.shape === "rect") {
|
|
281
|
-
const pcbX = cutout.center.x;
|
|
282
|
-
const pcbY = cutout.center.y;
|
|
283
|
-
const width = mmStr(cutout.width);
|
|
284
|
-
const height = mmStr(cutout.height);
|
|
285
|
-
const rotation = cutout.rotation !== void 0 ? ` pcbRotation="${mmStr(cutout.rotation)}"` : "";
|
|
223
|
+
return elementStrings;
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
// lib/generate-footprint-tsx/convert-holes.ts
|
|
227
|
+
import { su as su5 } from "@tscircuit/soup-util";
|
|
228
|
+
import { mmStr as mmStr2 } from "@tscircuit/mm";
|
|
229
|
+
var convertHoles = (circuitJson) => {
|
|
230
|
+
const holes = su5(circuitJson).pcb_hole.list();
|
|
231
|
+
const elementStrings = [];
|
|
232
|
+
for (const hole of holes) {
|
|
233
|
+
if (hole.hole_shape === "circle") {
|
|
286
234
|
elementStrings.push(
|
|
287
|
-
`<
|
|
235
|
+
`<hole pcbX="${mmStr2(hole.x)}" pcbY="${mmStr2(hole.y)}" diameter="${mmStr2(hole.hole_diameter)}" />`
|
|
288
236
|
);
|
|
289
|
-
} else if (
|
|
290
|
-
const pcbX = cutout.center.x;
|
|
291
|
-
const pcbY = cutout.center.y;
|
|
292
|
-
const radius = mmStr(cutout.radius);
|
|
237
|
+
} else if (hole.hole_shape === "rect") {
|
|
293
238
|
elementStrings.push(
|
|
294
|
-
`<
|
|
239
|
+
`<hole pcbX="${mmStr2(hole.x)}" pcbY="${mmStr2(hole.y)}" width="${mmStr2(hole.hole_width)}" height="${mmStr2(hole.hole_height)}" shape="rect" />`
|
|
240
|
+
);
|
|
241
|
+
} else if (hole.hole_shape === "oval" || hole.hole_shape === "pill" || hole.hole_shape === "rotated_pill") {
|
|
242
|
+
elementStrings.push(
|
|
243
|
+
`<hole pcbX="${mmStr2(hole.x)}" pcbY="${mmStr2(hole.y)}" width="${mmStr2(hole.hole_width)}" height="${mmStr2(hole.hole_height)}" shape="pill"${formatPcbRotationAttr("ccw_rotation" in hole ? hole.ccw_rotation : void 0)} />`
|
|
295
244
|
);
|
|
296
|
-
} else if (cutout.shape === "polygon") {
|
|
297
|
-
const pointsJson = JSON.stringify(cutout.points);
|
|
298
|
-
elementStrings.push(`<cutout shape="polygon" points={${pointsJson}} />`);
|
|
299
|
-
} else {
|
|
300
|
-
console.warn(`Unhandled pcb_cutout shape: ${cutout.shape}`);
|
|
301
245
|
}
|
|
302
246
|
}
|
|
247
|
+
return elementStrings;
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
// lib/generate-footprint-tsx/convert-notes.ts
|
|
251
|
+
import { su as su6 } from "@tscircuit/soup-util";
|
|
252
|
+
var convertNotes = (circuitJson) => {
|
|
253
|
+
const noteTexts = su6(circuitJson).pcb_note_text.list();
|
|
254
|
+
const noteRects = su6(circuitJson).pcb_note_rect.list();
|
|
255
|
+
const notePaths = su6(circuitJson).pcb_note_path.list();
|
|
256
|
+
const noteLines = su6(circuitJson).pcb_note_line.list();
|
|
257
|
+
const noteDimensions = su6(circuitJson).pcb_note_dimension.list();
|
|
258
|
+
const elementStrings = [];
|
|
303
259
|
for (const noteText of noteTexts) {
|
|
304
260
|
const anchorPosition = noteText.anchor_position ?? { x: 0, y: 0 };
|
|
305
|
-
const anchorAlignment = noteText.anchor_alignment ?? "center";
|
|
306
|
-
const font = noteText.font ?? "tscircuit2024";
|
|
307
|
-
const fontSize = noteText.font_size ?? 0;
|
|
308
261
|
const colorAttr = noteText.color ? ` color="${noteText.color}"` : "";
|
|
309
|
-
const rawText = String(noteText.text ?? "");
|
|
310
|
-
const escapedText = rawText.replace(/"/g, '\\"');
|
|
311
262
|
elementStrings.push(
|
|
312
|
-
`<pcbnotetext pcbX={${anchorPosition.x}} pcbY={${anchorPosition.y}} anchorAlignment="${
|
|
263
|
+
`<pcbnotetext pcbX={${anchorPosition.x}} pcbY={${anchorPosition.y}} anchorAlignment="${noteText.anchor_alignment ?? "center"}" font="${noteText.font ?? "tscircuit2024"}" fontSize={${noteText.font_size ?? 0}} text="${escapeJsxText(noteText.text)}"${colorAttr} />`
|
|
313
264
|
);
|
|
314
265
|
}
|
|
315
266
|
for (const noteRect of noteRects) {
|
|
316
267
|
const center = noteRect.center ?? { x: 0, y: 0 };
|
|
317
|
-
const width = noteRect.width ?? 0;
|
|
318
|
-
const height = noteRect.height ?? 0;
|
|
319
|
-
const strokeWidth = noteRect.stroke_width ?? 0;
|
|
320
268
|
const attrs = [
|
|
321
269
|
`pcbX={${center.x}}`,
|
|
322
270
|
`pcbY={${center.y}}`,
|
|
323
|
-
`width={${width}}`,
|
|
324
|
-
`height={${height}}`,
|
|
325
|
-
`strokeWidth={${
|
|
271
|
+
`width={${noteRect.width ?? 0}}`,
|
|
272
|
+
`height={${noteRect.height ?? 0}}`,
|
|
273
|
+
`strokeWidth={${noteRect.stroke_width ?? 0}}`
|
|
326
274
|
];
|
|
327
275
|
if (noteRect.is_filled !== void 0) {
|
|
328
276
|
attrs.push(`isFilled={${noteRect.is_filled}}`);
|
|
@@ -339,8 +287,7 @@ var generateFootprintTsx = (circuitJson) => {
|
|
|
339
287
|
elementStrings.push(`<pcbnoterect ${attrs.join(" ")} />`);
|
|
340
288
|
}
|
|
341
289
|
for (const notePath of notePaths) {
|
|
342
|
-
const
|
|
343
|
-
const attrs = [`route={${routeJson}}`];
|
|
290
|
+
const attrs = [`route={${JSON.stringify(notePath.route ?? [])}}`];
|
|
344
291
|
if (notePath.stroke_width !== void 0) {
|
|
345
292
|
attrs.push(`strokeWidth={${notePath.stroke_width}}`);
|
|
346
293
|
}
|
|
@@ -370,17 +317,14 @@ var generateFootprintTsx = (circuitJson) => {
|
|
|
370
317
|
for (const noteDimension of noteDimensions) {
|
|
371
318
|
const fromPoint = noteDimension.from ?? { x: 0, y: 0 };
|
|
372
319
|
const toPoint = noteDimension.to ?? { x: 0, y: 0 };
|
|
373
|
-
const font = noteDimension.font ?? "tscircuit2024";
|
|
374
|
-
const fontSize = noteDimension.font_size ?? 0;
|
|
375
|
-
const arrowSize = noteDimension.arrow_size;
|
|
376
320
|
const attrs = [
|
|
377
321
|
`from={{ x: ${fromPoint.x}, y: ${fromPoint.y} }}`,
|
|
378
322
|
`to={{ x: ${toPoint.x}, y: ${toPoint.y} }}`,
|
|
379
|
-
`font="${font}"`,
|
|
380
|
-
`fontSize={${
|
|
323
|
+
`font="${noteDimension.font ?? "tscircuit2024"}"`,
|
|
324
|
+
`fontSize={${noteDimension.font_size ?? 0}}`
|
|
381
325
|
];
|
|
382
|
-
if (
|
|
383
|
-
attrs.push(`arrowSize={${
|
|
326
|
+
if (noteDimension.arrow_size !== void 0) {
|
|
327
|
+
attrs.push(`arrowSize={${noteDimension.arrow_size}}`);
|
|
384
328
|
}
|
|
385
329
|
if ("offset" in noteDimension) {
|
|
386
330
|
const offsetValue = noteDimension.offset;
|
|
@@ -389,46 +333,182 @@ var generateFootprintTsx = (circuitJson) => {
|
|
|
389
333
|
}
|
|
390
334
|
}
|
|
391
335
|
if (noteDimension.text !== void 0) {
|
|
392
|
-
|
|
393
|
-
attrs.push(`text="${escapedText}"`);
|
|
336
|
+
attrs.push(`text="${escapeJsxText(noteDimension.text)}"`);
|
|
394
337
|
}
|
|
395
338
|
if (noteDimension.color !== void 0) {
|
|
396
339
|
attrs.push(`color="${noteDimension.color}"`);
|
|
397
340
|
}
|
|
398
341
|
elementStrings.push(`<pcbnotedimension ${attrs.join(" ")} />`);
|
|
399
342
|
}
|
|
400
|
-
|
|
343
|
+
return elementStrings;
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
// lib/generate-footprint-tsx/convert-plated-holes.ts
|
|
347
|
+
import { su as su7 } from "@tscircuit/soup-util";
|
|
348
|
+
import { mmStr as mmStr3 } from "@tscircuit/mm";
|
|
349
|
+
var formatOptionalMmAttr = (attrName, value) => {
|
|
350
|
+
if (value === void 0) return "";
|
|
351
|
+
return ` ${attrName}="${mmStr3(value)}"`;
|
|
352
|
+
};
|
|
353
|
+
var convertPlatedHoles = (circuitJson) => {
|
|
354
|
+
const platedHoles = su7(circuitJson).pcb_plated_hole.list();
|
|
355
|
+
const elementStrings = [];
|
|
356
|
+
for (const platedHole of platedHoles) {
|
|
357
|
+
if (platedHole.shape === "oval" || platedHole.shape === "pill") {
|
|
358
|
+
elementStrings.push(
|
|
359
|
+
`<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr3(platedHole.x)}" pcbY="${mmStr3(platedHole.y)}" outerHeight="${mmStr3(platedHole.outer_height)}" outerWidth="${mmStr3(platedHole.outer_width)}" holeHeight="${mmStr3(platedHole.hole_height)}" holeWidth="${mmStr3(platedHole.hole_width)}" height="${mmStr3(platedHole.hole_height)}" shape="${platedHole.shape}"${formatPcbRotationAttr("ccw_rotation" in platedHole ? platedHole.ccw_rotation : void 0)} />`
|
|
360
|
+
);
|
|
361
|
+
} else if (platedHole.shape === "circle") {
|
|
362
|
+
elementStrings.push(
|
|
363
|
+
`<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr3(platedHole.x)}" pcbY="${mmStr3(platedHole.y)}" outerDiameter="${mmStr3(platedHole.outer_diameter)}" holeDiameter="${mmStr3(platedHole.hole_diameter)}" shape="circle" />`
|
|
364
|
+
);
|
|
365
|
+
} else if (platedHole.shape === "circular_hole_with_rect_pad") {
|
|
366
|
+
elementStrings.push(
|
|
367
|
+
`<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr3(platedHole.x)}" pcbY="${mmStr3(platedHole.y)}" holeDiameter="${mmStr3(platedHole.hole_diameter)}" rectPadWidth="${mmStr3(platedHole.rect_pad_width)}" rectPadHeight="${mmStr3(platedHole.rect_pad_height)}"${formatOptionalMmAttr("rectBorderRadius", platedHole.rect_border_radius)}${formatOptionalMmAttr("holeOffsetX", platedHole.hole_offset_x)}${formatOptionalMmAttr("holeOffsetY", platedHole.hole_offset_y)} shape="circular_hole_with_rect_pad" />`
|
|
368
|
+
);
|
|
369
|
+
} else if (platedHole.shape === "pill_hole_with_rect_pad") {
|
|
370
|
+
elementStrings.push(
|
|
371
|
+
`<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr3(platedHole.x)}" pcbY="${mmStr3(platedHole.y)}" holeWidth="${mmStr3(platedHole.hole_width)}" holeHeight="${mmStr3(platedHole.hole_height)}" rectPadWidth="${mmStr3(platedHole.rect_pad_width)}" rectPadHeight="${mmStr3(platedHole.rect_pad_height)}"${formatOptionalMmAttr("rectBorderRadius", platedHole.rect_border_radius)}${formatOptionalMmAttr("holeOffsetX", platedHole.hole_offset_x)}${formatOptionalMmAttr("holeOffsetY", platedHole.hole_offset_y)} shape="pill_hole_with_rect_pad" />`
|
|
372
|
+
);
|
|
373
|
+
} else if (platedHole.shape === "hole_with_polygon_pad") {
|
|
374
|
+
const holeSizeAttrs = platedHole.hole_shape === "circle" ? ` holeDiameter="${mmStr3(platedHole.hole_diameter ?? 0)}"` : `${formatOptionalMmAttr("holeWidth", platedHole.hole_width)}${formatOptionalMmAttr("holeHeight", platedHole.hole_height)}`;
|
|
375
|
+
elementStrings.push(
|
|
376
|
+
`<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr3(platedHole.x)}" pcbY="${mmStr3(platedHole.y)}" holeShape="${platedHole.hole_shape}"${holeSizeAttrs} padOutline={${JSON.stringify(platedHole.pad_outline)}} holeOffsetX="${mmStr3(platedHole.hole_offset_x)}" holeOffsetY="${mmStr3(platedHole.hole_offset_y)}" shape="hole_with_polygon_pad" />`
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return elementStrings;
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
// lib/generate-footprint-tsx/convert-silkscreen.ts
|
|
384
|
+
import { su as su8 } from "@tscircuit/soup-util";
|
|
385
|
+
var convertSilkscreen = (circuitJson) => {
|
|
386
|
+
const silkscreenLines = su8(circuitJson).pcb_silkscreen_line.list();
|
|
387
|
+
const silkscreenPaths = su8(circuitJson).pcb_silkscreen_path.list();
|
|
388
|
+
const silkscreenRects = su8(circuitJson).pcb_silkscreen_rect.list();
|
|
389
|
+
const silkscreenCircles = su8(circuitJson).pcb_silkscreen_circle.list();
|
|
390
|
+
const elementStrings = [];
|
|
391
|
+
for (const silkscreenPath of silkscreenPaths) {
|
|
392
|
+
elementStrings.push(
|
|
393
|
+
`<silkscreenpath route={${JSON.stringify(silkscreenPath.route)}} />`
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
for (const silkscreenRect of silkscreenRects) {
|
|
397
|
+
const center = silkscreenRect.center ?? { x: 0, y: 0 };
|
|
401
398
|
const attrs = [
|
|
402
|
-
`
|
|
399
|
+
`pcbX={${center.x}}`,
|
|
400
|
+
`pcbY={${center.y}}`,
|
|
401
|
+
`width={${silkscreenRect.width ?? 0}}`,
|
|
402
|
+
`height={${silkscreenRect.height ?? 0}}`,
|
|
403
|
+
`layer="${silkscreenRect.layer}"`
|
|
403
404
|
];
|
|
404
|
-
if (
|
|
405
|
-
attrs.push(`
|
|
405
|
+
if (silkscreenRect.stroke_width !== void 0) {
|
|
406
|
+
attrs.push(`strokeWidth={${silkscreenRect.stroke_width}}`);
|
|
406
407
|
}
|
|
407
|
-
|
|
408
|
+
if (silkscreenRect.is_filled !== void 0) {
|
|
409
|
+
attrs.push(`filled={${silkscreenRect.is_filled}}`);
|
|
410
|
+
}
|
|
411
|
+
if (silkscreenRect.corner_radius !== void 0) {
|
|
412
|
+
attrs.push(`cornerRadius={${silkscreenRect.corner_radius}}`);
|
|
413
|
+
}
|
|
414
|
+
elementStrings.push(`<silkscreenrect ${attrs.join(" ")} />`);
|
|
408
415
|
}
|
|
409
|
-
for (const
|
|
416
|
+
for (const silkscreenCircle of silkscreenCircles) {
|
|
417
|
+
const center = silkscreenCircle.center ?? { x: 0, y: 0 };
|
|
410
418
|
const attrs = [
|
|
411
|
-
`pcbX={${
|
|
412
|
-
`pcbY={${
|
|
413
|
-
`
|
|
414
|
-
`
|
|
419
|
+
`pcbX={${center.x}}`,
|
|
420
|
+
`pcbY={${center.y}}`,
|
|
421
|
+
`radius={${silkscreenCircle.radius ?? 0}}`,
|
|
422
|
+
`layer="${silkscreenCircle.layer}"`
|
|
415
423
|
];
|
|
416
|
-
if (
|
|
417
|
-
attrs.push(`
|
|
424
|
+
if (silkscreenCircle.stroke_width !== void 0) {
|
|
425
|
+
attrs.push(`strokeWidth={${silkscreenCircle.stroke_width}}`);
|
|
418
426
|
}
|
|
419
|
-
|
|
427
|
+
if (silkscreenCircle.is_filled !== void 0) {
|
|
428
|
+
attrs.push(`isFilled={${silkscreenCircle.is_filled}}`);
|
|
429
|
+
}
|
|
430
|
+
elementStrings.push(`<silkscreencircle ${attrs.join(" ")} />`);
|
|
420
431
|
}
|
|
421
|
-
for (const
|
|
432
|
+
for (const silkscreenLine of silkscreenLines) {
|
|
422
433
|
const attrs = [
|
|
423
|
-
`
|
|
424
|
-
`
|
|
425
|
-
`
|
|
434
|
+
`x1={${silkscreenLine.x1 ?? 0}}`,
|
|
435
|
+
`y1={${silkscreenLine.y1 ?? 0}}`,
|
|
436
|
+
`x2={${silkscreenLine.x2 ?? 0}}`,
|
|
437
|
+
`y2={${silkscreenLine.y2 ?? 0}}`
|
|
426
438
|
];
|
|
427
|
-
if (
|
|
428
|
-
attrs.push(`
|
|
439
|
+
if (silkscreenLine.stroke_width !== void 0) {
|
|
440
|
+
attrs.push(`strokeWidth={${silkscreenLine.stroke_width}}`);
|
|
441
|
+
}
|
|
442
|
+
if (silkscreenLine.layer === "bottom") {
|
|
443
|
+
attrs.push(`layer="bottom"`);
|
|
444
|
+
}
|
|
445
|
+
elementStrings.push(`<silkscreenline ${attrs.join(" ")} />`);
|
|
446
|
+
}
|
|
447
|
+
return elementStrings;
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
// lib/generate-footprint-tsx/convert-silkscreen-text.ts
|
|
451
|
+
import { su as su9 } from "@tscircuit/soup-util";
|
|
452
|
+
var convertSilkscreenText = (circuitJson) => {
|
|
453
|
+
const silkscreenTexts = su9(circuitJson).pcb_silkscreen_text.list();
|
|
454
|
+
const elementStrings = [];
|
|
455
|
+
for (const silkscreenText of silkscreenTexts) {
|
|
456
|
+
const pcbX = silkscreenText.anchor_position?.x ?? 0;
|
|
457
|
+
const pcbY = silkscreenText.anchor_position?.y ?? 0;
|
|
458
|
+
elementStrings.push(
|
|
459
|
+
`<silkscreentext pcbX={${pcbX}} pcbY={${pcbY}} anchorAlignment="${silkscreenText.anchor_alignment}" fontSize={${silkscreenText.font_size}} text="${escapeJsxText(silkscreenText.text)}" />`
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
return elementStrings;
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
// lib/generate-footprint-tsx/convert-smt-pads.ts
|
|
466
|
+
import { su as su10 } from "@tscircuit/soup-util";
|
|
467
|
+
import { mmStr as mmStr4 } from "@tscircuit/mm";
|
|
468
|
+
var convertSmtPads = (circuitJson) => {
|
|
469
|
+
const smtPads = su10(circuitJson).pcb_smtpad.list();
|
|
470
|
+
const elementStrings = [];
|
|
471
|
+
for (const smtPad of smtPads) {
|
|
472
|
+
if (smtPad.shape === "circle") {
|
|
473
|
+
elementStrings.push(
|
|
474
|
+
`<smtpad portHints={${JSON.stringify(smtPad.port_hints)}} pcbX="${mmStr4(smtPad.x)}" pcbY="${mmStr4(smtPad.y)}" radius="${mmStr4(smtPad.radius)}" shape="circle" />`
|
|
475
|
+
);
|
|
476
|
+
} else if (smtPad.shape === "rect") {
|
|
477
|
+
elementStrings.push(
|
|
478
|
+
`<smtpad portHints={${JSON.stringify(smtPad.port_hints)}} pcbX="${mmStr4(smtPad.x)}" pcbY="${mmStr4(smtPad.y)}" width="${mmStr4(smtPad.width)}" height="${mmStr4(smtPad.height)}" shape="rect" />`
|
|
479
|
+
);
|
|
480
|
+
} else if (smtPad.shape === "pill") {
|
|
481
|
+
elementStrings.push(
|
|
482
|
+
`<smtpad portHints={${JSON.stringify(smtPad.port_hints)}} pcbX="${mmStr4(smtPad.x)}" pcbY="${mmStr4(smtPad.y)}" width="${mmStr4(smtPad.width)}" height="${mmStr4(smtPad.height)}" radius="${mmStr4(smtPad.radius)}" shape="pill" />`
|
|
483
|
+
);
|
|
484
|
+
} else if (smtPad.shape === "polygon") {
|
|
485
|
+
elementStrings.push(
|
|
486
|
+
`<smtpad portHints={${JSON.stringify(smtPad.port_hints)}} shape="polygon" points={${JSON.stringify(smtPad.points)}} />`
|
|
487
|
+
);
|
|
488
|
+
} else if (smtPad.shape === "rotated_rect") {
|
|
489
|
+
elementStrings.push(
|
|
490
|
+
`<smtpad portHints={${JSON.stringify(smtPad.port_hints)}} pcbX="${mmStr4(smtPad.x)}" pcbY="${mmStr4(smtPad.y)}" width="${mmStr4(smtPad.width)}" height="${mmStr4(smtPad.height)}" ccwRotation={${smtPad.ccw_rotation}} shape="rotated_rect" />`
|
|
491
|
+
);
|
|
429
492
|
}
|
|
430
|
-
elementStrings.push(`<courtyardcircle ${attrs.join(" ")} />`);
|
|
431
493
|
}
|
|
494
|
+
return elementStrings;
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
// lib/generate-footprint-tsx.tsx
|
|
498
|
+
var generateFootprintTsx = (circuitJson) => {
|
|
499
|
+
const converters = [
|
|
500
|
+
convertHoles,
|
|
501
|
+
convertPlatedHoles,
|
|
502
|
+
convertSmtPads,
|
|
503
|
+
convertSilkscreen,
|
|
504
|
+
convertFabrication,
|
|
505
|
+
convertSilkscreenText,
|
|
506
|
+
convertCopperText,
|
|
507
|
+
convertCutouts,
|
|
508
|
+
convertNotes,
|
|
509
|
+
convertCourtyard
|
|
510
|
+
];
|
|
511
|
+
const elementStrings = converters.flatMap((convert) => convert(circuitJson));
|
|
432
512
|
if (elementStrings.length === 0) {
|
|
433
513
|
return null;
|
|
434
514
|
}
|
|
@@ -440,15 +520,15 @@ var generateFootprintTsx = (circuitJson) => {
|
|
|
440
520
|
};
|
|
441
521
|
|
|
442
522
|
// lib/generate-symbol-tsx.ts
|
|
443
|
-
import { su as
|
|
523
|
+
import { su as su11 } from "@tscircuit/soup-util";
|
|
444
524
|
var generateSymbolTsx = (circuitJson) => {
|
|
445
|
-
const schematicArcs =
|
|
446
|
-
const schematicLines =
|
|
447
|
-
const schematicPaths =
|
|
448
|
-
const schematicTexts =
|
|
449
|
-
const schematicCircles =
|
|
450
|
-
const schematicBoxes =
|
|
451
|
-
const schematicRects =
|
|
525
|
+
const schematicArcs = su11(circuitJson).schematic_arc.list();
|
|
526
|
+
const schematicLines = su11(circuitJson).schematic_line.list();
|
|
527
|
+
const schematicPaths = su11(circuitJson).schematic_path.list();
|
|
528
|
+
const schematicTexts = su11(circuitJson).schematic_text.list();
|
|
529
|
+
const schematicCircles = su11(circuitJson).schematic_circle.list();
|
|
530
|
+
const schematicBoxes = su11(circuitJson).schematic_box.list();
|
|
531
|
+
const schematicRects = su11(circuitJson).schematic_rect.list();
|
|
452
532
|
const elementStrings = [];
|
|
453
533
|
for (const arc of schematicArcs) {
|
|
454
534
|
const center = arc.center ?? { x: 0, y: 0 };
|