@tscircuit/parts-engine 0.0.10 → 0.0.12

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,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 ?? []).map((r: any) => `C${r.lcsc}`).slice(0, 3),
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 ?? []).map((c: any) => `C${c.lcsc}`).slice(0, 3),
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 ?? []).map((h: any) => `C${h.lcsc}`).slice(0, 3),
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,17 +108,24 @@ export const jlcPartsEngine: PartsEngine = {
95
108
  package: jlcpcbPackage,
96
109
  })
97
110
  return {
98
- jlcpcb: (diodes ?? []).map((d: any) => `C${d.lcsc}`).slice(0, 3),
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" &&
102
117
  sourceComponent.ftype === "simple_chip"
103
118
  ) {
119
+ if (!jlcpcbPackage || !footprinterString) {
120
+ return {}
121
+ }
104
122
  const { chips } = await getJlcPartsCached("chips", {
105
123
  package: jlcpcbPackage,
106
124
  })
107
125
  return {
108
- jlcpcb: (chips ?? []).map((c: any) => `C${c.lcsc}`).slice(0, 3),
126
+ jlcpcb: withBasicPartPreference(chips)
127
+ .map((c: any) => `C${c.lcsc}`)
128
+ .slice(0, 3),
109
129
  }
110
130
  } else if (
111
131
  sourceComponent.type === "source_component" &&
@@ -116,7 +136,9 @@ export const jlcPartsEngine: PartsEngine = {
116
136
  transistor_type: sourceComponent.transistor_type,
117
137
  })
118
138
  return {
119
- jlcpcb: (transistors ?? []).map((t: any) => `C${t.lcsc}`).slice(0, 3),
139
+ jlcpcb: withBasicPartPreference(transistors)
140
+ .map((t: any) => `C${t.lcsc}`)
141
+ .slice(0, 3),
120
142
  }
121
143
  } else if (
122
144
  sourceComponent.type === "source_component" &&
@@ -127,7 +149,9 @@ export const jlcPartsEngine: PartsEngine = {
127
149
  package: jlcpcbPackage,
128
150
  })
129
151
  return {
130
- jlcpcb: (power_sources ?? []).map((p: any) => `C${p.lcsc}`).slice(0, 3),
152
+ jlcpcb: withBasicPartPreference(power_sources)
153
+ .map((p: any) => `C${p.lcsc}`)
154
+ .slice(0, 3),
131
155
  }
132
156
  } else if (
133
157
  sourceComponent.type === "source_component" &&
@@ -138,7 +162,9 @@ export const jlcPartsEngine: PartsEngine = {
138
162
  package: jlcpcbPackage,
139
163
  })
140
164
  return {
141
- jlcpcb: (inductors ?? []).map((i: any) => `C${i.lcsc}`).slice(0, 3),
165
+ jlcpcb: withBasicPartPreference(inductors)
166
+ .map((i: any) => `C${i.lcsc}`)
167
+ .slice(0, 3),
142
168
  }
143
169
  } else if (
144
170
  sourceComponent.type === "source_component" &&
@@ -150,7 +176,9 @@ export const jlcPartsEngine: PartsEngine = {
150
176
  package: jlcpcbPackage,
151
177
  })
152
178
  return {
153
- jlcpcb: (crystals ?? []).map((c: any) => `C${c.lcsc}`).slice(0, 3),
179
+ jlcpcb: withBasicPartPreference(crystals)
180
+ .map((c: any) => `C${c.lcsc}`)
181
+ .slice(0, 3),
154
182
  }
155
183
  } else if (
156
184
  sourceComponent.type === "source_component" &&
@@ -162,7 +190,9 @@ export const jlcPartsEngine: PartsEngine = {
162
190
  channel_type: sourceComponent.channel_type,
163
191
  })
164
192
  return {
165
- jlcpcb: (mosfets ?? []).map((m: any) => `C${m.lcsc}`).slice(0, 3),
193
+ jlcpcb: withBasicPartPreference(mosfets)
194
+ .map((m: any) => `C${m.lcsc}`)
195
+ .slice(0, 3),
166
196
  }
167
197
  } else if (
168
198
  sourceComponent.type === "source_component" &&
@@ -173,7 +203,9 @@ export const jlcPartsEngine: PartsEngine = {
173
203
  package: jlcpcbPackage,
174
204
  })
175
205
  return {
176
- jlcpcb: (resonators ?? []).map((r: any) => `C${r.lcsc}`).slice(0, 3),
206
+ jlcpcb: withBasicPartPreference(resonators)
207
+ .map((r: any) => `C${r.lcsc}`)
208
+ .slice(0, 3),
177
209
  }
178
210
  } else if (
179
211
  sourceComponent.type === "source_component" &&
@@ -184,7 +216,9 @@ export const jlcPartsEngine: PartsEngine = {
184
216
  package: jlcpcbPackage,
185
217
  })
186
218
  return {
187
- jlcpcb: (switches ?? []).map((s: any) => `C${s.lcsc}`).slice(0, 3),
219
+ jlcpcb: withBasicPartPreference(switches)
220
+ .map((s: any) => `C${s.lcsc}`)
221
+ .slice(0, 3),
188
222
  }
189
223
  } else if (
190
224
  sourceComponent.type === "source_component" &&
@@ -194,7 +228,9 @@ export const jlcPartsEngine: PartsEngine = {
194
228
  package: jlcpcbPackage,
195
229
  })
196
230
  return {
197
- jlcpcb: (leds ?? []).map((l: any) => `C${l.lcsc}`).slice(0, 3),
231
+ jlcpcb: withBasicPartPreference(leds)
232
+ .map((l: any) => `C${l.lcsc}`)
233
+ .slice(0, 3),
198
234
  }
199
235
  } else if (
200
236
  sourceComponent.type === "source_component" &&
@@ -204,7 +240,9 @@ export const jlcPartsEngine: PartsEngine = {
204
240
  package: jlcpcbPackage,
205
241
  })
206
242
  return {
207
- jlcpcb: (fuses ?? []).map((l: any) => `C${l.lcsc}`).slice(0, 3),
243
+ jlcpcb: withBasicPartPreference(fuses)
244
+ .map((l: any) => `C${l.lcsc}`)
245
+ .slice(0, 3),
208
246
  }
209
247
  }
210
248
  return {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/parts-engine",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "devDependencies": {
@@ -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
  })