@tscircuit/parts-engine 0.0.9 → 0.0.10

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.
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Transforms a KiCad footprint string into a generic "footprinter string".
3
+ * For now, this is a simplified conversion to a standard package name.
4
+ * e.g. "kicad:Resistor_SMD:R_0603_1608Metric" -> "0603"
5
+ */
6
+ export const getFootprinterStringFromKicad = (
7
+ kicadFootprint: string,
8
+ ): string | undefined => {
9
+ // kicad:Resistor_SMD:R_0603_1608Metric -> 0603
10
+ let match = kicadFootprint.match(/:[RC]_(\d{4})_/)
11
+ if (match) return match[1]
12
+
13
+ // kicad:Package_SO:SOIC-8_3.9x4.9mm_P1.27mm -> SOIC-8
14
+ // kicad:Package_TO_SOT_SMD:SOT-23 -> SOT-23
15
+ match = kicadFootprint.match(
16
+ /:(SOIC-\d+|SOT-\d+|SOD-\d+|SSOP-\d+|TSSOP-\d+|QFP-\d+|QFN-\d+)/,
17
+ )
18
+ if (match) return match[1]
19
+
20
+ return undefined
21
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Transforms a generic "footprinter string" into a JLC-compatible package name.
3
+ * e.g. "cap0603" -> "0603"
4
+ */
5
+ export const getJlcPackageFromFootprinterString = (
6
+ footprinterString: string,
7
+ ): string => {
8
+ if (footprinterString.includes("cap")) {
9
+ return footprinterString.replace(/cap/g, "")
10
+ }
11
+ return footprinterString
12
+ }
@@ -0,0 +1,25 @@
1
+ import { getFootprinterStringFromKicad } from "./get-footprinter-string-from-kicad"
2
+ import { getJlcPackageFromFootprinterString } from "./get-jlc-package-from-footprinter-string"
3
+
4
+ /**
5
+ * Get a JLC-compatible package name from a footprint string, which could be
6
+ * a KiCad footprint or a generic "footprinter string".
7
+ */
8
+ export const getJlcpcbPackageName = (
9
+ footprint: string | undefined,
10
+ ): string | undefined => {
11
+ if (!footprint) return undefined
12
+
13
+ if (footprint.startsWith("kicad:")) {
14
+ const footprinterString = getFootprinterStringFromKicad(footprint)
15
+ if (footprinterString) {
16
+ return getJlcPackageFromFootprinterString(footprinterString)
17
+ }
18
+
19
+ // Fallback for un-matched KiCad strings
20
+ return footprint
21
+ }
22
+
23
+ // Not a KiCad string, assume it's a footprinter string
24
+ return getJlcPackageFromFootprinterString(footprint)
25
+ }
@@ -1,4 +1,5 @@
1
1
  import type { PartsEngine, SupplierPartNumbers } from "@tscircuit/props"
2
+ import { getJlcpcbPackageName } from "./footprint-translators/index"
2
3
 
3
4
  const cache = new Map<string, any>()
4
5
 
@@ -23,13 +24,15 @@ export const jlcPartsEngine: PartsEngine = {
23
24
  sourceComponent,
24
25
  footprinterString,
25
26
  }): Promise<SupplierPartNumbers> => {
27
+ const jlcpcbPackage = getJlcpcbPackageName(footprinterString)
28
+
26
29
  if (
27
30
  sourceComponent.type === "source_component" &&
28
31
  sourceComponent.ftype === "simple_resistor"
29
32
  ) {
30
33
  const { resistors } = await getJlcPartsCached("resistors", {
31
34
  resistance: sourceComponent.resistance,
32
- package: footprinterString,
35
+ package: jlcpcbPackage,
33
36
  })
34
37
 
35
38
  return {
@@ -39,12 +42,9 @@ export const jlcPartsEngine: PartsEngine = {
39
42
  sourceComponent.type === "source_component" &&
40
43
  sourceComponent.ftype === "simple_capacitor"
41
44
  ) {
42
- if (footprinterString?.includes("cap")) {
43
- footprinterString = footprinterString.replace("cap", "")
44
- }
45
45
  const { capacitors } = await getJlcPartsCached("capacitors", {
46
46
  capacitance: sourceComponent.capacitance,
47
- package: footprinterString,
47
+ package: jlcpcbPackage,
48
48
  })
49
49
 
50
50
  return {
@@ -80,7 +80,7 @@ export const jlcPartsEngine: PartsEngine = {
80
80
  ) {
81
81
  const { potentiometers } = await getJlcPartsCached("potentiometers", {
82
82
  resistance: sourceComponent.max_resistance,
83
- package: footprinterString,
83
+ package: jlcpcbPackage,
84
84
  })
85
85
  return {
86
86
  jlcpcb: (potentiometers ?? [])
@@ -92,7 +92,7 @@ export const jlcPartsEngine: PartsEngine = {
92
92
  sourceComponent.ftype === "simple_diode"
93
93
  ) {
94
94
  const { diodes } = await getJlcPartsCached("diodes", {
95
- package: footprinterString,
95
+ package: jlcpcbPackage,
96
96
  })
97
97
  return {
98
98
  jlcpcb: (diodes ?? []).map((d: any) => `C${d.lcsc}`).slice(0, 3),
@@ -102,7 +102,7 @@ export const jlcPartsEngine: PartsEngine = {
102
102
  sourceComponent.ftype === "simple_chip"
103
103
  ) {
104
104
  const { chips } = await getJlcPartsCached("chips", {
105
- package: footprinterString,
105
+ package: jlcpcbPackage,
106
106
  })
107
107
  return {
108
108
  jlcpcb: (chips ?? []).map((c: any) => `C${c.lcsc}`).slice(0, 3),
@@ -112,7 +112,7 @@ export const jlcPartsEngine: PartsEngine = {
112
112
  sourceComponent.ftype === "simple_transistor"
113
113
  ) {
114
114
  const { transistors } = await getJlcPartsCached("transistors", {
115
- package: footprinterString,
115
+ package: jlcpcbPackage,
116
116
  transistor_type: sourceComponent.transistor_type,
117
117
  })
118
118
  return {
@@ -124,7 +124,7 @@ export const jlcPartsEngine: PartsEngine = {
124
124
  ) {
125
125
  const { power_sources } = await getJlcPartsCached("power_sources", {
126
126
  voltage: sourceComponent.voltage,
127
- package: footprinterString,
127
+ package: jlcpcbPackage,
128
128
  })
129
129
  return {
130
130
  jlcpcb: (power_sources ?? []).map((p: any) => `C${p.lcsc}`).slice(0, 3),
@@ -135,7 +135,7 @@ export const jlcPartsEngine: PartsEngine = {
135
135
  ) {
136
136
  const { inductors } = await getJlcPartsCached("inductors", {
137
137
  inductance: sourceComponent.inductance,
138
- package: footprinterString,
138
+ package: jlcpcbPackage,
139
139
  })
140
140
  return {
141
141
  jlcpcb: (inductors ?? []).map((i: any) => `C${i.lcsc}`).slice(0, 3),
@@ -147,7 +147,7 @@ export const jlcPartsEngine: PartsEngine = {
147
147
  const { crystals } = await getJlcPartsCached("crystals", {
148
148
  frequency: sourceComponent.frequency,
149
149
  load_capacitance: sourceComponent.load_capacitance,
150
- package: footprinterString,
150
+ package: jlcpcbPackage,
151
151
  })
152
152
  return {
153
153
  jlcpcb: (crystals ?? []).map((c: any) => `C${c.lcsc}`).slice(0, 3),
@@ -157,7 +157,7 @@ export const jlcPartsEngine: PartsEngine = {
157
157
  sourceComponent.ftype === "simple_mosfet"
158
158
  ) {
159
159
  const { mosfets } = await getJlcPartsCached("mosfets", {
160
- package: footprinterString,
160
+ package: jlcpcbPackage,
161
161
  mosfet_mode: sourceComponent.mosfet_mode,
162
162
  channel_type: sourceComponent.channel_type,
163
163
  })
@@ -170,7 +170,7 @@ export const jlcPartsEngine: PartsEngine = {
170
170
  ) {
171
171
  const { resonators } = await getJlcPartsCached("resonators", {
172
172
  frequency: sourceComponent.frequency,
173
- package: footprinterString,
173
+ package: jlcpcbPackage,
174
174
  })
175
175
  return {
176
176
  jlcpcb: (resonators ?? []).map((r: any) => `C${r.lcsc}`).slice(0, 3),
@@ -181,7 +181,7 @@ export const jlcPartsEngine: PartsEngine = {
181
181
  ) {
182
182
  const { switches } = await getJlcPartsCached("switches", {
183
183
  switch_type: sourceComponent.type,
184
- package: footprinterString,
184
+ package: jlcpcbPackage,
185
185
  })
186
186
  return {
187
187
  jlcpcb: (switches ?? []).map((s: any) => `C${s.lcsc}`).slice(0, 3),
@@ -191,7 +191,7 @@ export const jlcPartsEngine: PartsEngine = {
191
191
  sourceComponent.ftype === "simple_led"
192
192
  ) {
193
193
  const { leds } = await getJlcPartsCached("leds", {
194
- package: footprinterString,
194
+ package: jlcpcbPackage,
195
195
  })
196
196
  return {
197
197
  jlcpcb: (leds ?? []).map((l: any) => `C${l.lcsc}`).slice(0, 3),
@@ -201,7 +201,7 @@ export const jlcPartsEngine: PartsEngine = {
201
201
  sourceComponent.ftype === "simple_fuse"
202
202
  ) {
203
203
  const { fuses } = await getJlcPartsCached("fuses", {
204
- package: footprinterString,
204
+ package: jlcpcbPackage,
205
205
  })
206
206
  return {
207
207
  jlcpcb: (fuses ?? []).map((l: any) => `C${l.lcsc}`).slice(0, 3),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/parts-engine",
3
- "version": "0.0.9",
3
+ "version": "0.0.10",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "devDependencies": {
@@ -127,6 +127,25 @@ describe("jlcPartsEngine", () => {
127
127
  })
128
128
  })
129
129
 
130
+ test("should find resistor parts with kicad footprint", async () => {
131
+ const resistor: AnySourceComponent = {
132
+ type: "source_component",
133
+ ftype: "simple_resistor",
134
+ resistance: 10000,
135
+ source_component_id: "source_component_0",
136
+ name: "R1",
137
+ }
138
+
139
+ const result = await jlcPartsEngine.findPart({
140
+ sourceComponent: resistor,
141
+ footprinterString: "kicad:Resistor_SMD:R_0603_1608Metric",
142
+ })
143
+
144
+ expect(result).toEqual({
145
+ jlcpcb: ["C1234", "C5678", "C9012"],
146
+ })
147
+ })
148
+
130
149
  test("should find capacitor parts", async () => {
131
150
  const capacitor: AnySourceComponent = {
132
151
  type: "source_component",
@@ -138,7 +157,7 @@ describe("jlcPartsEngine", () => {
138
157
 
139
158
  const result = await jlcPartsEngine.findPart({
140
159
  sourceComponent: capacitor,
141
- footprinterString: "0603cap",
160
+ footprinterString: "cap0603",
142
161
  })
143
162
 
144
163
  expect(result).toEqual({
@@ -222,6 +241,24 @@ describe("jlcPartsEngine", () => {
222
241
  })
223
242
  })
224
243
 
244
+ test("should find chip parts with kicad footprint", async () => {
245
+ const chip: AnySourceComponent = {
246
+ type: "source_component",
247
+ ftype: "simple_chip",
248
+ source_component_id: "source_component_0",
249
+ name: "U1",
250
+ }
251
+
252
+ const result = await jlcPartsEngine.findPart({
253
+ sourceComponent: chip,
254
+ footprinterString: "kicad:Package_SO:SOIC-8_3.9x4.9mm_P1.27mm",
255
+ })
256
+
257
+ expect(result).toEqual({
258
+ jlcpcb: ["C5678", "C9012", "C3456"],
259
+ })
260
+ })
261
+
225
262
  test("should find transistor parts", async () => {
226
263
  const transistor: AnySourceComponent = {
227
264
  type: "source_component",