@tscircuit/core 0.0.16 → 0.0.18

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/index.js CHANGED
@@ -12,13 +12,16 @@ __export(components_exports, {
12
12
  Chip: () => Chip,
13
13
  Footprint: () => Footprint,
14
14
  Group: () => Group,
15
+ Jumper: () => Jumper,
15
16
  Led: () => Led,
16
17
  Net: () => Net,
17
18
  NormalComponent: () => NormalComponent,
19
+ PlatedHole: () => PlatedHole,
18
20
  Port: () => Port,
19
21
  PrimitiveComponent: () => PrimitiveComponent,
20
22
  Renderable: () => Renderable,
21
23
  Resistor: () => Resistor,
24
+ SilkscreenPath: () => SilkscreenPath,
22
25
  SmtPad: () => SmtPad,
23
26
  Trace: () => Trace,
24
27
  TraceHint: () => TraceHint
@@ -167,6 +170,7 @@ var PrimitiveComponent = class extends Renderable {
167
170
  _parsedProps;
168
171
  componentName = "";
169
172
  lowercaseComponentName = "";
173
+ externallyAddedAliases;
170
174
  source_group_id = null;
171
175
  source_component_id = null;
172
176
  schematic_component_id = null;
@@ -177,6 +181,7 @@ var PrimitiveComponent = class extends Renderable {
177
181
  this.children = [];
178
182
  this.childrenPendingRemoval = [];
179
183
  this.props = props ?? {};
184
+ this.externallyAddedAliases = [];
180
185
  this._parsedProps = this.config.zodProps.parse(
181
186
  props ?? {}
182
187
  );
@@ -466,7 +471,8 @@ var Port = class extends PrimitiveComponent {
466
471
  /* @__PURE__ */ new Set([
467
472
  ...props.aliases ?? [],
468
473
  props.name,
469
- ...typeof props.pinNumber === "number" ? [`pin${props.pinNumber}`, props.pinNumber.toString()] : []
474
+ ...typeof props.pinNumber === "number" ? [`pin${props.pinNumber}`, props.pinNumber.toString()] : [],
475
+ ...this.externallyAddedAliases
470
476
  ])
471
477
  );
472
478
  }
@@ -796,6 +802,83 @@ var SmtPad = class extends PrimitiveComponent {
796
802
  }
797
803
  };
798
804
 
805
+ // lib/components/primitive-components/SilkscreenPath.ts
806
+ import { silkscreenPathProps } from "@tscircuit/props";
807
+ var SilkscreenPath = class extends PrimitiveComponent {
808
+ pcb_silkscreen_path_id = null;
809
+ get config() {
810
+ return {
811
+ zodProps: silkscreenPathProps
812
+ };
813
+ }
814
+ doInitialPcbPrimitiveRender() {
815
+ const { db } = this.project;
816
+ const { _parsedProps: props } = this;
817
+ const layer = props.layer ?? "top";
818
+ if (layer !== "top" && layer !== "bottom") {
819
+ throw new Error(
820
+ `Invalid layer "${layer}" for SilkscreenPath. Must be "top" or "bottom".`
821
+ );
822
+ }
823
+ const pcb_silkscreen_path = db.pcb_silkscreen_path.insert({
824
+ pcb_component_id: this.parent?.pcb_component_id,
825
+ layer,
826
+ route: props.route,
827
+ stroke_width: props.strokeWidth ?? 0.1
828
+ });
829
+ this.pcb_silkscreen_path_id = pcb_silkscreen_path.pcb_silkscreen_path_id;
830
+ }
831
+ };
832
+
833
+ // lib/components/primitive-components/PlatedHole.ts
834
+ import { platedHoleProps } from "@tscircuit/props";
835
+ var PlatedHole = class extends PrimitiveComponent {
836
+ pcb_plated_hole_id = null;
837
+ matchedPort = null;
838
+ isPcbPrimitive = true;
839
+ get config() {
840
+ return {
841
+ zodProps: platedHoleProps
842
+ };
843
+ }
844
+ doInitialPortMatching() {
845
+ const parentPorts = (this.parent?.children ?? []).filter(
846
+ (c) => c.componentName === "Port"
847
+ );
848
+ if (!this.props.portHints) {
849
+ return;
850
+ }
851
+ for (const port of parentPorts) {
852
+ if (port.isMatchingAnyOf(this.props.portHints)) {
853
+ this.matchedPort = port;
854
+ port.registerMatch(this);
855
+ return;
856
+ }
857
+ }
858
+ }
859
+ doInitialPcbPrimitiveRender() {
860
+ const { db } = this.project;
861
+ const { _parsedProps: props } = this;
862
+ if (!props.portHints) return;
863
+ const position = this.getGlobalPcbPosition();
864
+ if (props.shape === "circle") {
865
+ const plated_hole_input = {
866
+ pcb_component_id: this.parent?.pcb_component_id,
867
+ pcb_port_id: this.matchedPort?.pcb_port_id,
868
+ layers: ["top", "bottom"],
869
+ outer_diameter: props.outerDiameter,
870
+ hole_diameter: props.holeDiameter,
871
+ shape: "circle",
872
+ port_hints: this.getNameAndAliases(),
873
+ x: position.x,
874
+ y: position.y,
875
+ type: "pcb_plated_hole"
876
+ };
877
+ const pcb_plated_hole = db.pcb_plated_hole.insert(plated_hole_input);
878
+ }
879
+ }
880
+ };
881
+
799
882
  // lib/utils/createComponentsFromSoup.ts
800
883
  var createComponentsFromSoup = (soup) => {
801
884
  const components = [];
@@ -823,6 +906,27 @@ var createComponentsFromSoup = (soup) => {
823
906
  portHints: elm.port_hints
824
907
  })
825
908
  );
909
+ } else if (elm.type === "pcb_silkscreen_path") {
910
+ components.push(
911
+ new SilkscreenPath({
912
+ layer: elm.layer,
913
+ route: elm.route,
914
+ strokeWidth: elm.stroke_width
915
+ })
916
+ );
917
+ } else if (elm.type === "pcb_plated_hole" && elm.shape === "circle") {
918
+ if (elm.shape === "circle") {
919
+ components.push(
920
+ new PlatedHole({
921
+ pcbX: elm.x,
922
+ pcbY: elm.y,
923
+ shape: "circle",
924
+ holeDiameter: elm.hole_diameter,
925
+ outerDiameter: elm.outer_diameter,
926
+ portHints: elm.port_hints
927
+ })
928
+ );
929
+ }
826
930
  }
827
931
  }
828
932
  return components;
@@ -866,6 +970,20 @@ var NormalComponent = class extends PrimitiveComponent {
866
970
  }
867
971
  const portsFromFootprint = this.getPortsFromFootprint();
868
972
  this.addAll(portsFromFootprint);
973
+ const pinLabels = this._parsedProps.pinLabels;
974
+ if (pinLabels) {
975
+ for (let [pinNumber, label] of Object.entries(pinLabels)) {
976
+ pinNumber = pinNumber.replace("pin", "");
977
+ const port = this.selectOne(`port[pinNumber='${pinNumber}']`);
978
+ if (!port) {
979
+ throw new Error(
980
+ `Could not find port for pin number ${pinNumber} in chip ${this.getString()}`
981
+ );
982
+ }
983
+ port.externallyAddedAliases.push(label);
984
+ port.props.name = label;
985
+ }
986
+ }
869
987
  }
870
988
  _addChildrenFromStringFootprint() {
871
989
  const { footprint } = this.props;
@@ -1902,27 +2020,81 @@ var Chip = class extends NormalComponent {
1902
2020
  zodProps: chipProps
1903
2021
  };
1904
2022
  }
1905
- initPorts() {
1906
- super.initPorts();
2023
+ doInitialSourceRender() {
2024
+ const { db } = this.project;
1907
2025
  const { _parsedProps: props } = this;
1908
- if (props.pinLabels) {
1909
- for (const [pinNumber, label] of Object.entries(props.pinLabels)) {
1910
- const port = this.selectOne(`port[pinNumber='${pinNumber}']`);
1911
- if (!port) {
1912
- throw new Error(
1913
- `Could not find port for pin number ${pinNumber} in chip ${this.getString()}`
1914
- );
1915
- }
1916
- port.props.aliases.push(port.props.name);
1917
- port.props.name = label;
1918
- }
1919
- }
2026
+ const source_component = db.source_component.insert({
2027
+ ftype: "simple_chip",
2028
+ name: props.name,
2029
+ manufacturer_part_number: props.manufacturerPartNumber,
2030
+ supplier_part_numbers: props.supplierPartNumbers
2031
+ });
2032
+ this.source_component_id = source_component.source_component_id;
2033
+ }
2034
+ doInitialSchematicComponentRender() {
2035
+ const { db } = this.project;
2036
+ const { _parsedProps: props } = this;
2037
+ const ports = this.children.filter((child) => child instanceof Port);
2038
+ const pinSpacing = props.schPinSpacing ?? 0.2;
2039
+ const dimensions = getAllDimensionsForSchematicBox({
2040
+ schWidth: props.schWidth,
2041
+ schHeight: props.schHeight,
2042
+ schPinSpacing: pinSpacing,
2043
+ schPinStyle: props.schPinStyle,
2044
+ pinCount: ports.length,
2045
+ // @ts-ignore there's a subtley in the definition difference with
2046
+ // leftSide/rightSide/topSide/bottomSide in how the direction is defined
2047
+ // that doesn't really matter
2048
+ schPortArrangement: props.schPortArrangement
2049
+ });
2050
+ this.schematicDimensions = dimensions;
2051
+ const schematic_component2 = db.schematic_component.insert({
2052
+ center: { x: props.schX ?? 0, y: props.schY ?? 0 },
2053
+ rotation: props.schRotation ?? 0,
2054
+ size: dimensions.getSize(),
2055
+ port_arrangement: underscorifyPortArrangement(
2056
+ props.schPortArrangement
2057
+ ),
2058
+ pin_spacing: pinSpacing,
2059
+ // @ts-ignore soup needs to support distance for pin_styles
2060
+ pin_styles: underscorifyPinStyles(props.schPinStyle),
2061
+ port_labels: props.pinLabels,
2062
+ source_component_id: this.source_component_id
2063
+ });
2064
+ this.schematic_component_id = schematic_component2.schematic_component_id;
2065
+ }
2066
+ doInitialPcbComponentRender() {
2067
+ const { db } = this.project;
2068
+ const { _parsedProps: props } = this;
2069
+ const pcb_component = db.pcb_component.insert({
2070
+ center: { x: props.pcbX ?? 0, y: props.pcbY ?? 0 },
2071
+ width: 2,
2072
+ // Default width, adjust as needed
2073
+ height: 3,
2074
+ // Default height, adjust as needed
2075
+ layer: props.layer ?? "top",
2076
+ rotation: props.pcbRotation ?? 0,
2077
+ source_component_id: this.source_component_id
2078
+ });
2079
+ this.pcb_component_id = pcb_component.pcb_component_id;
2080
+ }
2081
+ };
2082
+
2083
+ // lib/components/normal-components/Jumper.ts
2084
+ import { jumperProps } from "@tscircuit/props";
2085
+ var Jumper = class extends NormalComponent {
2086
+ schematicDimensions = null;
2087
+ get config() {
2088
+ return {
2089
+ zodProps: jumperProps
2090
+ };
1920
2091
  }
1921
2092
  doInitialSourceRender() {
1922
2093
  const { db } = this.project;
1923
2094
  const { _parsedProps: props } = this;
1924
2095
  const source_component = db.source_component.insert({
1925
2096
  ftype: "simple_chip",
2097
+ // TODO unknown or jumper
1926
2098
  name: props.name,
1927
2099
  manufacturer_part_number: props.manufacturerPartNumber,
1928
2100
  supplier_part_numbers: props.supplierPartNumbers
@@ -1943,7 +2115,10 @@ var Chip = class extends NormalComponent {
1943
2115
  // @ts-ignore there's a subtley in the definition difference with
1944
2116
  // leftSide/rightSide/topSide/bottomSide in how the direction is defined
1945
2117
  // that doesn't really matter
1946
- schPortArrangement: props.schPortArrangement
2118
+ schPortArrangement: {
2119
+ // TODO use schematic direction or schPortArrangement
2120
+ rightSize: ports.length
2121
+ }
1947
2122
  });
1948
2123
  this.schematicDimensions = dimensions;
1949
2124
  const schematic_component2 = db.schematic_component.insert({
@@ -1986,6 +2161,7 @@ var Project = class {
1986
2161
  rootComponent = null;
1987
2162
  children;
1988
2163
  db;
2164
+ _hasRenderedAtleastOnce = false;
1989
2165
  constructor() {
1990
2166
  this.children = [];
1991
2167
  this.db = su([]);
@@ -2029,13 +2205,29 @@ var Project = class {
2029
2205
  if (!rootComponent) throw new Error("Project has no root component");
2030
2206
  rootComponent.setProject(this);
2031
2207
  rootComponent.runRenderCycle();
2208
+ this._hasRenderedAtleastOnce = true;
2032
2209
  }
2033
2210
  getSoup() {
2211
+ if (!this._hasRenderedAtleastOnce) this.render();
2034
2212
  return this.db.toArray();
2035
2213
  }
2036
2214
  getCircuitJson() {
2037
2215
  return this.getSoup();
2038
2216
  }
2217
+ async getSvg(options) {
2218
+ const circuitToSvg = await import("circuit-to-svg").catch((e) => {
2219
+ throw new Error(
2220
+ `To use project.getSvg, you must install the "circuit-to-svg" package.
2221
+
2222
+ "${e.message}"`
2223
+ );
2224
+ });
2225
+ return circuitToSvg.circuitJsonToPcbSvg(this.getSoup());
2226
+ }
2227
+ async preview(previewNameOrOpts) {
2228
+ const previewOpts = typeof previewNameOrOpts === "object" ? previewNameOrOpts : { previewName: previewNameOrOpts };
2229
+ throw new Error("project.preview is not yet implemented");
2230
+ }
2039
2231
  computeGlobalSchematicTransform() {
2040
2232
  return identity5();
2041
2233
  }
@@ -2061,14 +2253,17 @@ export {
2061
2253
  Chip,
2062
2254
  Footprint,
2063
2255
  Group,
2256
+ Jumper,
2064
2257
  Led,
2065
2258
  Net,
2066
2259
  NormalComponent,
2260
+ PlatedHole,
2067
2261
  Port,
2068
2262
  PrimitiveComponent,
2069
2263
  Project,
2070
2264
  Renderable,
2071
2265
  Resistor,
2266
+ SilkscreenPath,
2072
2267
  SmtPad,
2073
2268
  Trace,
2074
2269
  TraceHint
package/lib/Project.ts CHANGED
@@ -11,6 +11,8 @@ export class Project {
11
11
  children: PrimitiveComponent[]
12
12
  db: SoupUtilObjects
13
13
 
14
+ _hasRenderedAtleastOnce = false
15
+
14
16
  constructor() {
15
17
  this.children = []
16
18
  this.db = su([])
@@ -64,9 +66,11 @@ export class Project {
64
66
  rootComponent.setProject(this)
65
67
 
66
68
  rootComponent.runRenderCycle()
69
+ this._hasRenderedAtleastOnce = true
67
70
  }
68
71
 
69
72
  getSoup(): AnySoupElement[] {
73
+ if (!this._hasRenderedAtleastOnce) this.render()
70
74
  return this.db.toArray()
71
75
  }
72
76
 
@@ -74,6 +78,31 @@ export class Project {
74
78
  return this.getSoup()
75
79
  }
76
80
 
81
+ async getSvg(options: { view: "pcb"; layer?: string }): Promise<string> {
82
+ const circuitToSvg = await import("circuit-to-svg").catch((e) => {
83
+ throw new Error(
84
+ `To use project.getSvg, you must install the "circuit-to-svg" package.\n\n"${e.message}"`,
85
+ )
86
+ })
87
+
88
+ return circuitToSvg.circuitJsonToPcbSvg(this.getSoup())
89
+ }
90
+
91
+ async preview(
92
+ previewNameOrOpts:
93
+ | string
94
+ | {
95
+ previewName: string
96
+ tscircuitApiKey?: string
97
+ },
98
+ ) {
99
+ const previewOpts =
100
+ typeof previewNameOrOpts === "object"
101
+ ? previewNameOrOpts
102
+ : { previewName: previewNameOrOpts }
103
+ throw new Error("project.preview is not yet implemented")
104
+ }
105
+
77
106
  computeGlobalSchematicTransform(): Matrix {
78
107
  return identity()
79
108
  }
@@ -87,6 +87,22 @@ export class NormalComponent<
87
87
  const portsFromFootprint = this.getPortsFromFootprint()
88
88
 
89
89
  this.addAll(portsFromFootprint)
90
+
91
+ const pinLabels: Record<string, string> | undefined =
92
+ this._parsedProps.pinLabels
93
+ if (pinLabels) {
94
+ for (let [pinNumber, label] of Object.entries(pinLabels)) {
95
+ pinNumber = pinNumber.replace("pin", "")
96
+ const port = this.selectOne(`port[pinNumber='${pinNumber}']`)
97
+ if (!port) {
98
+ throw new Error(
99
+ `Could not find port for pin number ${pinNumber} in chip ${this.getString()}`,
100
+ )
101
+ }
102
+ port.externallyAddedAliases.push(label)
103
+ port.props.name = label
104
+ }
105
+ }
90
106
  }
91
107
 
92
108
  _addChildrenFromStringFootprint() {
@@ -46,6 +46,8 @@ export abstract class PrimitiveComponent<
46
46
  componentName = ""
47
47
  lowercaseComponentName = ""
48
48
 
49
+ externallyAddedAliases: string[]
50
+
49
51
  source_group_id: string | null = null
50
52
  source_component_id: string | null = null
51
53
  schematic_component_id: string | null = null
@@ -57,6 +59,7 @@ export abstract class PrimitiveComponent<
57
59
  this.children = []
58
60
  this.childrenPendingRemoval = []
59
61
  this.props = props ?? {}
62
+ this.externallyAddedAliases = []
60
63
  this._parsedProps = this.config.zodProps.parse(
61
64
  props ?? {},
62
65
  ) as z.infer<ZodProps>
@@ -13,3 +13,6 @@ export { Trace } from "./primitive-components/Trace"
13
13
  export { TraceHint } from "./primitive-components/TraceHint"
14
14
  export { Group } from "./primitive-components/Group"
15
15
  export { Chip } from "./normal-components/Chip"
16
+ export { Jumper } from "./normal-components/Jumper"
17
+ export { SilkscreenPath } from "./primitive-components/SilkscreenPath"
18
+ export { PlatedHole } from "./primitive-components/PlatedHole"
@@ -21,25 +21,6 @@ export class Chip<PinLabels extends string = never> extends NormalComponent<
21
21
  }
22
22
  }
23
23
 
24
- initPorts() {
25
- super.initPorts()
26
-
27
- const { _parsedProps: props } = this
28
-
29
- if (props.pinLabels) {
30
- for (const [pinNumber, label] of Object.entries(props.pinLabels)) {
31
- const port = this.selectOne(`port[pinNumber='${pinNumber}']`)
32
- if (!port) {
33
- throw new Error(
34
- `Could not find port for pin number ${pinNumber} in chip ${this.getString()}`,
35
- )
36
- }
37
- port.props.aliases.push(port.props.name)
38
- port.props.name = label
39
- }
40
- }
41
- }
42
-
43
24
  doInitialSourceRender(): void {
44
25
  const { db } = this.project!
45
26
  const { _parsedProps: props } = this
@@ -0,0 +1,101 @@
1
+ import { NormalComponent } from "lib/components/base-components/NormalComponent"
2
+ import { jumperProps } from "@tscircuit/props"
3
+ import { Port } from "../primitive-components/Port"
4
+ import type { BaseSymbolName } from "lib/utils/constants"
5
+ import {
6
+ getAllDimensionsForSchematicBox,
7
+ type SchematicBoxDimensions,
8
+ } from "lib/utils/schematic/getAllDimensionsForSchematicBox"
9
+ import { underscorifyPortArrangement } from "lib/soup/underscorifyPortArrangement"
10
+ import { underscorifyPinStyles } from "lib/soup/underscorifyPinStyles"
11
+
12
+ export class Jumper<PinLabels extends string = never> extends NormalComponent<
13
+ typeof jumperProps,
14
+ PinLabels
15
+ > {
16
+ schematicDimensions: SchematicBoxDimensions | null = null
17
+
18
+ get config() {
19
+ return {
20
+ zodProps: jumperProps,
21
+ }
22
+ }
23
+
24
+ doInitialSourceRender(): void {
25
+ const { db } = this.project!
26
+ const { _parsedProps: props } = this
27
+
28
+ const source_component = db.source_component.insert({
29
+ ftype: "simple_chip", // TODO unknown or jumper
30
+ name: props.name,
31
+ manufacturer_part_number: props.manufacturerPartNumber,
32
+ supplier_part_numbers: props.supplierPartNumbers,
33
+ })
34
+
35
+ this.source_component_id = source_component.source_component_id!
36
+ }
37
+
38
+ doInitialSchematicComponentRender() {
39
+ const { db } = this.project!
40
+ const { _parsedProps: props } = this
41
+
42
+ const ports = this.children.filter((child) => child instanceof Port)
43
+
44
+ const pinSpacing = props.schPinSpacing ?? 0.2
45
+
46
+ const dimensions = getAllDimensionsForSchematicBox({
47
+ schWidth: props.schWidth,
48
+ schHeight: props.schHeight,
49
+ schPinSpacing: pinSpacing,
50
+ schPinStyle: props.schPinStyle,
51
+
52
+ pinCount: ports.length,
53
+
54
+ // @ts-ignore there's a subtley in the definition difference with
55
+ // leftSide/rightSide/topSide/bottomSide in how the direction is defined
56
+ // that doesn't really matter
57
+ schPortArrangement: {
58
+ // TODO use schematic direction or schPortArrangement
59
+ rightSize: ports.length,
60
+ },
61
+ })
62
+ this.schematicDimensions = dimensions
63
+
64
+ const schematic_component = db.schematic_component.insert({
65
+ center: { x: props.schX ?? 0, y: props.schY ?? 0 },
66
+ rotation: props.schRotation ?? 0,
67
+ size: dimensions.getSize(),
68
+
69
+ port_arrangement: underscorifyPortArrangement(
70
+ props.schPortArrangement as any,
71
+ ),
72
+
73
+ pin_spacing: pinSpacing,
74
+
75
+ // @ts-ignore soup needs to support distance for pin_styles
76
+ pin_styles: underscorifyPinStyles(props.schPinStyle),
77
+
78
+ port_labels: props.pinLabels,
79
+
80
+ source_component_id: this.source_component_id!,
81
+ })
82
+
83
+ this.schematic_component_id = schematic_component.schematic_component_id
84
+ }
85
+
86
+ doInitialPcbComponentRender() {
87
+ const { db } = this.project!
88
+ const { _parsedProps: props } = this
89
+
90
+ const pcb_component = db.pcb_component.insert({
91
+ center: { x: props.pcbX ?? 0, y: props.pcbY ?? 0 },
92
+ width: 2, // Default width, adjust as needed
93
+ height: 3, // Default height, adjust as needed
94
+ layer: props.layer ?? "top",
95
+ rotation: props.pcbRotation ?? 0,
96
+ source_component_id: this.source_component_id!,
97
+ })
98
+
99
+ this.pcb_component_id = pcb_component.pcb_component_id
100
+ }
101
+ }
@@ -0,0 +1,60 @@
1
+ import { PrimitiveComponent } from "../base-components/PrimitiveComponent"
2
+ import { platedHoleProps } from "@tscircuit/props"
3
+ import type { Port } from "./Port"
4
+ import type { PCBPlatedHoleInput } from "@tscircuit/soup"
5
+
6
+ export class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
7
+ pcb_plated_hole_id: string | null = null
8
+ matchedPort: Port | null = null
9
+ isPcbPrimitive = true
10
+
11
+ get config() {
12
+ return {
13
+ zodProps: platedHoleProps,
14
+ }
15
+ }
16
+
17
+ doInitialPortMatching(): void {
18
+ const parentPorts = (this.parent?.children ?? []).filter(
19
+ (c) => c.componentName === "Port",
20
+ ) as Port[]
21
+
22
+ if (!this.props.portHints) {
23
+ return
24
+ }
25
+
26
+ for (const port of parentPorts) {
27
+ if (port.isMatchingAnyOf(this.props.portHints)) {
28
+ this.matchedPort = port
29
+ port.registerMatch(this)
30
+ return
31
+ }
32
+ }
33
+ }
34
+
35
+ doInitialPcbPrimitiveRender(): void {
36
+ const { db } = this.project!
37
+ const { _parsedProps: props } = this
38
+ if (!props.portHints) return
39
+ const position = this.getGlobalPcbPosition()
40
+ if (props.shape === "circle") {
41
+ const plated_hole_input: PCBPlatedHoleInput = {
42
+ pcb_component_id: this.parent?.pcb_component_id!,
43
+ pcb_port_id: this.matchedPort?.pcb_port_id!,
44
+ layers: ["top", "bottom"],
45
+ outer_diameter: props.outerDiameter,
46
+ hole_diameter: props.holeDiameter,
47
+ shape: "circle",
48
+ port_hints: this.getNameAndAliases(),
49
+ x: position.x,
50
+ y: position.y,
51
+ type: "pcb_plated_hole",
52
+ }
53
+
54
+ // @ts-ignore - some issue with soup-util types it seems
55
+ const pcb_plated_hole = db.pcb_plated_hole.insert(plated_hole_input)
56
+
57
+ // this.pcb_plated_hole_id = pcb_plated_hole.pcb_plated_hole_id
58
+ }
59
+ }
60
+ }
@@ -82,6 +82,7 @@ export class Port extends PrimitiveComponent<typeof portProps> {
82
82
  ...(typeof props.pinNumber === "number"
83
83
  ? [`pin${props.pinNumber}`, props.pinNumber.toString()]
84
84
  : []),
85
+ ...this.externallyAddedAliases,
85
86
  ]),
86
87
  ) as string[]
87
88
  }
@@ -0,0 +1,35 @@
1
+ import { silkscreenPathProps } from "@tscircuit/props"
2
+ import { PrimitiveComponent } from "../base-components/PrimitiveComponent"
3
+
4
+ export class SilkscreenPath extends PrimitiveComponent<
5
+ typeof silkscreenPathProps
6
+ > {
7
+ pcb_silkscreen_path_id: string | null = null
8
+
9
+ get config() {
10
+ return {
11
+ zodProps: silkscreenPathProps,
12
+ }
13
+ }
14
+
15
+ doInitialPcbPrimitiveRender(): void {
16
+ const { db } = this.project!
17
+ const { _parsedProps: props } = this
18
+
19
+ const layer = props.layer ?? "top"
20
+ if (layer !== "top" && layer !== "bottom") {
21
+ throw new Error(
22
+ `Invalid layer "${layer}" for SilkscreenPath. Must be "top" or "bottom".`,
23
+ )
24
+ }
25
+
26
+ const pcb_silkscreen_path = db.pcb_silkscreen_path.insert({
27
+ pcb_component_id: this.parent?.pcb_component_id!,
28
+ layer,
29
+ route: props.route,
30
+ stroke_width: props.strokeWidth ?? 0.1,
31
+ })
32
+
33
+ this.pcb_silkscreen_path_id = pcb_silkscreen_path.pcb_silkscreen_path_id
34
+ }
35
+ }
@@ -9,6 +9,7 @@ declare global {
9
9
  diode: Props.DiodeProps
10
10
  led: Props.LedProps
11
11
  board: Props.BoardProps
12
+ jumper: Props.JumperProps
12
13
  bug: Props.ChipProps
13
14
  // TODO use ChipProps once it gets merged in @tscircuit/props
14
15
  chip: Props.ChipProps