@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.
- package/lib/footprint-translators/get-footprinter-string-from-kicad.ts +21 -0
- package/lib/footprint-translators/get-jlc-package-from-footprinter-string.ts +12 -0
- package/lib/footprint-translators/index.ts +25 -0
- package/lib/jlc-parts-engine.ts +17 -17
- package/package.json +1 -1
- package/tests/jlc-parts-engine.test.ts +38 -1
|
@@ -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
|
+
}
|
package/lib/jlc-parts-engine.ts
CHANGED
|
@@ -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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
@@ -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: "
|
|
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",
|