@tscircuit/parts-engine 0.0.10 → 0.0.11
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/jlc-parts-engine.ts +51 -16
- package/package.json +1 -1
- package/tests/jlc-parts-engine.test.ts +40 -1
package/lib/jlc-parts-engine.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { PartsEngine, SupplierPartNumbers } from "@tscircuit/props"
|
|
2
2
|
import { getJlcpcbPackageName } from "./footprint-translators/index"
|
|
3
3
|
|
|
4
|
-
const cache = new Map<string, any>()
|
|
4
|
+
export const cache = new Map<string, any>()
|
|
5
5
|
|
|
6
6
|
const getJlcPartsCached = async (name: any, params: any) => {
|
|
7
7
|
const paramString = new URLSearchParams({
|
|
@@ -19,6 +19,13 @@ const getJlcPartsCached = async (name: any, params: any) => {
|
|
|
19
19
|
return responseJson
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
const withBasicPartPreference = (parts: any[] | undefined) => {
|
|
23
|
+
if (!parts) return []
|
|
24
|
+
return [...parts].sort(
|
|
25
|
+
(a, b) => Number(b.is_basic ?? false) - Number(a.is_basic ?? false),
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
22
29
|
export const jlcPartsEngine: PartsEngine = {
|
|
23
30
|
findPart: async ({
|
|
24
31
|
sourceComponent,
|
|
@@ -36,7 +43,9 @@ export const jlcPartsEngine: PartsEngine = {
|
|
|
36
43
|
})
|
|
37
44
|
|
|
38
45
|
return {
|
|
39
|
-
jlcpcb: (resistors
|
|
46
|
+
jlcpcb: withBasicPartPreference(resistors)
|
|
47
|
+
.map((r: any) => `C${r.lcsc}`)
|
|
48
|
+
.slice(0, 3),
|
|
40
49
|
}
|
|
41
50
|
} else if (
|
|
42
51
|
sourceComponent.type === "source_component" &&
|
|
@@ -48,7 +57,9 @@ export const jlcPartsEngine: PartsEngine = {
|
|
|
48
57
|
})
|
|
49
58
|
|
|
50
59
|
return {
|
|
51
|
-
jlcpcb: (capacitors
|
|
60
|
+
jlcpcb: withBasicPartPreference(capacitors)
|
|
61
|
+
.map((c: any) => `C${c.lcsc}`)
|
|
62
|
+
.slice(0, 3),
|
|
52
63
|
}
|
|
53
64
|
} else if (
|
|
54
65
|
sourceComponent.type === "source_component" &&
|
|
@@ -72,7 +83,9 @@ export const jlcPartsEngine: PartsEngine = {
|
|
|
72
83
|
},
|
|
73
84
|
)
|
|
74
85
|
return {
|
|
75
|
-
jlcpcb: (headers
|
|
86
|
+
jlcpcb: withBasicPartPreference(headers)
|
|
87
|
+
.map((h: any) => `C${h.lcsc}`)
|
|
88
|
+
.slice(0, 3),
|
|
76
89
|
}
|
|
77
90
|
} else if (
|
|
78
91
|
sourceComponent.type === "source_component" &&
|
|
@@ -83,7 +96,7 @@ export const jlcPartsEngine: PartsEngine = {
|
|
|
83
96
|
package: jlcpcbPackage,
|
|
84
97
|
})
|
|
85
98
|
return {
|
|
86
|
-
jlcpcb: (potentiometers
|
|
99
|
+
jlcpcb: withBasicPartPreference(potentiometers)
|
|
87
100
|
.map((p: any) => `C${p.lcsc}`)
|
|
88
101
|
.slice(0, 3),
|
|
89
102
|
}
|
|
@@ -95,7 +108,9 @@ export const jlcPartsEngine: PartsEngine = {
|
|
|
95
108
|
package: jlcpcbPackage,
|
|
96
109
|
})
|
|
97
110
|
return {
|
|
98
|
-
jlcpcb: (diodes
|
|
111
|
+
jlcpcb: withBasicPartPreference(diodes)
|
|
112
|
+
.map((d: any) => `C${d.lcsc}`)
|
|
113
|
+
.slice(0, 3),
|
|
99
114
|
}
|
|
100
115
|
} else if (
|
|
101
116
|
sourceComponent.type === "source_component" &&
|
|
@@ -105,7 +120,9 @@ export const jlcPartsEngine: PartsEngine = {
|
|
|
105
120
|
package: jlcpcbPackage,
|
|
106
121
|
})
|
|
107
122
|
return {
|
|
108
|
-
jlcpcb: (chips
|
|
123
|
+
jlcpcb: withBasicPartPreference(chips)
|
|
124
|
+
.map((c: any) => `C${c.lcsc}`)
|
|
125
|
+
.slice(0, 3),
|
|
109
126
|
}
|
|
110
127
|
} else if (
|
|
111
128
|
sourceComponent.type === "source_component" &&
|
|
@@ -116,7 +133,9 @@ export const jlcPartsEngine: PartsEngine = {
|
|
|
116
133
|
transistor_type: sourceComponent.transistor_type,
|
|
117
134
|
})
|
|
118
135
|
return {
|
|
119
|
-
jlcpcb: (transistors
|
|
136
|
+
jlcpcb: withBasicPartPreference(transistors)
|
|
137
|
+
.map((t: any) => `C${t.lcsc}`)
|
|
138
|
+
.slice(0, 3),
|
|
120
139
|
}
|
|
121
140
|
} else if (
|
|
122
141
|
sourceComponent.type === "source_component" &&
|
|
@@ -127,7 +146,9 @@ export const jlcPartsEngine: PartsEngine = {
|
|
|
127
146
|
package: jlcpcbPackage,
|
|
128
147
|
})
|
|
129
148
|
return {
|
|
130
|
-
jlcpcb: (power_sources
|
|
149
|
+
jlcpcb: withBasicPartPreference(power_sources)
|
|
150
|
+
.map((p: any) => `C${p.lcsc}`)
|
|
151
|
+
.slice(0, 3),
|
|
131
152
|
}
|
|
132
153
|
} else if (
|
|
133
154
|
sourceComponent.type === "source_component" &&
|
|
@@ -138,7 +159,9 @@ export const jlcPartsEngine: PartsEngine = {
|
|
|
138
159
|
package: jlcpcbPackage,
|
|
139
160
|
})
|
|
140
161
|
return {
|
|
141
|
-
jlcpcb: (inductors
|
|
162
|
+
jlcpcb: withBasicPartPreference(inductors)
|
|
163
|
+
.map((i: any) => `C${i.lcsc}`)
|
|
164
|
+
.slice(0, 3),
|
|
142
165
|
}
|
|
143
166
|
} else if (
|
|
144
167
|
sourceComponent.type === "source_component" &&
|
|
@@ -150,7 +173,9 @@ export const jlcPartsEngine: PartsEngine = {
|
|
|
150
173
|
package: jlcpcbPackage,
|
|
151
174
|
})
|
|
152
175
|
return {
|
|
153
|
-
jlcpcb: (crystals
|
|
176
|
+
jlcpcb: withBasicPartPreference(crystals)
|
|
177
|
+
.map((c: any) => `C${c.lcsc}`)
|
|
178
|
+
.slice(0, 3),
|
|
154
179
|
}
|
|
155
180
|
} else if (
|
|
156
181
|
sourceComponent.type === "source_component" &&
|
|
@@ -162,7 +187,9 @@ export const jlcPartsEngine: PartsEngine = {
|
|
|
162
187
|
channel_type: sourceComponent.channel_type,
|
|
163
188
|
})
|
|
164
189
|
return {
|
|
165
|
-
jlcpcb: (mosfets
|
|
190
|
+
jlcpcb: withBasicPartPreference(mosfets)
|
|
191
|
+
.map((m: any) => `C${m.lcsc}`)
|
|
192
|
+
.slice(0, 3),
|
|
166
193
|
}
|
|
167
194
|
} else if (
|
|
168
195
|
sourceComponent.type === "source_component" &&
|
|
@@ -173,7 +200,9 @@ export const jlcPartsEngine: PartsEngine = {
|
|
|
173
200
|
package: jlcpcbPackage,
|
|
174
201
|
})
|
|
175
202
|
return {
|
|
176
|
-
jlcpcb: (resonators
|
|
203
|
+
jlcpcb: withBasicPartPreference(resonators)
|
|
204
|
+
.map((r: any) => `C${r.lcsc}`)
|
|
205
|
+
.slice(0, 3),
|
|
177
206
|
}
|
|
178
207
|
} else if (
|
|
179
208
|
sourceComponent.type === "source_component" &&
|
|
@@ -184,7 +213,9 @@ export const jlcPartsEngine: PartsEngine = {
|
|
|
184
213
|
package: jlcpcbPackage,
|
|
185
214
|
})
|
|
186
215
|
return {
|
|
187
|
-
jlcpcb: (switches
|
|
216
|
+
jlcpcb: withBasicPartPreference(switches)
|
|
217
|
+
.map((s: any) => `C${s.lcsc}`)
|
|
218
|
+
.slice(0, 3),
|
|
188
219
|
}
|
|
189
220
|
} else if (
|
|
190
221
|
sourceComponent.type === "source_component" &&
|
|
@@ -194,7 +225,9 @@ export const jlcPartsEngine: PartsEngine = {
|
|
|
194
225
|
package: jlcpcbPackage,
|
|
195
226
|
})
|
|
196
227
|
return {
|
|
197
|
-
jlcpcb: (leds
|
|
228
|
+
jlcpcb: withBasicPartPreference(leds)
|
|
229
|
+
.map((l: any) => `C${l.lcsc}`)
|
|
230
|
+
.slice(0, 3),
|
|
198
231
|
}
|
|
199
232
|
} else if (
|
|
200
233
|
sourceComponent.type === "source_component" &&
|
|
@@ -204,7 +237,9 @@ export const jlcPartsEngine: PartsEngine = {
|
|
|
204
237
|
package: jlcpcbPackage,
|
|
205
238
|
})
|
|
206
239
|
return {
|
|
207
|
-
jlcpcb: (fuses
|
|
240
|
+
jlcpcb: withBasicPartPreference(fuses)
|
|
241
|
+
.map((l: any) => `C${l.lcsc}`)
|
|
242
|
+
.slice(0, 3),
|
|
208
243
|
}
|
|
209
244
|
}
|
|
210
245
|
return {}
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { describe, test, expect, beforeEach } from "bun:test"
|
|
2
|
-
import { jlcPartsEngine } from "../lib/jlc-parts-engine"
|
|
2
|
+
import { jlcPartsEngine, cache } from "../lib/jlc-parts-engine"
|
|
3
3
|
import type { AnySourceComponent } from "circuit-json"
|
|
4
4
|
describe("jlcPartsEngine", () => {
|
|
5
5
|
beforeEach(() => {
|
|
6
|
+
cache.clear()
|
|
6
7
|
// Reset fetch fake between tests
|
|
7
8
|
globalThis.fetch = (async (url: string) => {
|
|
8
9
|
if (url.includes("/resistors/")) {
|
|
@@ -431,4 +432,42 @@ describe("jlcPartsEngine", () => {
|
|
|
431
432
|
|
|
432
433
|
expect(result).toEqual({ jlcpcb: [] })
|
|
433
434
|
})
|
|
435
|
+
|
|
436
|
+
test("should prefer basic parts when available", async () => {
|
|
437
|
+
// Override the global fetch mock for this specific test
|
|
438
|
+
globalThis.fetch = (async (url: string) => {
|
|
439
|
+
if (url.includes("/resistors/")) {
|
|
440
|
+
return {
|
|
441
|
+
json: async () => ({
|
|
442
|
+
resistors: [
|
|
443
|
+
{ lcsc: "1111" }, // is_basic is undefined, treated as false
|
|
444
|
+
{ lcsc: "2222", is_basic: true },
|
|
445
|
+
{ lcsc: "3333", is_basic: false },
|
|
446
|
+
{ lcsc: "4444", is_basic: true },
|
|
447
|
+
{ lcsc: "5555" },
|
|
448
|
+
],
|
|
449
|
+
}),
|
|
450
|
+
} as Response
|
|
451
|
+
}
|
|
452
|
+
return {} as Response
|
|
453
|
+
}) as unknown as typeof fetch
|
|
454
|
+
|
|
455
|
+
const resistor: AnySourceComponent = {
|
|
456
|
+
type: "source_component",
|
|
457
|
+
ftype: "simple_resistor",
|
|
458
|
+
resistance: 10000,
|
|
459
|
+
source_component_id: "source_component_0",
|
|
460
|
+
name: "R1",
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
const result = await jlcPartsEngine.findPart({
|
|
464
|
+
sourceComponent: resistor,
|
|
465
|
+
footprinterString: "0603",
|
|
466
|
+
})
|
|
467
|
+
|
|
468
|
+
// Expecting basic parts to be prioritized
|
|
469
|
+
expect(result).toEqual({
|
|
470
|
+
jlcpcb: ["C2222", "C4444", "C1111"],
|
|
471
|
+
})
|
|
472
|
+
})
|
|
434
473
|
})
|