@tscircuit/parts-engine 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.
@@ -1,291 +0,0 @@
1
- import type { PartsEngine, SupplierPartNumbers } from "@tscircuit/props"
2
- import { getJlcpcbPackageName } from "./footprint-translators/index"
3
- import {
4
- fetchEasyEDAComponent,
5
- EasyEdaJsonSchema,
6
- convertEasyEdaJsonToCircuitJson,
7
- } from "easyeda/browser"
8
-
9
- export const cache = new Map<string, any>()
10
-
11
- const getJlcPartsCached = async (name: any, params: any) => {
12
- const paramString = new URLSearchParams({
13
- ...params,
14
- json: "true",
15
- }).toString()
16
- if (cache.has(paramString)) {
17
- return cache.get(paramString)
18
- }
19
- const response = await fetch(
20
- `https://jlcsearch.tscircuit.com/${name}/list?${paramString}`,
21
- )
22
- const responseJson = await response.json()
23
- cache.set(paramString, responseJson)
24
- return responseJson
25
- }
26
-
27
- const withBasicPartPreference = (parts: any[] | undefined) => {
28
- if (!parts) return []
29
- return [...parts].sort(
30
- (a, b) => Number(b.is_basic ?? false) - Number(a.is_basic ?? false),
31
- )
32
- }
33
-
34
- export const jlcPartsEngine: PartsEngine = {
35
- findPart: async ({
36
- sourceComponent,
37
- footprinterString,
38
- }): Promise<SupplierPartNumbers> => {
39
- const jlcpcbPackage = getJlcpcbPackageName(footprinterString)
40
-
41
- if (
42
- sourceComponent.type === "source_component" &&
43
- sourceComponent.ftype === "simple_resistor"
44
- ) {
45
- const { resistors } = await getJlcPartsCached("resistors", {
46
- resistance: sourceComponent.resistance,
47
- package: jlcpcbPackage,
48
- })
49
-
50
- return {
51
- jlcpcb: withBasicPartPreference(resistors)
52
- .map((r: any) => `C${r.lcsc}`)
53
- .slice(0, 3),
54
- }
55
- } else if (
56
- sourceComponent.type === "source_component" &&
57
- sourceComponent.ftype === "simple_capacitor"
58
- ) {
59
- const { capacitors } = await getJlcPartsCached("capacitors", {
60
- capacitance: sourceComponent.capacitance,
61
- package: jlcpcbPackage,
62
- })
63
-
64
- return {
65
- jlcpcb: withBasicPartPreference(capacitors)
66
- .map((c: any) => `C${c.lcsc}`)
67
- .slice(0, 3),
68
- }
69
- } else if (
70
- sourceComponent.type === "source_component" &&
71
- sourceComponent.ftype === "simple_pin_header"
72
- ) {
73
- let pitch: number | undefined
74
- if (footprinterString?.includes("_p")) {
75
- pitch = Number(footprinterString.split("_p")[1])
76
- }
77
- const { headers } = await getJlcPartsCached(
78
- "headers",
79
- pitch
80
- ? {
81
- pitch: pitch,
82
- num_pins: sourceComponent.pin_count,
83
- gender: sourceComponent.gender,
84
- }
85
- : {
86
- num_pins: sourceComponent.pin_count,
87
- gender: sourceComponent.gender,
88
- },
89
- )
90
- return {
91
- jlcpcb: withBasicPartPreference(headers)
92
- .map((h: any) => `C${h.lcsc}`)
93
- .slice(0, 3),
94
- }
95
- } else if (
96
- sourceComponent.type === "source_component" &&
97
- sourceComponent.ftype === "simple_potentiometer"
98
- ) {
99
- const { potentiometers } = await getJlcPartsCached("potentiometers", {
100
- resistance: sourceComponent.max_resistance,
101
- package: jlcpcbPackage,
102
- })
103
- return {
104
- jlcpcb: withBasicPartPreference(potentiometers)
105
- .map((p: any) => `C${p.lcsc}`)
106
- .slice(0, 3),
107
- }
108
- } else if (
109
- sourceComponent.type === "source_component" &&
110
- sourceComponent.ftype === "simple_diode"
111
- ) {
112
- const { diodes } = await getJlcPartsCached("diodes", {
113
- package: jlcpcbPackage,
114
- })
115
- return {
116
- jlcpcb: withBasicPartPreference(diodes)
117
- .map((d: any) => `C${d.lcsc}`)
118
- .slice(0, 3),
119
- }
120
- } else if (
121
- sourceComponent.type === "source_component" &&
122
- sourceComponent.ftype === "simple_chip"
123
- ) {
124
- if (!jlcpcbPackage || !footprinterString) {
125
- return {}
126
- }
127
- const { chips } = await getJlcPartsCached("chips", {
128
- package: jlcpcbPackage,
129
- })
130
- return {
131
- jlcpcb: withBasicPartPreference(chips)
132
- .map((c: any) => `C${c.lcsc}`)
133
- .slice(0, 3),
134
- }
135
- } else if (
136
- sourceComponent.type === "source_component" &&
137
- sourceComponent.ftype === "simple_transistor"
138
- ) {
139
- const { transistors } = await getJlcPartsCached("transistors", {
140
- package: jlcpcbPackage,
141
- transistor_type: sourceComponent.transistor_type,
142
- })
143
- return {
144
- jlcpcb: withBasicPartPreference(transistors)
145
- .map((t: any) => `C${t.lcsc}`)
146
- .slice(0, 3),
147
- }
148
- } else if (
149
- sourceComponent.type === "source_component" &&
150
- sourceComponent.ftype === "simple_power_source"
151
- ) {
152
- const { power_sources } = await getJlcPartsCached("power_sources", {
153
- voltage: sourceComponent.voltage,
154
- package: jlcpcbPackage,
155
- })
156
- return {
157
- jlcpcb: withBasicPartPreference(power_sources)
158
- .map((p: any) => `C${p.lcsc}`)
159
- .slice(0, 3),
160
- }
161
- } else if (
162
- sourceComponent.type === "source_component" &&
163
- sourceComponent.ftype === "simple_inductor"
164
- ) {
165
- const { inductors } = await getJlcPartsCached("inductors", {
166
- inductance: sourceComponent.inductance,
167
- package: jlcpcbPackage,
168
- })
169
- return {
170
- jlcpcb: withBasicPartPreference(inductors)
171
- .map((i: any) => `C${i.lcsc}`)
172
- .slice(0, 3),
173
- }
174
- } else if (
175
- sourceComponent.type === "source_component" &&
176
- sourceComponent.ftype === "simple_crystal"
177
- ) {
178
- const { crystals } = await getJlcPartsCached("crystals", {
179
- frequency: sourceComponent.frequency,
180
- load_capacitance: sourceComponent.load_capacitance,
181
- package: jlcpcbPackage,
182
- })
183
- return {
184
- jlcpcb: withBasicPartPreference(crystals)
185
- .map((c: any) => `C${c.lcsc}`)
186
- .slice(0, 3),
187
- }
188
- } else if (
189
- sourceComponent.type === "source_component" &&
190
- sourceComponent.ftype === "simple_mosfet"
191
- ) {
192
- const { mosfets } = await getJlcPartsCached("mosfets", {
193
- package: jlcpcbPackage,
194
- mosfet_mode: sourceComponent.mosfet_mode,
195
- channel_type: sourceComponent.channel_type,
196
- })
197
- return {
198
- jlcpcb: withBasicPartPreference(mosfets)
199
- .map((m: any) => `C${m.lcsc}`)
200
- .slice(0, 3),
201
- }
202
- } else if (
203
- sourceComponent.type === "source_component" &&
204
- sourceComponent.ftype === "simple_resonator"
205
- ) {
206
- const { resonators } = await getJlcPartsCached("resonators", {
207
- frequency: sourceComponent.frequency,
208
- package: jlcpcbPackage,
209
- })
210
- return {
211
- jlcpcb: withBasicPartPreference(resonators)
212
- .map((r: any) => `C${r.lcsc}`)
213
- .slice(0, 3),
214
- }
215
- } else if (
216
- sourceComponent.type === "source_component" &&
217
- sourceComponent.ftype === "simple_switch"
218
- ) {
219
- const { switches } = await getJlcPartsCached("switches", {
220
- switch_type: sourceComponent.type,
221
- package: jlcpcbPackage,
222
- })
223
- return {
224
- jlcpcb: withBasicPartPreference(switches)
225
- .map((s: any) => `C${s.lcsc}`)
226
- .slice(0, 3),
227
- }
228
- } else if (
229
- sourceComponent.type === "source_component" &&
230
- sourceComponent.ftype === "simple_led"
231
- ) {
232
- const { leds } = await getJlcPartsCached("leds", {
233
- package: jlcpcbPackage,
234
- })
235
- return {
236
- jlcpcb: withBasicPartPreference(leds)
237
- .map((l: any) => `C${l.lcsc}`)
238
- .slice(0, 3),
239
- }
240
- } else if (
241
- sourceComponent.type === "source_component" &&
242
- sourceComponent.ftype === "simple_fuse"
243
- ) {
244
- const { fuses } = await getJlcPartsCached("fuses", {
245
- package: jlcpcbPackage,
246
- })
247
- return {
248
- jlcpcb: withBasicPartPreference(fuses)
249
- .map((l: any) => `C${l.lcsc}`)
250
- .slice(0, 3),
251
- }
252
- } else if (
253
- sourceComponent.type === "source_component" &&
254
- sourceComponent.ftype === "simple_connector" &&
255
- sourceComponent.standard === "usb_c"
256
- ) {
257
- const { usb_c_connectors } = await getJlcPartsCached(
258
- "usb_c_connectors",
259
- {},
260
- )
261
- return {
262
- jlcpcb: withBasicPartPreference(usb_c_connectors)
263
- .map((c: any) => `C${c.lcsc}`)
264
- .slice(0, 3),
265
- }
266
- }
267
- return {}
268
- },
269
-
270
- fetchPartCircuitJson: async ({
271
- supplierPartNumber,
272
- manufacturerPartNumber,
273
- }) => {
274
- let resolvedPartNumber = supplierPartNumber
275
-
276
- if (!resolvedPartNumber && manufacturerPartNumber) {
277
- const { components } = await getJlcPartsCached("components", {
278
- search: manufacturerPartNumber,
279
- })
280
- resolvedPartNumber = components?.[0]
281
- ? `C${components[0].lcsc}`
282
- : undefined
283
- }
284
-
285
- if (!resolvedPartNumber) return undefined
286
-
287
- const rawEasyEdaJson = await fetchEasyEDAComponent(resolvedPartNumber)
288
- const parsed = EasyEdaJsonSchema.parse(rawEasyEdaJson)
289
- return convertEasyEdaJsonToCircuitJson(parsed)
290
- },
291
- }
@@ -1,33 +0,0 @@
1
- import { test, expect } from "bun:test"
2
- import { jlcPartsEngine } from "../lib/jlc-parts-engine"
3
-
4
- test("fetchPartCircuitJson returns circuit json for USB-C connector (C165948)", async () => {
5
- const result = await jlcPartsEngine.fetchPartCircuitJson!({
6
- supplierPartNumber: "C165948",
7
- })
8
-
9
- expect(result).toBeDefined()
10
- expect(Array.isArray(result)).toBe(true)
11
-
12
- const types = result!.map((el: any) => el.type)
13
-
14
- // Has PCB elements
15
- expect(types.filter((t: string) => t === "pcb_smtpad").length).toBe(12)
16
- expect(types.filter((t: string) => t === "pcb_plated_hole").length).toBe(4)
17
- expect(types).toContain("pcb_silkscreen_path")
18
- expect(types).toContain("pcb_courtyard_outline")
19
- expect(types).toContain("cad_component")
20
- }, 20000)
21
-
22
- test("fetchPartCircuitJson works with manufacturerPartNumber (TYPE-C-31-M-12)", async () => {
23
- const result = await jlcPartsEngine.fetchPartCircuitJson!({
24
- manufacturerPartNumber: "TYPE-C-31-M-12",
25
- })
26
-
27
- expect(result).toBeDefined()
28
- expect(Array.isArray(result)).toBe(true)
29
-
30
- const types = result!.map((el: any) => el.type)
31
- expect(types.filter((t: string) => t === "pcb_smtpad").length).toBe(12)
32
- expect(types.filter((t: string) => t === "pcb_plated_hole").length).toBe(4)
33
- }, 20000)