circuit-json-to-tscircuit 0.0.39 → 0.0.41

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.
Files changed (24) hide show
  1. package/dist/{chunk-G5NSFWRY.js → chunk-BA4FQZIF.js} +129 -102
  2. package/dist/cli/main.js +2 -2
  3. package/dist/lib/index.js +1 -1
  4. package/lib/generate-footprint-tsx/convert-copper-text.ts +1 -1
  5. package/lib/generate-footprint-tsx/convert-courtyard.ts +4 -0
  6. package/lib/generate-footprint-tsx/convert-cutouts.ts +1 -1
  7. package/lib/generate-footprint-tsx/convert-fabrication.ts +1 -1
  8. package/lib/generate-footprint-tsx/convert-holes.ts +1 -1
  9. package/lib/generate-footprint-tsx/convert-keepouts.ts +1 -1
  10. package/lib/generate-footprint-tsx/convert-notes.ts +1 -1
  11. package/lib/generate-footprint-tsx/convert-plated-holes.ts +3 -5
  12. package/lib/generate-footprint-tsx/convert-silkscreen-text.ts +1 -1
  13. package/lib/generate-footprint-tsx/convert-smt-pads.ts +1 -1
  14. package/lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/escape-jsx-text.ts +2 -0
  15. package/lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/format-mm.ts +3 -0
  16. package/lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/format-optional-mm-attr.ts +9 -0
  17. package/lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/format-pcb-rotation-attr.ts +8 -0
  18. package/lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/format-solder-mask-attrs.ts +14 -0
  19. package/lib/get-board-using-template.ts +3 -2
  20. package/package.json +1 -1
  21. package/tests/__snapshots__/test20-board-conversion-drops-children-pcb.snap.svg +1 -1
  22. package/tests/__snapshots__/test8-support-courtyard-courtyard-pcb.snap.svg +1 -1
  23. package/tests/test8-support-courtyard.test.tsx +31 -10
  24. package/lib/generate-footprint-tsx/helpers.ts +0 -33
@@ -1,76 +1,16 @@
1
1
  // lib/get-board-using-template.ts
2
- import { mmStr } from "@tscircuit/mm";
3
- import { su } from "@tscircuit/soup-util";
4
- var getBoardUsingTemplate = ({ circuitJson }) => {
5
- const pcbBoard = su(circuitJson).pcb_board.list()[0];
6
- const boardProps = [];
7
- if (pcbBoard) {
8
- if (pcbBoard.width !== void 0) {
9
- boardProps.push(`width="${mmStr(pcbBoard.width)}"`);
10
- }
11
- if (pcbBoard.height !== void 0) {
12
- boardProps.push(`height="${mmStr(pcbBoard.height)}"`);
13
- }
14
- if (pcbBoard.outline && pcbBoard.outline.length > 0) {
15
- const points = pcbBoard.outline.map((p) => `{ x: ${p.x}, y: ${p.y} }`).join(", ");
16
- boardProps.push(`outline={[${points}]}`);
17
- }
18
- if (pcbBoard.thickness !== void 0) {
19
- boardProps.push(`thickness="${mmStr(pcbBoard.thickness)}"`);
20
- }
21
- if (pcbBoard.num_layers !== void 0) {
22
- boardProps.push(`layers={${pcbBoard.num_layers}}`);
23
- }
24
- if (pcbBoard.material !== void 0) {
25
- boardProps.push(`material="${pcbBoard.material}"`);
26
- }
27
- if (pcbBoard.solder_mask_color !== void 0) {
28
- boardProps.push(`solderMaskColor="${pcbBoard.solder_mask_color}"`);
29
- }
30
- if (pcbBoard.silkscreen_color !== void 0) {
31
- boardProps.push(`silkscreenColor="${pcbBoard.silkscreen_color}"`);
32
- }
33
- if (pcbBoard.anchor_position !== void 0) {
34
- boardProps.push(
35
- `boardAnchorPosition={{ x: ${pcbBoard.anchor_position.x}, y: ${pcbBoard.anchor_position.y} }}`
36
- );
37
- }
38
- if (pcbBoard.anchor_alignment !== void 0) {
39
- boardProps.push(`boardAnchorAlignment="${pcbBoard.anchor_alignment}"`);
40
- }
41
- }
42
- const boardPropsStr = boardProps.join(" ");
43
- const children = "";
44
- return `
45
- export default () => (
46
- <board${boardPropsStr ? ` ${boardPropsStr}` : ""}>
47
- ${children}
48
- </board>
49
- )
50
- `.replace(/\n\s*\n/g, "\n").trim();
51
- };
2
+ import { mmStr as mmStr7 } from "@tscircuit/mm";
3
+ import { su as su12 } from "@tscircuit/soup-util";
52
4
 
53
5
  // lib/generate-footprint-tsx/convert-copper-text.ts
54
- import { su as su2 } from "@tscircuit/soup-util";
6
+ import { su } from "@tscircuit/soup-util";
55
7
 
56
- // lib/generate-footprint-tsx/helpers.ts
57
- import { mmStr as mmStr2 } from "@tscircuit/mm";
8
+ // lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/escape-jsx-text.ts
58
9
  var escapeJsxText = (value) => String(value ?? "").replace(/"/g, '\\"');
59
- var formatMm = (value) => mmStr2(value ?? 0);
60
- var formatOptionalMmAttr = (attrName, value) => {
61
- if (value === void 0) return "";
62
- return ` ${attrName}="${mmStr2(value)}"`;
63
- };
64
- var formatSolderMaskAttrs = (platedHole) => `${platedHole.is_covered_with_solder_mask === void 0 ? "" : ` coveredWithSolderMask={${platedHole.is_covered_with_solder_mask}}`}${formatOptionalMmAttr("solderMaskMargin", platedHole.soldermask_margin)}`;
65
- var formatPcbRotationAttr = (rotation, attrName = "pcbRotation") => {
66
- if (rotation === void 0) return "";
67
- const formatted = typeof rotation === "number" ? `${rotation}deg` : rotation;
68
- return ` ${attrName}="${formatted}"`;
69
- };
70
10
 
71
11
  // lib/generate-footprint-tsx/convert-copper-text.ts
72
12
  var convertCopperText = (circuitJson) => {
73
- const copperTexts = su2(circuitJson).pcb_copper_text.list();
13
+ const copperTexts = su(circuitJson).pcb_copper_text.list();
74
14
  const elementStrings = [];
75
15
  for (const copperText of copperTexts) {
76
16
  const anchorPosition = copperText.anchor_position ?? { x: 0, y: 0 };
@@ -104,11 +44,20 @@ var convertCopperText = (circuitJson) => {
104
44
  };
105
45
 
106
46
  // lib/generate-footprint-tsx/convert-courtyard.ts
107
- import { su as su3 } from "@tscircuit/soup-util";
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
108
57
  var convertCourtyard = (circuitJson) => {
109
- const courtyardOutlines = su3(circuitJson).pcb_courtyard_outline.list();
110
- const courtyardRects = su3(circuitJson).pcb_courtyard_rect.list();
111
- const courtyardCircles = su3(circuitJson).pcb_courtyard_circle.list();
58
+ const courtyardOutlines = su2(circuitJson).pcb_courtyard_outline.list();
59
+ const courtyardRects = su2(circuitJson).pcb_courtyard_rect.list();
60
+ const courtyardCircles = su2(circuitJson).pcb_courtyard_circle.list();
112
61
  const elementStrings = [];
113
62
  for (const courtyardOutline of courtyardOutlines) {
114
63
  const attrs = [
@@ -129,6 +78,9 @@ var convertCourtyard = (circuitJson) => {
129
78
  if (courtyardRect.layer !== void 0) {
130
79
  attrs.push(`layer="${courtyardRect.layer}"`);
131
80
  }
81
+ if (courtyardRect.ccw_rotation !== void 0) {
82
+ attrs.push(formatPcbRotationAttr(courtyardRect.ccw_rotation).trimStart());
83
+ }
132
84
  elementStrings.push(`<courtyardrect ${attrs.join(" ")} />`);
133
85
  }
134
86
  for (const courtyardCircle of courtyardCircles) {
@@ -146,9 +98,15 @@ var convertCourtyard = (circuitJson) => {
146
98
  };
147
99
 
148
100
  // lib/generate-footprint-tsx/convert-cutouts.ts
149
- import { su as su4 } from "@tscircuit/soup-util";
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
150
108
  var convertCutouts = (circuitJson) => {
151
- const pcbCutouts = su4(circuitJson).pcb_cutout.list();
109
+ const pcbCutouts = su3(circuitJson).pcb_cutout.list();
152
110
  const elementStrings = [];
153
111
  for (const cutout of pcbCutouts) {
154
112
  if (cutout.shape === "rect") {
@@ -172,12 +130,12 @@ var convertCutouts = (circuitJson) => {
172
130
  };
173
131
 
174
132
  // lib/generate-footprint-tsx/convert-fabrication.ts
175
- import { su as su5 } from "@tscircuit/soup-util";
133
+ import { su as su4 } from "@tscircuit/soup-util";
176
134
  var convertFabrication = (circuitJson) => {
177
- const fabricationNotePaths = su5(circuitJson).pcb_fabrication_note_path.list();
178
- const fabricationNoteTexts = su5(circuitJson).pcb_fabrication_note_text.list();
179
- const fabricationNoteRects = su5(circuitJson).pcb_fabrication_note_rect.list();
180
- const fabricationNoteDimensions = su5(circuitJson).pcb_fabrication_note_dimension.list();
135
+ const fabricationNotePaths = su4(circuitJson).pcb_fabrication_note_path.list();
136
+ const fabricationNoteTexts = su4(circuitJson).pcb_fabrication_note_text.list();
137
+ const fabricationNoteRects = su4(circuitJson).pcb_fabrication_note_rect.list();
138
+ const fabricationNoteDimensions = su4(circuitJson).pcb_fabrication_note_dimension.list();
181
139
  const elementStrings = [];
182
140
  for (const fabPath of fabricationNotePaths) {
183
141
  const attrs = [`route={${JSON.stringify(fabPath.route)}}`];
@@ -281,27 +239,27 @@ var convertFabrication = (circuitJson) => {
281
239
  };
282
240
 
283
241
  // lib/generate-footprint-tsx/convert-holes.ts
284
- import { su as su6 } from "@tscircuit/soup-util";
285
- import { mmStr as mmStr3 } from "@tscircuit/mm";
242
+ import { su as su5 } from "@tscircuit/soup-util";
243
+ import { mmStr as mmStr2 } from "@tscircuit/mm";
286
244
  var convertHoles = (circuitJson) => {
287
- const holes = su6(circuitJson).pcb_hole.list();
245
+ const holes = su5(circuitJson).pcb_hole.list();
288
246
  const elementStrings = [];
289
247
  for (const hole of holes) {
290
248
  if (hole.hole_shape === "circle") {
291
249
  elementStrings.push(
292
- `<hole pcbX="${mmStr3(hole.x)}" pcbY="${mmStr3(hole.y)}" diameter="${mmStr3(hole.hole_diameter)}" />`
250
+ `<hole pcbX="${mmStr2(hole.x)}" pcbY="${mmStr2(hole.y)}" diameter="${mmStr2(hole.hole_diameter)}" />`
293
251
  );
294
252
  } else if (hole.hole_shape === "rect") {
295
253
  elementStrings.push(
296
- `<hole pcbX="${mmStr3(hole.x)}" pcbY="${mmStr3(hole.y)}" width="${mmStr3(hole.hole_width)}" height="${mmStr3(hole.hole_height)}" shape="rect" />`
254
+ `<hole pcbX="${mmStr2(hole.x)}" pcbY="${mmStr2(hole.y)}" width="${mmStr2(hole.hole_width)}" height="${mmStr2(hole.hole_height)}" shape="rect" />`
297
255
  );
298
256
  } else if (hole.hole_shape === "oval") {
299
257
  elementStrings.push(
300
- `<hole pcbX="${mmStr3(hole.x)}" pcbY="${mmStr3(hole.y)}" width="${mmStr3(hole.hole_width)}" height="${mmStr3(hole.hole_height)}" shape="oval" />`
258
+ `<hole pcbX="${mmStr2(hole.x)}" pcbY="${mmStr2(hole.y)}" width="${mmStr2(hole.hole_width)}" height="${mmStr2(hole.hole_height)}" shape="oval" />`
301
259
  );
302
260
  } else if (hole.hole_shape === "pill" || hole.hole_shape === "rotated_pill") {
303
261
  elementStrings.push(
304
- `<hole pcbX="${mmStr3(hole.x)}" pcbY="${mmStr3(hole.y)}" width="${mmStr3(hole.hole_width)}" height="${mmStr3(hole.hole_height)}" shape="pill"${formatPcbRotationAttr("ccw_rotation" in hole ? hole.ccw_rotation : void 0)} />`
262
+ `<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)} />`
305
263
  );
306
264
  }
307
265
  }
@@ -309,9 +267,9 @@ var convertHoles = (circuitJson) => {
309
267
  };
310
268
 
311
269
  // lib/generate-footprint-tsx/convert-keepouts.ts
312
- import { su as su7 } from "@tscircuit/soup-util";
270
+ import { su as su6 } from "@tscircuit/soup-util";
313
271
  var convertKeepouts = (circuitJson) => {
314
- const pcbKeepouts = su7(circuitJson).pcb_keepout.list();
272
+ const pcbKeepouts = su6(circuitJson).pcb_keepout.list();
315
273
  const elementStrings = [];
316
274
  for (const keepout of pcbKeepouts) {
317
275
  if (keepout.shape === "rect") {
@@ -330,13 +288,13 @@ var convertKeepouts = (circuitJson) => {
330
288
  };
331
289
 
332
290
  // lib/generate-footprint-tsx/convert-notes.ts
333
- import { su as su8 } from "@tscircuit/soup-util";
291
+ import { su as su7 } from "@tscircuit/soup-util";
334
292
  var convertNotes = (circuitJson) => {
335
- const noteTexts = su8(circuitJson).pcb_note_text.list();
336
- const noteRects = su8(circuitJson).pcb_note_rect.list();
337
- const notePaths = su8(circuitJson).pcb_note_path.list();
338
- const noteLines = su8(circuitJson).pcb_note_line.list();
339
- const noteDimensions = su8(circuitJson).pcb_note_dimension.list();
293
+ const noteTexts = su7(circuitJson).pcb_note_text.list();
294
+ const noteRects = su7(circuitJson).pcb_note_rect.list();
295
+ const notePaths = su7(circuitJson).pcb_note_path.list();
296
+ const noteLines = su7(circuitJson).pcb_note_line.list();
297
+ const noteDimensions = su7(circuitJson).pcb_note_dimension.list();
340
298
  const elementStrings = [];
341
299
  for (const noteText of noteTexts) {
342
300
  const anchorPosition = noteText.anchor_position ?? { x: 0, y: 0 };
@@ -426,10 +384,28 @@ var convertNotes = (circuitJson) => {
426
384
  };
427
385
 
428
386
  // lib/generate-footprint-tsx/convert-plated-holes.ts
429
- import { su as su9 } from "@tscircuit/soup-util";
387
+ import { su as su8 } from "@tscircuit/soup-util";
430
388
  import { mmStr as mmStr4 } from "@tscircuit/mm";
389
+
390
+ // lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/format-optional-mm-attr.ts
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
431
407
  var convertPlatedHoles = (circuitJson) => {
432
- const platedHoles = su9(circuitJson).pcb_plated_hole.list();
408
+ const platedHoles = su8(circuitJson).pcb_plated_hole.list();
433
409
  const elementStrings = [];
434
410
  for (const platedHole of platedHoles) {
435
411
  if (platedHole.shape === "oval" || platedHole.shape === "pill") {
@@ -461,12 +437,12 @@ var convertPlatedHoles = (circuitJson) => {
461
437
  };
462
438
 
463
439
  // lib/generate-footprint-tsx/convert-silkscreen.ts
464
- import { su as su10 } from "@tscircuit/soup-util";
440
+ import { su as su9 } from "@tscircuit/soup-util";
465
441
  var convertSilkscreen = (circuitJson) => {
466
- const silkscreenLines = su10(circuitJson).pcb_silkscreen_line.list();
467
- const silkscreenPaths = su10(circuitJson).pcb_silkscreen_path.list();
468
- const silkscreenRects = su10(circuitJson).pcb_silkscreen_rect.list();
469
- const silkscreenCircles = su10(circuitJson).pcb_silkscreen_circle.list();
442
+ const silkscreenLines = su9(circuitJson).pcb_silkscreen_line.list();
443
+ const silkscreenPaths = su9(circuitJson).pcb_silkscreen_path.list();
444
+ const silkscreenRects = su9(circuitJson).pcb_silkscreen_rect.list();
445
+ const silkscreenCircles = su9(circuitJson).pcb_silkscreen_circle.list();
470
446
  const elementStrings = [];
471
447
  for (const silkscreenPath of silkscreenPaths) {
472
448
  elementStrings.push(
@@ -528,10 +504,10 @@ var convertSilkscreen = (circuitJson) => {
528
504
  };
529
505
 
530
506
  // lib/generate-footprint-tsx/convert-silkscreen-text.ts
531
- import { su as su11 } from "@tscircuit/soup-util";
507
+ import { su as su10 } from "@tscircuit/soup-util";
532
508
  import { mmStr as mmStr5 } from "@tscircuit/mm";
533
509
  var convertSilkscreenText = (circuitJson) => {
534
- const silkscreenTexts = su11(circuitJson).pcb_silkscreen_text.list();
510
+ const silkscreenTexts = su10(circuitJson).pcb_silkscreen_text.list();
535
511
  const elementStrings = [];
536
512
  for (const silkscreenText of silkscreenTexts) {
537
513
  const pcbX = silkscreenText.anchor_position?.x ?? 0;
@@ -546,10 +522,10 @@ var convertSilkscreenText = (circuitJson) => {
546
522
  };
547
523
 
548
524
  // lib/generate-footprint-tsx/convert-smt-pads.ts
549
- import { su as su12 } from "@tscircuit/soup-util";
525
+ import { su as su11 } from "@tscircuit/soup-util";
550
526
  import { mmStr as mmStr6 } from "@tscircuit/mm";
551
527
  var convertSmtPads = (circuitJson) => {
552
- const smtPads = su12(circuitJson).pcb_smtpad.list();
528
+ const smtPads = su11(circuitJson).pcb_smtpad.list();
553
529
  const elementStrings = [];
554
530
  for (const smtPad of smtPads) {
555
531
  const commonAttrs = [];
@@ -676,6 +652,57 @@ var generateFootprintTsx = (circuitJson) => {
676
652
  `.trim();
677
653
  };
678
654
 
655
+ // lib/get-board-using-template.ts
656
+ var getBoardUsingTemplate = ({ circuitJson }) => {
657
+ const pcbBoard = su12(circuitJson).pcb_board.list()[0];
658
+ const boardProps = [];
659
+ if (pcbBoard) {
660
+ if (pcbBoard.width !== void 0) {
661
+ boardProps.push(`width="${mmStr7(pcbBoard.width)}"`);
662
+ }
663
+ if (pcbBoard.height !== void 0) {
664
+ boardProps.push(`height="${mmStr7(pcbBoard.height)}"`);
665
+ }
666
+ if (pcbBoard.outline && pcbBoard.outline.length > 0) {
667
+ const points = pcbBoard.outline.map((p) => `{ x: ${p.x}, y: ${p.y} }`).join(", ");
668
+ boardProps.push(`outline={[${points}]}`);
669
+ }
670
+ if (pcbBoard.thickness !== void 0) {
671
+ boardProps.push(`thickness="${mmStr7(pcbBoard.thickness)}"`);
672
+ }
673
+ if (pcbBoard.num_layers !== void 0) {
674
+ boardProps.push(`layers={${pcbBoard.num_layers}}`);
675
+ }
676
+ if (pcbBoard.material !== void 0) {
677
+ boardProps.push(`material="${pcbBoard.material}"`);
678
+ }
679
+ if (pcbBoard.solder_mask_color !== void 0) {
680
+ boardProps.push(`solderMaskColor="${pcbBoard.solder_mask_color}"`);
681
+ }
682
+ if (pcbBoard.silkscreen_color !== void 0) {
683
+ boardProps.push(`silkscreenColor="${pcbBoard.silkscreen_color}"`);
684
+ }
685
+ if (pcbBoard.anchor_position !== void 0) {
686
+ boardProps.push(
687
+ `boardAnchorPosition={{ x: ${pcbBoard.anchor_position.x}, y: ${pcbBoard.anchor_position.y} }}`
688
+ );
689
+ }
690
+ if (pcbBoard.anchor_alignment !== void 0) {
691
+ boardProps.push(`boardAnchorAlignment="${pcbBoard.anchor_alignment}"`);
692
+ }
693
+ }
694
+ const boardPropsStr = boardProps.join(" ");
695
+ const footprintTsx = generateFootprintTsx(circuitJson);
696
+ const children = footprintTsx ? `<chip footprint={${footprintTsx}} />` : "";
697
+ return `
698
+ export default () => (
699
+ <board${boardPropsStr ? ` ${boardPropsStr}` : ""}>
700
+ ${children}
701
+ </board>
702
+ )
703
+ `.replace(/\n\s*\n/g, "\n").trim();
704
+ };
705
+
679
706
  // lib/generate-symbol-tsx.ts
680
707
  import { su as su13 } from "@tscircuit/soup-util";
681
708
  var escapeJsxText2 = (text) => text.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
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-G5NSFWRY.js";
4
+ } from "../chunk-BA4FQZIF.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.38",
19
+ version: "0.0.40",
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 {
2
2
  convertCircuitJsonToTscircuit
3
- } from "../chunk-G5NSFWRY.js";
3
+ } from "../chunk-BA4FQZIF.js";
4
4
  export {
5
5
  convertCircuitJsonToTscircuit
6
6
  };
@@ -1,6 +1,6 @@
1
1
  import { su } from "@tscircuit/soup-util"
2
2
  import type { FootprintElementConverter } from "./converter-types"
3
- import { escapeJsxText } from "./helpers"
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 "./helpers"
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 "./helpers"
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 "./helpers"
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 "./helpers"
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 "./helpers"
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
- formatOptionalMmAttr,
6
- formatPcbRotationAttr,
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 "./helpers"
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,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 "./helpers"
4
+ import { formatPcbRotationAttr } from "./footprint-tsx-attribute-formatters/format-pcb-rotation-attr"
5
5
 
6
6
  export const convertSmtPads: FootprintElementConverter = (circuitJson) => {
7
7
  const smtPads = su(circuitJson).pcb_smtpad.list()
@@ -0,0 +1,2 @@
1
+ export const escapeJsxText = (value: unknown): string =>
2
+ String(value ?? "").replace(/"/g, '\\"')
@@ -0,0 +1,3 @@
1
+ import { mmStr } from "@tscircuit/mm"
2
+
3
+ export const formatMm = (value: number | undefined): string => mmStr(value ?? 0)
@@ -0,0 +1,9 @@
1
+ import { mmStr } from "@tscircuit/mm"
2
+
3
+ export const formatOptionalMmAttr = (
4
+ attrName: string,
5
+ value: number | undefined,
6
+ ): string => {
7
+ if (value === undefined) return ""
8
+ return ` ${attrName}="${mmStr(value)}"`
9
+ }
@@ -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
+ }
@@ -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
+ }
@@ -1,6 +1,7 @@
1
1
  import { mmStr } from "@tscircuit/mm"
2
2
  import { su } from "@tscircuit/soup-util"
3
3
  import type { AnyCircuitElement } from "circuit-json"
4
+ import { generateFootprintTsx } from "./generate-footprint-tsx"
4
5
 
5
6
  export interface BoardTemplateParams {
6
7
  circuitJson: AnyCircuitElement[]
@@ -50,9 +51,9 @@ export const getBoardUsingTemplate = ({ circuitJson }: BoardTemplateParams) => {
50
51
  }
51
52
 
52
53
  const boardPropsStr = boardProps.join(" ")
54
+ const footprintTsx = generateFootprintTsx(circuitJson)
53
55
 
54
- // Children slot - components and connections are added in later stages
55
- const children = ""
56
+ const children = footprintTsx ? `<chip footprint={${footprintTsx}} />` : ""
56
57
 
57
58
  return `
58
59
  export default () => (
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.39",
9
+ "version": "0.0.41",
10
10
  "scripts": {
11
11
  "build": "tsup-node lib/index.ts cli/main.ts --format esm --dts",
12
12
  "test": "bun test",
@@ -1 +1 @@
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="57.14285714285717" y="71.42857142857147" width="685.7142857142858" height="457.1428571428572" data-type="pcb_boundary" data-pcb-layer="global"/><path class="pcb-board" d="M 57.14285714285717 528.5714285714287 L 742.8571428571429 528.5714285714287 L 742.8571428571429 71.42857142857147 L 57.14285714285717 71.42857142857147 Z" fill="none" stroke="rgba(255, 255, 255, 0.5)" stroke-width="5.714285714285715" data-type="pcb_board" data-pcb-layer="board"/></svg>
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="57.14285714285717" y="71.42857142857147" width="685.7142857142858" height="457.1428571428572" data-type="pcb_boundary" data-pcb-layer="global"/><path class="pcb-board" d="M 57.14285714285717 528.5714285714287 L 742.8571428571429 528.5714285714287 L 742.8571428571429 71.42857142857147 L 57.14285714285717 71.42857142857147 Z" fill="none" stroke="rgba(255, 255, 255, 0.5)" stroke-width="5.714285714285715" data-type="pcb_board" data-pcb-layer="board"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="314.28571428571433" y="277.1428571428572" width="57.142857142857146" height="45.71428571428572" data-type="pcb_smtpad" data-pcb-layer="top"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="428.57142857142867" y="277.1428571428572" width="57.142857142857146" height="45.71428571428572" data-type="pcb_smtpad" data-pcb-layer="top"/></svg>
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="800" height="600" data-software-used-string="@tscircuit/core@0.0.1090"><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(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"/><path class="pcb-fabrication-note-path" stroke="rgba(255,255,255,0.5)" fill="none" d="M 350.9090909090909 338.1818181818182 L 449.0909090909091 338.1818181818182 L 449.0909090909091 261.8181818181818 L 350.9090909090909 261.8181818181818" stroke-width="2.7272727272727275" data-pcb-component-id="pcb_component_0" data-pcb-fabrication-note-path-id="projected_fnp_pcb_courtyard_outline_0" data-type="pcb_fabrication_note_path" data-pcb-layer="overlay"/><rect x="345.45454545454544" y="259.0909090909091" width="109.09090909090912" height="81.81818181818176" class="pcb-fabrication-note-rect" data-type="pcb_fabrication_note_rect" data-pcb-fabrication-note-rect-id="projected_fnr_pcb_courtyard_rect_0" data-pcb-layer="overlay" data-pcb-component-id="pcb_component_0" fill="none" stroke="rgba(255,255,255,0.5)" stroke-width="2.7272727272727275"/><path class="pcb-fabrication-note-path" stroke="rgba(255,255,255,0.5)" fill="none" d="M 350.9090909090909 338.1818181818182 L 449.0909090909091 338.1818181818182 L 449.0909090909091 261.8181818181818 L 350.9090909090909 261.8181818181818" stroke-width="2.7272727272727275" data-pcb-component-id="pcb_component_1" data-pcb-fabrication-note-path-id="projected_fnp_pcb_courtyard_outline_1" data-type="pcb_fabrication_note_path" data-pcb-layer="overlay"/><rect x="345.45454545454544" y="259.0909090909091" width="109.09090909090912" height="81.81818181818176" class="pcb-fabrication-note-rect" data-type="pcb_fabrication_note_rect" data-pcb-fabrication-note-rect-id="projected_fnr_pcb_courtyard_rect_1" data-pcb-layer="overlay" data-pcb-component-id="pcb_component_1" fill="none" stroke="rgba(255,255,255,0.5)" stroke-width="2.7272727272727275"/></svg>
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>
@@ -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":-1.8,"y":-1.4},{"x":1.8,"y":-1.4},{"x":1.8,"y":1.4},{"x":-1.8,"y":1.4}]} layer="top" />
17
- <courtyardrect pcbX={0} pcbY={0} width={4} height={3} layer="top" />
18
- <courtyardrect pcbX={0.2} pcbY={0.2} width={4.6} height={3.6} layer="bottom" />
19
- <courtyardcircle pcbX={0.4} pcbY={-0.3} radius={2.1} layer="top" />
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: -1.8, y: -1.4 },
114
- { x: 1.8, y: -1.4 },
115
- { x: 1.8, y: 1.4 },
116
- { x: -1.8, y: 1.4 },
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: 0.2, y: 0.2 },
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: -0.3 },
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
- }