circuit-json-to-tscircuit 0.0.40 → 0.0.42
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-UHPKLBYL.js → chunk-UXTI3RT6.js} +62 -92
- package/dist/cli/main.js +2 -2
- package/dist/lib/index.js +1 -1
- package/lib/generate-footprint-tsx/convert-copper-text.ts +1 -1
- package/lib/generate-footprint-tsx/convert-courtyard.ts +4 -0
- package/lib/generate-footprint-tsx/convert-cutouts.ts +1 -1
- package/lib/generate-footprint-tsx/convert-fabrication.ts +1 -1
- package/lib/generate-footprint-tsx/convert-holes.ts +1 -1
- package/lib/generate-footprint-tsx/convert-keepouts.ts +1 -1
- package/lib/generate-footprint-tsx/convert-notes.ts +1 -1
- package/lib/generate-footprint-tsx/convert-plated-holes.ts +3 -5
- package/lib/generate-footprint-tsx/convert-silkscreen-text.ts +1 -1
- package/lib/generate-footprint-tsx/convert-smt-pads.ts +13 -65
- package/lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/escape-jsx-text.ts +2 -0
- package/lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/format-mm.ts +3 -0
- package/lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/format-optional-mm-attr.ts +9 -0
- package/lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/format-pcb-rotation-attr.ts +8 -0
- package/lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/format-solder-mask-attrs.ts +14 -0
- package/package.json +1 -1
- package/tests/__snapshots__/test16-support-pcb-smtpad-shapes-pcb.snap.svg +1 -1
- package/tests/__snapshots__/test8-support-courtyard-courtyard-pcb.snap.svg +1 -1
- package/tests/test16-support-pcb-smtpad-shapes.test.tsx +30 -1
- package/tests/test8-support-courtyard.test.tsx +31 -10
- package/lib/generate-footprint-tsx/helpers.ts +0 -33
|
@@ -1,24 +1,12 @@
|
|
|
1
1
|
// lib/get-board-using-template.ts
|
|
2
|
-
import { mmStr as
|
|
2
|
+
import { mmStr as mmStr7 } from "@tscircuit/mm";
|
|
3
3
|
import { su as su12 } from "@tscircuit/soup-util";
|
|
4
4
|
|
|
5
5
|
// lib/generate-footprint-tsx/convert-copper-text.ts
|
|
6
6
|
import { su } from "@tscircuit/soup-util";
|
|
7
7
|
|
|
8
|
-
// lib/generate-footprint-tsx/
|
|
9
|
-
import { mmStr } from "@tscircuit/mm";
|
|
8
|
+
// lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/escape-jsx-text.ts
|
|
10
9
|
var escapeJsxText = (value) => String(value ?? "").replace(/"/g, '\\"');
|
|
11
|
-
var formatMm = (value) => mmStr(value ?? 0);
|
|
12
|
-
var formatOptionalMmAttr = (attrName, value) => {
|
|
13
|
-
if (value === void 0) return "";
|
|
14
|
-
return ` ${attrName}="${mmStr(value)}"`;
|
|
15
|
-
};
|
|
16
|
-
var formatSolderMaskAttrs = (platedHole) => `${platedHole.is_covered_with_solder_mask === void 0 ? "" : ` coveredWithSolderMask={${platedHole.is_covered_with_solder_mask}}`}${formatOptionalMmAttr("solderMaskMargin", platedHole.soldermask_margin)}`;
|
|
17
|
-
var formatPcbRotationAttr = (rotation, attrName = "pcbRotation") => {
|
|
18
|
-
if (rotation === void 0) return "";
|
|
19
|
-
const formatted = typeof rotation === "number" ? `${rotation}deg` : rotation;
|
|
20
|
-
return ` ${attrName}="${formatted}"`;
|
|
21
|
-
};
|
|
22
10
|
|
|
23
11
|
// lib/generate-footprint-tsx/convert-copper-text.ts
|
|
24
12
|
var convertCopperText = (circuitJson) => {
|
|
@@ -57,6 +45,15 @@ var convertCopperText = (circuitJson) => {
|
|
|
57
45
|
|
|
58
46
|
// lib/generate-footprint-tsx/convert-courtyard.ts
|
|
59
47
|
import { su as su2 } from "@tscircuit/soup-util";
|
|
48
|
+
|
|
49
|
+
// lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/format-pcb-rotation-attr.ts
|
|
50
|
+
var formatPcbRotationAttr = (rotation, attrName = "pcbRotation") => {
|
|
51
|
+
if (rotation === void 0) return "";
|
|
52
|
+
const formatted = typeof rotation === "number" ? `${rotation}deg` : rotation;
|
|
53
|
+
return ` ${attrName}="${formatted}"`;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// lib/generate-footprint-tsx/convert-courtyard.ts
|
|
60
57
|
var convertCourtyard = (circuitJson) => {
|
|
61
58
|
const courtyardOutlines = su2(circuitJson).pcb_courtyard_outline.list();
|
|
62
59
|
const courtyardRects = su2(circuitJson).pcb_courtyard_rect.list();
|
|
@@ -81,6 +78,9 @@ var convertCourtyard = (circuitJson) => {
|
|
|
81
78
|
if (courtyardRect.layer !== void 0) {
|
|
82
79
|
attrs.push(`layer="${courtyardRect.layer}"`);
|
|
83
80
|
}
|
|
81
|
+
if (courtyardRect.ccw_rotation !== void 0) {
|
|
82
|
+
attrs.push(formatPcbRotationAttr(courtyardRect.ccw_rotation).trimStart());
|
|
83
|
+
}
|
|
84
84
|
elementStrings.push(`<courtyardrect ${attrs.join(" ")} />`);
|
|
85
85
|
}
|
|
86
86
|
for (const courtyardCircle of courtyardCircles) {
|
|
@@ -99,6 +99,12 @@ var convertCourtyard = (circuitJson) => {
|
|
|
99
99
|
|
|
100
100
|
// lib/generate-footprint-tsx/convert-cutouts.ts
|
|
101
101
|
import { su as su3 } from "@tscircuit/soup-util";
|
|
102
|
+
|
|
103
|
+
// lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/format-mm.ts
|
|
104
|
+
import { mmStr } from "@tscircuit/mm";
|
|
105
|
+
var formatMm = (value) => mmStr(value ?? 0);
|
|
106
|
+
|
|
107
|
+
// lib/generate-footprint-tsx/convert-cutouts.ts
|
|
102
108
|
var convertCutouts = (circuitJson) => {
|
|
103
109
|
const pcbCutouts = su3(circuitJson).pcb_cutout.list();
|
|
104
110
|
const elementStrings = [];
|
|
@@ -379,33 +385,51 @@ var convertNotes = (circuitJson) => {
|
|
|
379
385
|
|
|
380
386
|
// lib/generate-footprint-tsx/convert-plated-holes.ts
|
|
381
387
|
import { su as su8 } from "@tscircuit/soup-util";
|
|
388
|
+
import { mmStr as mmStr4 } from "@tscircuit/mm";
|
|
389
|
+
|
|
390
|
+
// lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/format-optional-mm-attr.ts
|
|
382
391
|
import { mmStr as mmStr3 } from "@tscircuit/mm";
|
|
392
|
+
var formatOptionalMmAttr = (attrName, value) => {
|
|
393
|
+
if (value === void 0) return "";
|
|
394
|
+
return ` ${attrName}="${mmStr3(value)}"`;
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
// lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/format-solder-mask-attrs.ts
|
|
398
|
+
var formatSolderMaskAttrs = (platedHole) => {
|
|
399
|
+
let coveredWithSolderMaskAttr = "";
|
|
400
|
+
if (platedHole.is_covered_with_solder_mask !== void 0) {
|
|
401
|
+
coveredWithSolderMaskAttr = ` coveredWithSolderMask={${platedHole.is_covered_with_solder_mask}}`;
|
|
402
|
+
}
|
|
403
|
+
return `${coveredWithSolderMaskAttr}${formatOptionalMmAttr("solderMaskMargin", platedHole.soldermask_margin)}`;
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
// lib/generate-footprint-tsx/convert-plated-holes.ts
|
|
383
407
|
var convertPlatedHoles = (circuitJson) => {
|
|
384
408
|
const platedHoles = su8(circuitJson).pcb_plated_hole.list();
|
|
385
409
|
const elementStrings = [];
|
|
386
410
|
for (const platedHole of platedHoles) {
|
|
387
411
|
if (platedHole.shape === "oval" || platedHole.shape === "pill") {
|
|
388
412
|
elementStrings.push(
|
|
389
|
-
`<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${
|
|
413
|
+
`<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr4(platedHole.x)}" pcbY="${mmStr4(platedHole.y)}"${formatSolderMaskAttrs(platedHole)} outerHeight="${mmStr4(platedHole.outer_height)}" outerWidth="${mmStr4(platedHole.outer_width)}" holeHeight="${mmStr4(platedHole.hole_height)}" holeWidth="${mmStr4(platedHole.hole_width)}" height="${mmStr4(platedHole.hole_height)}" shape="${platedHole.shape}"${formatPcbRotationAttr("ccw_rotation" in platedHole ? platedHole.ccw_rotation : void 0)} />`
|
|
390
414
|
);
|
|
391
415
|
} else if (platedHole.shape === "circle") {
|
|
392
416
|
elementStrings.push(
|
|
393
|
-
`<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${
|
|
417
|
+
`<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr4(platedHole.x)}" pcbY="${mmStr4(platedHole.y)}"${formatSolderMaskAttrs(platedHole)} outerDiameter="${mmStr4(platedHole.outer_diameter)}" holeDiameter="${mmStr4(platedHole.hole_diameter)}" shape="circle" />`
|
|
394
418
|
);
|
|
395
419
|
} else if (platedHole.shape === "circular_hole_with_rect_pad") {
|
|
396
420
|
elementStrings.push(
|
|
397
|
-
`<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${
|
|
421
|
+
`<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr4(platedHole.x)}" pcbY="${mmStr4(platedHole.y)}"${platedHole.hole_shape === void 0 ? "" : ` holeShape="${platedHole.hole_shape}"`}${platedHole.pad_shape === void 0 ? "" : ` padShape="${platedHole.pad_shape}"`}${formatSolderMaskAttrs(platedHole)} holeDiameter="${mmStr4(platedHole.hole_diameter)}" rectPadWidth="${mmStr4(platedHole.rect_pad_width)}" rectPadHeight="${mmStr4(platedHole.rect_pad_height)}"${formatOptionalMmAttr("rectBorderRadius", platedHole.rect_border_radius)}${formatOptionalMmAttr("holeOffsetX", platedHole.hole_offset_x)}${formatOptionalMmAttr("holeOffsetY", platedHole.hole_offset_y)}${formatPcbRotationAttr(platedHole.rect_ccw_rotation)} shape="circular_hole_with_rect_pad" />`
|
|
398
422
|
);
|
|
399
423
|
} else if (platedHole.shape === "pill_hole_with_rect_pad" || platedHole.shape === "rotated_pill_hole_with_rect_pad") {
|
|
400
424
|
const holeShape = platedHole.shape === "rotated_pill_hole_with_rect_pad" ? "pill" : platedHole.hole_shape;
|
|
401
425
|
const rotation = platedHole.shape === "rotated_pill_hole_with_rect_pad" ? platedHole.hole_ccw_rotation : void 0;
|
|
402
426
|
elementStrings.push(
|
|
403
|
-
`<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${
|
|
427
|
+
`<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr4(platedHole.x)}" pcbY="${mmStr4(platedHole.y)}"${holeShape === void 0 ? "" : ` holeShape="${holeShape}"`}${platedHole.pad_shape === void 0 ? "" : ` padShape="${platedHole.pad_shape}"`}${formatSolderMaskAttrs(platedHole)} holeWidth="${mmStr4(platedHole.hole_width)}" holeHeight="${mmStr4(platedHole.hole_height)}" rectPadWidth="${mmStr4(platedHole.rect_pad_width)}" rectPadHeight="${mmStr4(platedHole.rect_pad_height)}"${formatOptionalMmAttr("rectBorderRadius", platedHole.rect_border_radius)}${formatOptionalMmAttr("holeOffsetX", platedHole.hole_offset_x)}${formatOptionalMmAttr("holeOffsetY", platedHole.hole_offset_y)}${formatPcbRotationAttr(rotation)} shape="pill_hole_with_rect_pad" />`
|
|
404
428
|
);
|
|
405
429
|
} else if (platedHole.shape === "hole_with_polygon_pad") {
|
|
406
|
-
const holeSizeAttrs = platedHole.hole_shape === "circle" ? ` holeDiameter="${
|
|
430
|
+
const holeSizeAttrs = platedHole.hole_shape === "circle" ? ` holeDiameter="${mmStr4(platedHole.hole_diameter ?? 0)}"` : `${formatOptionalMmAttr("holeWidth", platedHole.hole_width)}${formatOptionalMmAttr("holeHeight", platedHole.hole_height)}`;
|
|
407
431
|
elementStrings.push(
|
|
408
|
-
`<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${
|
|
432
|
+
`<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr4(platedHole.x)}" pcbY="${mmStr4(platedHole.y)}"${platedHole.hole_shape === void 0 ? "" : ` holeShape="${platedHole.hole_shape}"`}${formatSolderMaskAttrs(platedHole)}${holeSizeAttrs} padOutline={${JSON.stringify(platedHole.pad_outline)}} holeOffsetX="${mmStr4(platedHole.hole_offset_x ?? 0)}" holeOffsetY="${mmStr4(platedHole.hole_offset_y ?? 0)}" shape="hole_with_polygon_pad" />`
|
|
409
433
|
);
|
|
410
434
|
}
|
|
411
435
|
}
|
|
@@ -481,7 +505,7 @@ var convertSilkscreen = (circuitJson) => {
|
|
|
481
505
|
|
|
482
506
|
// lib/generate-footprint-tsx/convert-silkscreen-text.ts
|
|
483
507
|
import { su as su10 } from "@tscircuit/soup-util";
|
|
484
|
-
import { mmStr as
|
|
508
|
+
import { mmStr as mmStr5 } from "@tscircuit/mm";
|
|
485
509
|
var convertSilkscreenText = (circuitJson) => {
|
|
486
510
|
const silkscreenTexts = su10(circuitJson).pcb_silkscreen_text.list();
|
|
487
511
|
const elementStrings = [];
|
|
@@ -491,7 +515,7 @@ var convertSilkscreenText = (circuitJson) => {
|
|
|
491
515
|
const knockoutPadding = silkscreenText.knockout_padding;
|
|
492
516
|
const hasUniformKnockoutPadding = knockoutPadding && knockoutPadding.left === knockoutPadding.top && knockoutPadding.top === knockoutPadding.right && knockoutPadding.right === knockoutPadding.bottom;
|
|
493
517
|
elementStrings.push(
|
|
494
|
-
`<silkscreentext pcbX={${pcbX}} pcbY={${pcbY}} anchorAlignment="${silkscreenText.anchor_alignment}" fontSize={${silkscreenText.font_size}}${silkscreenText.font !== void 0 ? ` font="${silkscreenText.font}"` : ""}${silkscreenText.ccw_rotation !== void 0 ? ` pcbRotation="${typeof silkscreenText.ccw_rotation === "number" ? `${silkscreenText.ccw_rotation}deg` : silkscreenText.ccw_rotation}"` : ""}${silkscreenText.is_knockout !== void 0 ? ` isKnockout={${silkscreenText.is_knockout}}` : ""}${knockoutPadding ? hasUniformKnockoutPadding ? ` knockoutPadding="${
|
|
518
|
+
`<silkscreentext pcbX={${pcbX}} pcbY={${pcbY}} anchorAlignment="${silkscreenText.anchor_alignment}" fontSize={${silkscreenText.font_size}}${silkscreenText.font !== void 0 ? ` font="${silkscreenText.font}"` : ""}${silkscreenText.ccw_rotation !== void 0 ? ` pcbRotation="${typeof silkscreenText.ccw_rotation === "number" ? `${silkscreenText.ccw_rotation}deg` : silkscreenText.ccw_rotation}"` : ""}${silkscreenText.is_knockout !== void 0 ? ` isKnockout={${silkscreenText.is_knockout}}` : ""}${knockoutPadding ? hasUniformKnockoutPadding ? ` knockoutPadding="${mmStr5(knockoutPadding.left)}"` : ` knockoutPaddingLeft="${mmStr5(knockoutPadding.left)}" knockoutPaddingTop="${mmStr5(knockoutPadding.top)}" knockoutPaddingRight="${mmStr5(knockoutPadding.right)}" knockoutPaddingBottom="${mmStr5(knockoutPadding.bottom)}"` : ""}${silkscreenText.is_mirrored !== void 0 ? ` mirrored={${silkscreenText.is_mirrored}}` : ""}${silkscreenText.layer !== void 0 ? ` layer="${silkscreenText.layer}"` : ""} text="${escapeJsxText(silkscreenText.text)}" />`
|
|
495
519
|
);
|
|
496
520
|
}
|
|
497
521
|
return elementStrings;
|
|
@@ -499,103 +523,49 @@ var convertSilkscreenText = (circuitJson) => {
|
|
|
499
523
|
|
|
500
524
|
// lib/generate-footprint-tsx/convert-smt-pads.ts
|
|
501
525
|
import { su as su11 } from "@tscircuit/soup-util";
|
|
502
|
-
import { mmStr as
|
|
526
|
+
import { mmStr as mmStr6 } from "@tscircuit/mm";
|
|
503
527
|
var convertSmtPads = (circuitJson) => {
|
|
504
528
|
const smtPads = su11(circuitJson).pcb_smtpad.list();
|
|
505
529
|
const elementStrings = [];
|
|
506
530
|
for (const smtPad of smtPads) {
|
|
507
531
|
const commonAttrs = [];
|
|
532
|
+
const solderMaskAttrs = formatSolderMaskAttrs(smtPad);
|
|
508
533
|
if (smtPad.port_hints !== void 0) {
|
|
509
534
|
commonAttrs.push(`portHints={${JSON.stringify(smtPad.port_hints)}}`);
|
|
510
535
|
}
|
|
511
536
|
if ("x" in smtPad && smtPad.x !== void 0) {
|
|
512
|
-
commonAttrs.push(`pcbX="${
|
|
537
|
+
commonAttrs.push(`pcbX="${mmStr6(smtPad.x)}"`);
|
|
513
538
|
}
|
|
514
539
|
if ("y" in smtPad && smtPad.y !== void 0) {
|
|
515
|
-
commonAttrs.push(`pcbY="${
|
|
540
|
+
commonAttrs.push(`pcbY="${mmStr6(smtPad.y)}"`);
|
|
516
541
|
}
|
|
517
542
|
if (smtPad.layer !== void 0) {
|
|
518
543
|
commonAttrs.push(`layer="${smtPad.layer}"`);
|
|
519
544
|
}
|
|
520
|
-
if (smtPad.is_covered_with_solder_mask !== void 0) {
|
|
521
|
-
commonAttrs.push(
|
|
522
|
-
`coveredWithSolderMask={${smtPad.is_covered_with_solder_mask}}`
|
|
523
|
-
);
|
|
524
|
-
}
|
|
525
|
-
if (smtPad.soldermask_margin !== void 0) {
|
|
526
|
-
commonAttrs.push(`solderMaskMargin="${mmStr5(smtPad.soldermask_margin)}"`);
|
|
527
|
-
}
|
|
528
545
|
if (smtPad.shape === "circle") {
|
|
529
546
|
elementStrings.push(
|
|
530
|
-
`<smtpad ${commonAttrs.join(" ")} radius="${
|
|
547
|
+
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs} radius="${mmStr6(smtPad.radius ?? 0)}" shape="circle" />`
|
|
531
548
|
);
|
|
532
549
|
} else if (smtPad.shape === "rect") {
|
|
533
|
-
if (smtPad.rect_border_radius !== void 0) {
|
|
534
|
-
commonAttrs.push(
|
|
535
|
-
`rectBorderRadius="${mmStr5(smtPad.rect_border_radius)}"`
|
|
536
|
-
);
|
|
537
|
-
}
|
|
538
|
-
if (smtPad.corner_radius !== void 0) {
|
|
539
|
-
commonAttrs.push(`cornerRadius="${mmStr5(smtPad.corner_radius)}"`);
|
|
540
|
-
}
|
|
541
|
-
if (smtPad.soldermask_margin_left !== void 0) {
|
|
542
|
-
commonAttrs.push(
|
|
543
|
-
`solderMaskMarginLeft="${mmStr5(smtPad.soldermask_margin_left)}"`
|
|
544
|
-
);
|
|
545
|
-
}
|
|
546
|
-
if (smtPad.soldermask_margin_top !== void 0) {
|
|
547
|
-
commonAttrs.push(
|
|
548
|
-
`solderMaskMarginTop="${mmStr5(smtPad.soldermask_margin_top)}"`
|
|
549
|
-
);
|
|
550
|
-
}
|
|
551
|
-
if (smtPad.soldermask_margin_right !== void 0) {
|
|
552
|
-
commonAttrs.push(
|
|
553
|
-
`solderMaskMarginRight="${mmStr5(smtPad.soldermask_margin_right)}"`
|
|
554
|
-
);
|
|
555
|
-
}
|
|
556
|
-
if (smtPad.soldermask_margin_bottom !== void 0) {
|
|
557
|
-
commonAttrs.push(
|
|
558
|
-
`solderMaskMarginBottom="${mmStr5(smtPad.soldermask_margin_bottom)}"`
|
|
559
|
-
);
|
|
560
|
-
}
|
|
561
550
|
elementStrings.push(
|
|
562
|
-
`<smtpad ${commonAttrs.join(" ")} width="${
|
|
551
|
+
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs}${formatOptionalMmAttr("rectBorderRadius", smtPad.rect_border_radius)}${formatOptionalMmAttr("cornerRadius", smtPad.corner_radius)}${formatOptionalMmAttr("solderMaskMarginLeft", smtPad.soldermask_margin_left)}${formatOptionalMmAttr("solderMaskMarginTop", smtPad.soldermask_margin_top)}${formatOptionalMmAttr("solderMaskMarginRight", smtPad.soldermask_margin_right)}${formatOptionalMmAttr("solderMaskMarginBottom", smtPad.soldermask_margin_bottom)} width="${mmStr6(smtPad.width ?? 0)}" height="${mmStr6(smtPad.height ?? 0)}" shape="rect" />`
|
|
563
552
|
);
|
|
564
553
|
} else if (smtPad.shape === "pill") {
|
|
565
554
|
elementStrings.push(
|
|
566
|
-
`<smtpad ${commonAttrs.join(" ")} width="${
|
|
555
|
+
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs} width="${mmStr6(smtPad.width ?? 0)}" height="${mmStr6(smtPad.height ?? 0)}" radius="${mmStr6(smtPad.radius ?? 0)}" shape="pill" />`
|
|
556
|
+
);
|
|
557
|
+
} else if (smtPad.shape === "rotated_pill") {
|
|
558
|
+
elementStrings.push(
|
|
559
|
+
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs} width="${mmStr6(smtPad.width ?? 0)}" height="${mmStr6(smtPad.height ?? 0)}" radius="${mmStr6(smtPad.radius ?? 0)}"${formatPcbRotationAttr(smtPad.ccw_rotation)} shape="pill" />`
|
|
567
560
|
);
|
|
568
561
|
} else if (smtPad.shape === "polygon") {
|
|
569
562
|
elementStrings.push(
|
|
570
|
-
`<smtpad ${commonAttrs.join(" ")} shape="polygon" points={${JSON.stringify(smtPad.points)}} />`
|
|
563
|
+
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs} shape="polygon" points={${JSON.stringify(smtPad.points)}} />`
|
|
571
564
|
);
|
|
572
565
|
} else if (smtPad.shape === "rotated_rect") {
|
|
573
566
|
const cornerRadius = smtPad.corner_radius ?? smtPad.rect_border_radius ?? void 0;
|
|
574
|
-
if (cornerRadius !== void 0) {
|
|
575
|
-
commonAttrs.push(`cornerRadius="${mmStr5(cornerRadius)}"`);
|
|
576
|
-
}
|
|
577
|
-
if (smtPad.soldermask_margin_left !== void 0) {
|
|
578
|
-
commonAttrs.push(
|
|
579
|
-
`solderMaskMarginLeft="${mmStr5(smtPad.soldermask_margin_left)}"`
|
|
580
|
-
);
|
|
581
|
-
}
|
|
582
|
-
if (smtPad.soldermask_margin_top !== void 0) {
|
|
583
|
-
commonAttrs.push(
|
|
584
|
-
`solderMaskMarginTop="${mmStr5(smtPad.soldermask_margin_top)}"`
|
|
585
|
-
);
|
|
586
|
-
}
|
|
587
|
-
if (smtPad.soldermask_margin_right !== void 0) {
|
|
588
|
-
commonAttrs.push(
|
|
589
|
-
`solderMaskMarginRight="${mmStr5(smtPad.soldermask_margin_right)}"`
|
|
590
|
-
);
|
|
591
|
-
}
|
|
592
|
-
if (smtPad.soldermask_margin_bottom !== void 0) {
|
|
593
|
-
commonAttrs.push(
|
|
594
|
-
`solderMaskMarginBottom="${mmStr5(smtPad.soldermask_margin_bottom)}"`
|
|
595
|
-
);
|
|
596
|
-
}
|
|
597
567
|
elementStrings.push(
|
|
598
|
-
`<smtpad ${commonAttrs.join(" ")} width="${
|
|
568
|
+
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs}${formatOptionalMmAttr("cornerRadius", cornerRadius)}${formatOptionalMmAttr("solderMaskMarginLeft", smtPad.soldermask_margin_left)}${formatOptionalMmAttr("solderMaskMarginTop", smtPad.soldermask_margin_top)}${formatOptionalMmAttr("solderMaskMarginRight", smtPad.soldermask_margin_right)}${formatOptionalMmAttr("solderMaskMarginBottom", smtPad.soldermask_margin_bottom)} width="${mmStr6(smtPad.width ?? 0)}" height="${mmStr6(smtPad.height ?? 0)}"${formatPcbRotationAttr(smtPad.ccw_rotation)} shape="rotated_rect" />`
|
|
599
569
|
);
|
|
600
570
|
}
|
|
601
571
|
}
|
|
@@ -634,17 +604,17 @@ var getBoardUsingTemplate = ({ circuitJson }) => {
|
|
|
634
604
|
const boardProps = [];
|
|
635
605
|
if (pcbBoard) {
|
|
636
606
|
if (pcbBoard.width !== void 0) {
|
|
637
|
-
boardProps.push(`width="${
|
|
607
|
+
boardProps.push(`width="${mmStr7(pcbBoard.width)}"`);
|
|
638
608
|
}
|
|
639
609
|
if (pcbBoard.height !== void 0) {
|
|
640
|
-
boardProps.push(`height="${
|
|
610
|
+
boardProps.push(`height="${mmStr7(pcbBoard.height)}"`);
|
|
641
611
|
}
|
|
642
612
|
if (pcbBoard.outline && pcbBoard.outline.length > 0) {
|
|
643
613
|
const points = pcbBoard.outline.map((p) => `{ x: ${p.x}, y: ${p.y} }`).join(", ");
|
|
644
614
|
boardProps.push(`outline={[${points}]}`);
|
|
645
615
|
}
|
|
646
616
|
if (pcbBoard.thickness !== void 0) {
|
|
647
|
-
boardProps.push(`thickness="${
|
|
617
|
+
boardProps.push(`thickness="${mmStr7(pcbBoard.thickness)}"`);
|
|
648
618
|
}
|
|
649
619
|
if (pcbBoard.num_layers !== void 0) {
|
|
650
620
|
boardProps.push(`layers={${pcbBoard.num_layers}}`);
|
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-UXTI3RT6.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.41",
|
|
20
20
|
scripts: {
|
|
21
21
|
build: "tsup-node lib/index.ts cli/main.ts --format esm --dts",
|
|
22
22
|
test: "bun test",
|
package/dist/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { su } from "@tscircuit/soup-util"
|
|
2
2
|
import type { FootprintElementConverter } from "./converter-types"
|
|
3
|
-
import { escapeJsxText } from "./
|
|
3
|
+
import { escapeJsxText } from "./footprint-tsx-attribute-formatters/escape-jsx-text"
|
|
4
4
|
|
|
5
5
|
export const convertCopperText: FootprintElementConverter = (circuitJson) => {
|
|
6
6
|
const copperTexts = su(circuitJson).pcb_copper_text.list()
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { su } from "@tscircuit/soup-util"
|
|
2
2
|
import type { FootprintElementConverter } from "./converter-types"
|
|
3
|
+
import { formatPcbRotationAttr } from "./footprint-tsx-attribute-formatters/format-pcb-rotation-attr"
|
|
3
4
|
|
|
4
5
|
export const convertCourtyard: FootprintElementConverter = (circuitJson) => {
|
|
5
6
|
const courtyardOutlines = su(circuitJson).pcb_courtyard_outline.list()
|
|
@@ -28,6 +29,9 @@ export const convertCourtyard: FootprintElementConverter = (circuitJson) => {
|
|
|
28
29
|
if (courtyardRect.layer !== undefined) {
|
|
29
30
|
attrs.push(`layer="${courtyardRect.layer}"`)
|
|
30
31
|
}
|
|
32
|
+
if (courtyardRect.ccw_rotation !== undefined) {
|
|
33
|
+
attrs.push(formatPcbRotationAttr(courtyardRect.ccw_rotation).trimStart())
|
|
34
|
+
}
|
|
31
35
|
|
|
32
36
|
elementStrings.push(`<courtyardrect ${attrs.join(" ")} />`)
|
|
33
37
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { su } from "@tscircuit/soup-util"
|
|
2
2
|
import type { FootprintElementConverter } from "./converter-types"
|
|
3
|
-
import { formatMm } from "./
|
|
3
|
+
import { formatMm } from "./footprint-tsx-attribute-formatters/format-mm"
|
|
4
4
|
|
|
5
5
|
export const convertCutouts: FootprintElementConverter = (circuitJson) => {
|
|
6
6
|
const pcbCutouts = su(circuitJson).pcb_cutout.list()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { su } from "@tscircuit/soup-util"
|
|
2
2
|
import type { FootprintElementConverter } from "./converter-types"
|
|
3
|
-
import { escapeJsxText } from "./
|
|
3
|
+
import { escapeJsxText } from "./footprint-tsx-attribute-formatters/escape-jsx-text"
|
|
4
4
|
|
|
5
5
|
export const convertFabrication: FootprintElementConverter = (circuitJson) => {
|
|
6
6
|
const fabricationNotePaths = su(circuitJson).pcb_fabrication_note_path.list()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { su } from "@tscircuit/soup-util"
|
|
2
2
|
import { mmStr } from "@tscircuit/mm"
|
|
3
3
|
import type { FootprintElementConverter } from "./converter-types"
|
|
4
|
-
import { formatPcbRotationAttr } from "./
|
|
4
|
+
import { formatPcbRotationAttr } from "./footprint-tsx-attribute-formatters/format-pcb-rotation-attr"
|
|
5
5
|
|
|
6
6
|
export const convertHoles: FootprintElementConverter = (circuitJson) => {
|
|
7
7
|
const holes = su(circuitJson).pcb_hole.list()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { su } from "@tscircuit/soup-util"
|
|
2
2
|
import type { FootprintElementConverter } from "./converter-types"
|
|
3
|
-
import { formatMm } from "./
|
|
3
|
+
import { formatMm } from "./footprint-tsx-attribute-formatters/format-mm"
|
|
4
4
|
|
|
5
5
|
export const convertKeepouts: FootprintElementConverter = (circuitJson) => {
|
|
6
6
|
const pcbKeepouts = su(circuitJson).pcb_keepout.list()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { su } from "@tscircuit/soup-util"
|
|
2
2
|
import type { FootprintElementConverter } from "./converter-types"
|
|
3
|
-
import { escapeJsxText } from "./
|
|
3
|
+
import { escapeJsxText } from "./footprint-tsx-attribute-formatters/escape-jsx-text"
|
|
4
4
|
|
|
5
5
|
export const convertNotes: FootprintElementConverter = (circuitJson) => {
|
|
6
6
|
const noteTexts = su(circuitJson).pcb_note_text.list()
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { su } from "@tscircuit/soup-util"
|
|
2
2
|
import { mmStr } from "@tscircuit/mm"
|
|
3
3
|
import type { FootprintElementConverter } from "./converter-types"
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
formatSolderMaskAttrs,
|
|
8
|
-
} from "./helpers"
|
|
4
|
+
import { formatOptionalMmAttr } from "./footprint-tsx-attribute-formatters/format-optional-mm-attr"
|
|
5
|
+
import { formatPcbRotationAttr } from "./footprint-tsx-attribute-formatters/format-pcb-rotation-attr"
|
|
6
|
+
import { formatSolderMaskAttrs } from "./footprint-tsx-attribute-formatters/format-solder-mask-attrs"
|
|
9
7
|
|
|
10
8
|
export const convertPlatedHoles: FootprintElementConverter = (circuitJson) => {
|
|
11
9
|
const platedHoles = su(circuitJson).pcb_plated_hole.list()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { su } from "@tscircuit/soup-util"
|
|
2
2
|
import { mmStr } from "@tscircuit/mm"
|
|
3
3
|
import type { FootprintElementConverter } from "./converter-types"
|
|
4
|
-
import { escapeJsxText } from "./
|
|
4
|
+
import { escapeJsxText } from "./footprint-tsx-attribute-formatters/escape-jsx-text"
|
|
5
5
|
|
|
6
6
|
export const convertSilkscreenText: FootprintElementConverter = (
|
|
7
7
|
circuitJson,
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { su } from "@tscircuit/soup-util"
|
|
2
2
|
import { mmStr } from "@tscircuit/mm"
|
|
3
3
|
import type { FootprintElementConverter } from "./converter-types"
|
|
4
|
-
import {
|
|
4
|
+
import { formatOptionalMmAttr } from "./footprint-tsx-attribute-formatters/format-optional-mm-attr"
|
|
5
|
+
import { formatPcbRotationAttr } from "./footprint-tsx-attribute-formatters/format-pcb-rotation-attr"
|
|
6
|
+
import { formatSolderMaskAttrs } from "./footprint-tsx-attribute-formatters/format-solder-mask-attrs"
|
|
5
7
|
|
|
6
8
|
export const convertSmtPads: FootprintElementConverter = (circuitJson) => {
|
|
7
9
|
const smtPads = su(circuitJson).pcb_smtpad.list()
|
|
@@ -9,6 +11,7 @@ export const convertSmtPads: FootprintElementConverter = (circuitJson) => {
|
|
|
9
11
|
|
|
10
12
|
for (const smtPad of smtPads) {
|
|
11
13
|
const commonAttrs: string[] = []
|
|
14
|
+
const solderMaskAttrs = formatSolderMaskAttrs(smtPad)
|
|
12
15
|
|
|
13
16
|
if (smtPad.port_hints !== undefined) {
|
|
14
17
|
commonAttrs.push(`portHints={${JSON.stringify(smtPad.port_hints)}}`)
|
|
@@ -22,88 +25,33 @@ export const convertSmtPads: FootprintElementConverter = (circuitJson) => {
|
|
|
22
25
|
if (smtPad.layer !== undefined) {
|
|
23
26
|
commonAttrs.push(`layer="${smtPad.layer}"`)
|
|
24
27
|
}
|
|
25
|
-
if (smtPad.is_covered_with_solder_mask !== undefined) {
|
|
26
|
-
commonAttrs.push(
|
|
27
|
-
`coveredWithSolderMask={${smtPad.is_covered_with_solder_mask}}`,
|
|
28
|
-
)
|
|
29
|
-
}
|
|
30
|
-
if (smtPad.soldermask_margin !== undefined) {
|
|
31
|
-
commonAttrs.push(`solderMaskMargin="${mmStr(smtPad.soldermask_margin)}"`)
|
|
32
|
-
}
|
|
33
28
|
|
|
34
29
|
if (smtPad.shape === "circle") {
|
|
35
30
|
elementStrings.push(
|
|
36
|
-
`<smtpad ${commonAttrs.join(" ")} radius="${mmStr(smtPad.radius ?? 0)}" shape="circle" />`,
|
|
31
|
+
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs} radius="${mmStr(smtPad.radius ?? 0)}" shape="circle" />`,
|
|
37
32
|
)
|
|
38
33
|
} else if (smtPad.shape === "rect") {
|
|
39
|
-
if (smtPad.rect_border_radius !== undefined) {
|
|
40
|
-
commonAttrs.push(
|
|
41
|
-
`rectBorderRadius="${mmStr(smtPad.rect_border_radius)}"`,
|
|
42
|
-
)
|
|
43
|
-
}
|
|
44
|
-
if (smtPad.corner_radius !== undefined) {
|
|
45
|
-
commonAttrs.push(`cornerRadius="${mmStr(smtPad.corner_radius)}"`)
|
|
46
|
-
}
|
|
47
|
-
if (smtPad.soldermask_margin_left !== undefined) {
|
|
48
|
-
commonAttrs.push(
|
|
49
|
-
`solderMaskMarginLeft="${mmStr(smtPad.soldermask_margin_left)}"`,
|
|
50
|
-
)
|
|
51
|
-
}
|
|
52
|
-
if (smtPad.soldermask_margin_top !== undefined) {
|
|
53
|
-
commonAttrs.push(
|
|
54
|
-
`solderMaskMarginTop="${mmStr(smtPad.soldermask_margin_top)}"`,
|
|
55
|
-
)
|
|
56
|
-
}
|
|
57
|
-
if (smtPad.soldermask_margin_right !== undefined) {
|
|
58
|
-
commonAttrs.push(
|
|
59
|
-
`solderMaskMarginRight="${mmStr(smtPad.soldermask_margin_right)}"`,
|
|
60
|
-
)
|
|
61
|
-
}
|
|
62
|
-
if (smtPad.soldermask_margin_bottom !== undefined) {
|
|
63
|
-
commonAttrs.push(
|
|
64
|
-
`solderMaskMarginBottom="${mmStr(smtPad.soldermask_margin_bottom)}"`,
|
|
65
|
-
)
|
|
66
|
-
}
|
|
67
34
|
elementStrings.push(
|
|
68
|
-
`<smtpad ${commonAttrs.join(" ")} width="${mmStr(smtPad.width ?? 0)}" height="${mmStr(smtPad.height ?? 0)}" shape="rect" />`,
|
|
35
|
+
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs}${formatOptionalMmAttr("rectBorderRadius", smtPad.rect_border_radius)}${formatOptionalMmAttr("cornerRadius", smtPad.corner_radius)}${formatOptionalMmAttr("solderMaskMarginLeft", smtPad.soldermask_margin_left)}${formatOptionalMmAttr("solderMaskMarginTop", smtPad.soldermask_margin_top)}${formatOptionalMmAttr("solderMaskMarginRight", smtPad.soldermask_margin_right)}${formatOptionalMmAttr("solderMaskMarginBottom", smtPad.soldermask_margin_bottom)} width="${mmStr(smtPad.width ?? 0)}" height="${mmStr(smtPad.height ?? 0)}" shape="rect" />`,
|
|
69
36
|
)
|
|
70
37
|
} else if (smtPad.shape === "pill") {
|
|
71
38
|
elementStrings.push(
|
|
72
|
-
`<smtpad ${commonAttrs.join(" ")} width="${mmStr(smtPad.width ?? 0)}" height="${mmStr(smtPad.height ?? 0)}" radius="${mmStr(smtPad.radius ?? 0)}" shape="pill" />`,
|
|
39
|
+
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs} width="${mmStr(smtPad.width ?? 0)}" height="${mmStr(smtPad.height ?? 0)}" radius="${mmStr(smtPad.radius ?? 0)}" shape="pill" />`,
|
|
40
|
+
)
|
|
41
|
+
} else if (smtPad.shape === "rotated_pill") {
|
|
42
|
+
elementStrings.push(
|
|
43
|
+
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs} width="${mmStr(smtPad.width ?? 0)}" height="${mmStr(smtPad.height ?? 0)}" radius="${mmStr(smtPad.radius ?? 0)}"${formatPcbRotationAttr(smtPad.ccw_rotation)} shape="pill" />`,
|
|
73
44
|
)
|
|
74
45
|
} else if (smtPad.shape === "polygon") {
|
|
75
46
|
elementStrings.push(
|
|
76
|
-
`<smtpad ${commonAttrs.join(" ")} shape="polygon" points={${JSON.stringify(smtPad.points)}} />`,
|
|
47
|
+
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs} shape="polygon" points={${JSON.stringify(smtPad.points)}} />`,
|
|
77
48
|
)
|
|
78
49
|
} else if (smtPad.shape === "rotated_rect") {
|
|
79
50
|
const cornerRadius =
|
|
80
51
|
smtPad.corner_radius ?? smtPad.rect_border_radius ?? undefined
|
|
81
52
|
|
|
82
|
-
if (cornerRadius !== undefined) {
|
|
83
|
-
commonAttrs.push(`cornerRadius="${mmStr(cornerRadius)}"`)
|
|
84
|
-
}
|
|
85
|
-
if (smtPad.soldermask_margin_left !== undefined) {
|
|
86
|
-
commonAttrs.push(
|
|
87
|
-
`solderMaskMarginLeft="${mmStr(smtPad.soldermask_margin_left)}"`,
|
|
88
|
-
)
|
|
89
|
-
}
|
|
90
|
-
if (smtPad.soldermask_margin_top !== undefined) {
|
|
91
|
-
commonAttrs.push(
|
|
92
|
-
`solderMaskMarginTop="${mmStr(smtPad.soldermask_margin_top)}"`,
|
|
93
|
-
)
|
|
94
|
-
}
|
|
95
|
-
if (smtPad.soldermask_margin_right !== undefined) {
|
|
96
|
-
commonAttrs.push(
|
|
97
|
-
`solderMaskMarginRight="${mmStr(smtPad.soldermask_margin_right)}"`,
|
|
98
|
-
)
|
|
99
|
-
}
|
|
100
|
-
if (smtPad.soldermask_margin_bottom !== undefined) {
|
|
101
|
-
commonAttrs.push(
|
|
102
|
-
`solderMaskMarginBottom="${mmStr(smtPad.soldermask_margin_bottom)}"`,
|
|
103
|
-
)
|
|
104
|
-
}
|
|
105
53
|
elementStrings.push(
|
|
106
|
-
`<smtpad ${commonAttrs.join(" ")} width="${mmStr(smtPad.width ?? 0)}" height="${mmStr(smtPad.height ?? 0)}"${formatPcbRotationAttr(smtPad.ccw_rotation)} shape="rotated_rect" />`,
|
|
54
|
+
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs}${formatOptionalMmAttr("cornerRadius", cornerRadius)}${formatOptionalMmAttr("solderMaskMarginLeft", smtPad.soldermask_margin_left)}${formatOptionalMmAttr("solderMaskMarginTop", smtPad.soldermask_margin_top)}${formatOptionalMmAttr("solderMaskMarginRight", smtPad.soldermask_margin_right)}${formatOptionalMmAttr("solderMaskMarginBottom", smtPad.soldermask_margin_bottom)} width="${mmStr(smtPad.width ?? 0)}" height="${mmStr(smtPad.height ?? 0)}"${formatPcbRotationAttr(smtPad.ccw_rotation)} shape="rotated_rect" />`,
|
|
107
55
|
)
|
|
108
56
|
}
|
|
109
57
|
}
|
package/lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/format-pcb-rotation-attr.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const formatPcbRotationAttr = (
|
|
2
|
+
rotation: string | number | undefined,
|
|
3
|
+
attrName = "pcbRotation",
|
|
4
|
+
): string => {
|
|
5
|
+
if (rotation === undefined) return ""
|
|
6
|
+
const formatted = typeof rotation === "number" ? `${rotation}deg` : rotation
|
|
7
|
+
return ` ${attrName}="${formatted}"`
|
|
8
|
+
}
|
package/lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/format-solder-mask-attrs.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { formatOptionalMmAttr } from "./format-optional-mm-attr"
|
|
2
|
+
|
|
3
|
+
export const formatSolderMaskAttrs = (platedHole: {
|
|
4
|
+
is_covered_with_solder_mask?: boolean
|
|
5
|
+
soldermask_margin?: number
|
|
6
|
+
}): string => {
|
|
7
|
+
let coveredWithSolderMaskAttr = ""
|
|
8
|
+
|
|
9
|
+
if (platedHole.is_covered_with_solder_mask !== undefined) {
|
|
10
|
+
coveredWithSolderMaskAttr = ` coveredWithSolderMask={${platedHole.is_covered_with_solder_mask}}`
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return `${coveredWithSolderMaskAttr}${formatOptionalMmAttr("solderMaskMargin", platedHole.soldermask_margin)}`
|
|
14
|
+
}
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="600" data-software-used-string="@tscircuit/core@0.0.
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="600" data-software-used-string="@tscircuit/core@0.0.1322"><style></style><rect class="boundary" x="0" y="0" fill="#000" width="800" height="600" data-type="pcb_background" data-pcb-layer="global"/><rect class="pcb-boundary" fill="none" stroke="#fff" stroke-width="0.3" x="127.27272727272725" y="27.272727272727252" width="545.4545454545455" height="545.4545454545455" data-type="pcb_boundary" data-pcb-layer="global"/><path class="pcb-board" d="M 127.27272727272725 572.7272727272727 L 672.7272727272727 572.7272727272727 L 672.7272727272727 27.272727272727252 L 127.27272727272725 27.272727272727252 Z" fill="none" stroke="rgba(255, 255, 255, 0.5)" stroke-width="2.7272727272727275" data-type="pcb_board" data-pcb-layer="board"/><rect class="pcb-pad" fill="rgb(77, 127, 196)" x="-27.272727272727273" y="-8.181818181818182" width="54.54545454545455" height="16.363636363636363" transform="translate(372.72727272727275 354.54545454545456) rotate(-45)" data-type="pcb_smtpad" data-pcb-layer="bottom" rx="4.090909090909091" ry="4.090909090909091"/><rect class="pcb-pad" fill="rgb(77, 127, 196)" x="443.6363636363636" y="328.6363636363636" width="49.09090909090909" height="24.545454545454547" data-type="pcb_smtpad" data-pcb-layer="bottom" rx="5.454545454545455" ry="5.454545454545455"/><rect class="pcb-pad" fill="rgb(77, 127, 196)" x="-27.272727272727273" y="-8.181818181818182" width="54.54545454545455" height="16.363636363636363" transform="translate(372.72727272727275 354.54545454545456) rotate(-45)" data-type="pcb_smtpad" data-pcb-layer="bottom" rx="4.090909090909091" ry="4.090909090909091"/><rect class="pcb-pad" fill="rgb(77, 127, 196)" x="443.6363636363636" y="328.6363636363636" width="49.09090909090909" height="24.545454545454547" data-type="pcb_smtpad" data-pcb-layer="bottom" rx="5.454545454545455" ry="5.454545454545455"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="406.8181818181818" y="234.54545454545453" width="40.90909090909091" height="21.81818181818182" rx="10.90909090909091" ry="10.90909090909091" data-type="pcb_smtpad" data-pcb-layer="top"/><polygon class="pcb-pad" fill="rgb(200, 52, 52)" points="400,300 427.27272727272725,300 413.6363636363636,272.72727272727275" data-type="pcb_smtpad" data-pcb-layer="top"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="-30.000000000000004" y="-12.272727272727273" width="60.00000000000001" height="24.545454545454547" rx="12.272727272727273" ry="12.272727272727273" data-type="pcb_smtpad" data-pcb-layer="top" transform="translate(334.54545454545456 256.3636363636364) rotate(-30)"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="406.8181818181818" y="234.54545454545453" width="40.90909090909091" height="21.81818181818182" rx="10.90909090909091" ry="10.90909090909091" data-type="pcb_smtpad" data-pcb-layer="top"/><polygon class="pcb-pad" fill="rgb(200, 52, 52)" points="400,300 427.27272727272725,300 413.6363636363636,272.72727272727275" data-type="pcb_smtpad" data-pcb-layer="top"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="-30.000000000000004" y="-12.272727272727273" width="60.00000000000001" height="24.545454545454547" rx="12.272727272727273" ry="12.272727272727273" data-type="pcb_smtpad" data-pcb-layer="top" transform="translate(334.54545454545456 256.3636363636364) rotate(-30)"/></svg>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="600" data-software-used-string="@tscircuit/core@0.0.
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="600" data-software-used-string="@tscircuit/core@0.0.1322"><style></style><rect class="boundary" x="0" y="0" fill="#000" width="800" height="600" data-type="pcb_background" data-pcb-layer="global"/><rect class="pcb-boundary" fill="none" stroke="#fff" stroke-width="0.3" x="127.27272727272725" y="27.272727272727252" width="545.4545454545455" height="545.4545454545455" data-type="pcb_boundary" data-pcb-layer="global"/><path class="pcb-board" d="M 127.27272727272725 572.7272727272727 L 672.7272727272727 572.7272727272727 L 672.7272727272727 27.272727272727252 L 127.27272727272725 27.272727272727252 Z" fill="none" stroke="rgba(255, 255, 255, 0.5)" stroke-width="2.7272727272727275" data-type="pcb_board" data-pcb-layer="board"/><rect x="506.3636363636364" y="245.45454545454547" width="125.45454545454545" height="98.18181818181819" class="pcb-courtyard-rect pcb-courtyard-bottom" data-pcb-courtyard-rect-id="pcb_courtyard_rect_1" data-type="pcb_courtyard_rect" data-pcb-layer="bottom" stroke-linejoin="round" fill="none" stroke="rgb(38, 233, 255)" stroke-width="1.3636363636363638"/><rect x="506.3636363636364" y="245.45454545454547" width="125.45454545454545" height="98.18181818181819" class="pcb-courtyard-rect pcb-courtyard-bottom" data-pcb-courtyard-rect-id="pcb_courtyard_rect_3" data-type="pcb_courtyard_rect" data-pcb-layer="bottom" stroke-linejoin="round" fill="none" stroke="rgb(38, 233, 255)" stroke-width="1.3636363636363638"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="378.1818181818182" y="287.72727272727275" width="16.363636363636363" height="24.545454545454547" data-type="pcb_smtpad" data-pcb-layer="top"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="378.1818181818182" y="287.72727272727275" width="16.363636363636363" height="24.545454545454547" data-type="pcb_smtpad" data-pcb-layer="top"/><polygon points="187.27272727272728,338.1818181818182 285.45454545454544,338.1818181818182 285.45454545454544,261.8181818181818 187.27272727272728,261.8181818181818" class="pcb-courtyard-outline pcb-courtyard-top" data-pcb-courtyard-outline-id="pcb_courtyard_outline_0" data-type="pcb_courtyard_outline" data-pcb-layer="top" fill="none" stroke="#FF00FF" stroke-width="1.3636363636363638" stroke-linejoin="round"/><rect x="-54.54545454545455" y="-40.90909090909091" width="109.0909090909091" height="81.81818181818181" class="pcb-courtyard-rect pcb-courtyard-top" data-pcb-courtyard-rect-id="pcb_courtyard_rect_0" data-type="pcb_courtyard_rect" data-pcb-layer="top" stroke-linejoin="round" transform="translate(400 300) rotate(-45)" fill="none" stroke="#FF00FF" stroke-width="1.3636363636363638"/><circle cx="410.90909090909093" cy="152.72727272727272" r="57.27272727272727" class="pcb-courtyard-circle pcb-courtyard-top" data-pcb-courtyard-circle-id="pcb_courtyard_circle_0" data-type="pcb_courtyard_circle" data-pcb-layer="top" fill="none" stroke="#FF00FF" stroke-width="1.3636363636363638"/><polygon points="187.27272727272728,338.1818181818182 285.45454545454544,338.1818181818182 285.45454545454544,261.8181818181818 187.27272727272728,261.8181818181818" class="pcb-courtyard-outline pcb-courtyard-top" data-pcb-courtyard-outline-id="pcb_courtyard_outline_1" data-type="pcb_courtyard_outline" data-pcb-layer="top" fill="none" stroke="#FF00FF" stroke-width="1.3636363636363638" stroke-linejoin="round"/><rect x="-54.54545454545455" y="-40.90909090909091" width="109.0909090909091" height="81.81818181818181" class="pcb-courtyard-rect pcb-courtyard-top" data-pcb-courtyard-rect-id="pcb_courtyard_rect_2" data-type="pcb_courtyard_rect" data-pcb-layer="top" stroke-linejoin="round" transform="translate(400 300) rotate(-45)" fill="none" stroke="#FF00FF" stroke-width="1.3636363636363638"/><circle cx="410.90909090909093" cy="152.72727272727272" r="57.27272727272727" class="pcb-courtyard-circle pcb-courtyard-top" data-pcb-courtyard-circle-id="pcb_courtyard_circle_1" data-type="pcb_courtyard_circle" data-pcb-layer="top" fill="none" stroke="#FF00FF" stroke-width="1.3636363636363638"/></svg>
|
|
@@ -18,6 +18,7 @@ test("test16 support pcb smtpad shapes", async () => {
|
|
|
18
18
|
<smtpad portHints={["2"]} layer="top" coveredWithSolderMask={true} solderMaskMargin="0.06mm" shape="polygon" points={[{"x":0,"y":0},{"x":1,"y":0},{"x":0.5,"y":1}]} />
|
|
19
19
|
<smtpad portHints={["3"]} pcbX="-1mm" pcbY="-2mm" layer="bottom" coveredWithSolderMask={true} solderMaskMargin="0.04mm" cornerRadius="0.15mm" solderMaskMarginLeft="0.01mm" solderMaskMarginTop="0.02mm" solderMaskMarginRight="0.03mm" solderMaskMarginBottom="0.05mm" width="2mm" height="0.6mm" pcbRotation="45deg" shape="rotated_rect" />
|
|
20
20
|
<smtpad portHints={["4"]} pcbX="2.5mm" pcbY="-1.5mm" layer="bottom" coveredWithSolderMask={true} solderMaskMargin="0.05mm" rectBorderRadius="0.25mm" cornerRadius="0.2mm" solderMaskMarginLeft="0.11mm" solderMaskMarginTop="0.12mm" solderMaskMarginRight="0.13mm" solderMaskMarginBottom="0.14mm" width="1.8mm" height="0.9mm" shape="rect" />
|
|
21
|
+
<smtpad portHints={["5"]} pcbX="-2.4mm" pcbY="1.6mm" layer="top" coveredWithSolderMask={true} solderMaskMargin="0.07mm" width="2.2mm" height="0.9mm" radius="0.45mm" pcbRotation="30deg" shape="pill" />
|
|
21
22
|
</footprint>}
|
|
22
23
|
{...props}
|
|
23
24
|
/>
|
|
@@ -25,6 +26,7 @@ test("test16 support pcb smtpad shapes", async () => {
|
|
|
25
26
|
`)
|
|
26
27
|
expect(tscircuit).toContain(`pcbRotation="45deg"`)
|
|
27
28
|
expect(tscircuit).toContain(`shape="rotated_rect"`)
|
|
29
|
+
expect(tscircuit).toContain(`pcbRotation="30deg"`)
|
|
28
30
|
|
|
29
31
|
// The generator emits pcbRotation for consistency, but the current smtpad
|
|
30
32
|
// runtime still expects ccwRotation for rotated_rect pads.
|
|
@@ -47,7 +49,7 @@ circuit.add(
|
|
|
47
49
|
(elm): elm is PcbSmtPad => elm.type === "pcb_smtpad",
|
|
48
50
|
)
|
|
49
51
|
|
|
50
|
-
expect(renderedSmtPads).toHaveLength(
|
|
52
|
+
expect(renderedSmtPads).toHaveLength(10)
|
|
51
53
|
expect(renderedSmtPads).toEqual(
|
|
52
54
|
expect.arrayContaining([
|
|
53
55
|
expect.objectContaining({
|
|
@@ -66,6 +68,17 @@ circuit.add(
|
|
|
66
68
|
is_covered_with_solder_mask: true,
|
|
67
69
|
soldermask_margin: 0.05,
|
|
68
70
|
}),
|
|
71
|
+
expect.objectContaining({
|
|
72
|
+
port_hints: ["5"],
|
|
73
|
+
layer: "top",
|
|
74
|
+
shape: "rotated_pill",
|
|
75
|
+
ccw_rotation: 30,
|
|
76
|
+
radius: 0.45,
|
|
77
|
+
width: 2.2,
|
|
78
|
+
height: 0.9,
|
|
79
|
+
is_covered_with_solder_mask: true,
|
|
80
|
+
soldermask_margin: 0.07,
|
|
81
|
+
}),
|
|
69
82
|
]),
|
|
70
83
|
)
|
|
71
84
|
|
|
@@ -167,4 +180,20 @@ const circuitJson: any = [
|
|
|
167
180
|
soldermask_margin_bottom: 0.14,
|
|
168
181
|
port_hints: ["4"],
|
|
169
182
|
},
|
|
183
|
+
{
|
|
184
|
+
type: "pcb_smtpad",
|
|
185
|
+
pcb_smtpad_id: "rotated_pill_pad",
|
|
186
|
+
pcb_component_id: "pcb_generic_component_0",
|
|
187
|
+
shape: "rotated_pill",
|
|
188
|
+
x: -2.4,
|
|
189
|
+
y: 1.6,
|
|
190
|
+
width: 2.2,
|
|
191
|
+
height: 0.9,
|
|
192
|
+
radius: 0.45,
|
|
193
|
+
ccw_rotation: 30,
|
|
194
|
+
layer: "top",
|
|
195
|
+
is_covered_with_solder_mask: true,
|
|
196
|
+
soldermask_margin: 0.07,
|
|
197
|
+
port_hints: ["5"],
|
|
198
|
+
},
|
|
170
199
|
]
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { expect, test } from "bun:test"
|
|
2
|
+
import { convertCircuitJsonToPcbSvg } from "circuit-to-svg"
|
|
2
3
|
import { convertCircuitJsonToTscircuit } from "lib"
|
|
3
4
|
import { runTscircuitCode } from "tscircuit"
|
|
4
5
|
|
|
@@ -13,10 +14,10 @@ test("test8 support courtyard elements", async () => {
|
|
|
13
14
|
<chip
|
|
14
15
|
footprint={<footprint>
|
|
15
16
|
<smtpad portHints={["1"]} pcbX="-0.5mm" pcbY="0mm" layer="top" width="0.6mm" height="0.9mm" shape="rect" />
|
|
16
|
-
<courtyardoutline outline={[{"x":-
|
|
17
|
-
<courtyardrect pcbX={0} pcbY={0} width={4} height={3} layer="top" />
|
|
18
|
-
<courtyardrect pcbX={
|
|
19
|
-
<courtyardcircle pcbX={0.4} pcbY={
|
|
17
|
+
<courtyardoutline outline={[{"x":-7.8,"y":-1.4},{"x":-4.2,"y":-1.4},{"x":-4.2,"y":1.4},{"x":-7.8,"y":1.4}]} layer="top" />
|
|
18
|
+
<courtyardrect pcbX={0} pcbY={0} width={4} height={3} layer="top" pcbRotation="45deg" />
|
|
19
|
+
<courtyardrect pcbX={6.2} pcbY={0.2} width={4.6} height={3.6} layer="bottom" />
|
|
20
|
+
<courtyardcircle pcbX={0.4} pcbY={5.4} radius={2.1} layer="top" />
|
|
20
21
|
</footprint>}
|
|
21
22
|
{...props}
|
|
22
23
|
/>
|
|
@@ -57,6 +58,25 @@ circuit.add(
|
|
|
57
58
|
expect(
|
|
58
59
|
courtyardElements.filter((elm) => elm.type === "pcb_courtyard_circle"),
|
|
59
60
|
).toHaveLength(2)
|
|
61
|
+
expect(
|
|
62
|
+
courtyardElements.filter(
|
|
63
|
+
(elm) =>
|
|
64
|
+
elm.type === "pcb_courtyard_rect" &&
|
|
65
|
+
elm.layer === "top" &&
|
|
66
|
+
elm.center?.x === 0 &&
|
|
67
|
+
elm.center?.y === 0 &&
|
|
68
|
+
elm.width === 4 &&
|
|
69
|
+
elm.height === 3,
|
|
70
|
+
),
|
|
71
|
+
).toEqual([
|
|
72
|
+
expect.objectContaining({ ccw_rotation: 45 }),
|
|
73
|
+
expect.objectContaining({ ccw_rotation: 45 }),
|
|
74
|
+
])
|
|
75
|
+
|
|
76
|
+
const pcbSvg = convertCircuitJsonToPcbSvg(renderedCircuitJson, {
|
|
77
|
+
showCourtyards: true,
|
|
78
|
+
})
|
|
79
|
+
await expect(pcbSvg).toMatchSvgSnapshot(import.meta.path, "courtyard-pcb")
|
|
60
80
|
})
|
|
61
81
|
|
|
62
82
|
const circuitJson: any = [
|
|
@@ -110,10 +130,10 @@ const circuitJson: any = [
|
|
|
110
130
|
pcb_component_id: "pcb_generic_component_0",
|
|
111
131
|
layer: "top",
|
|
112
132
|
outline: [
|
|
113
|
-
{ x: -
|
|
114
|
-
{ x:
|
|
115
|
-
{ x:
|
|
116
|
-
{ x: -
|
|
133
|
+
{ x: -7.8, y: -1.4 },
|
|
134
|
+
{ x: -4.2, y: -1.4 },
|
|
135
|
+
{ x: -4.2, y: 1.4 },
|
|
136
|
+
{ x: -7.8, y: 1.4 },
|
|
117
137
|
],
|
|
118
138
|
},
|
|
119
139
|
{
|
|
@@ -124,12 +144,13 @@ const circuitJson: any = [
|
|
|
124
144
|
width: 4,
|
|
125
145
|
height: 3,
|
|
126
146
|
layer: "top",
|
|
147
|
+
ccw_rotation: 45,
|
|
127
148
|
},
|
|
128
149
|
{
|
|
129
150
|
type: "pcb_courtyard_rect",
|
|
130
151
|
pcb_courtyard_rect_id: "pcb_courtyard_rect_1",
|
|
131
152
|
pcb_component_id: "pcb_generic_component_0",
|
|
132
|
-
center: { x:
|
|
153
|
+
center: { x: 6.2, y: 0.2 },
|
|
133
154
|
width: 4.6,
|
|
134
155
|
height: 3.6,
|
|
135
156
|
layer: "bottom",
|
|
@@ -138,7 +159,7 @@ const circuitJson: any = [
|
|
|
138
159
|
type: "pcb_courtyard_circle",
|
|
139
160
|
pcb_courtyard_circle_id: "pcb_courtyard_circle_0",
|
|
140
161
|
pcb_component_id: "pcb_generic_component_0",
|
|
141
|
-
center: { x: 0.4, y:
|
|
162
|
+
center: { x: 0.4, y: 5.4 },
|
|
142
163
|
radius: 2.1,
|
|
143
164
|
layer: "top",
|
|
144
165
|
},
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { mmStr } from "@tscircuit/mm"
|
|
2
|
-
|
|
3
|
-
export const escapeJsxText = (value: unknown): string =>
|
|
4
|
-
String(value ?? "").replace(/"/g, '\\"')
|
|
5
|
-
|
|
6
|
-
export const formatMm = (value: number | undefined): string => mmStr(value ?? 0)
|
|
7
|
-
|
|
8
|
-
export const formatOptionalMmAttr = (
|
|
9
|
-
attrName: string,
|
|
10
|
-
value: number | undefined,
|
|
11
|
-
): string => {
|
|
12
|
-
if (value === undefined) return ""
|
|
13
|
-
return ` ${attrName}="${mmStr(value)}"`
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const formatSolderMaskAttrs = (platedHole: {
|
|
17
|
-
is_covered_with_solder_mask?: boolean
|
|
18
|
-
soldermask_margin?: number
|
|
19
|
-
}): string =>
|
|
20
|
-
`${
|
|
21
|
-
platedHole.is_covered_with_solder_mask === undefined
|
|
22
|
-
? ""
|
|
23
|
-
: ` coveredWithSolderMask={${platedHole.is_covered_with_solder_mask}}`
|
|
24
|
-
}${formatOptionalMmAttr("solderMaskMargin", platedHole.soldermask_margin)}`
|
|
25
|
-
|
|
26
|
-
export const formatPcbRotationAttr = (
|
|
27
|
-
rotation: string | number | undefined,
|
|
28
|
-
attrName = "pcbRotation",
|
|
29
|
-
): string => {
|
|
30
|
-
if (rotation === undefined) return ""
|
|
31
|
-
const formatted = typeof rotation === "number" ? `${rotation}deg` : rotation
|
|
32
|
-
return ` ${attrName}="${formatted}"`
|
|
33
|
-
}
|