@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.
@@ -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,7 +108,9 @@ 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" &&
@@ -105,7 +120,9 @@ export const jlcPartsEngine: PartsEngine = {
105
120
  package: jlcpcbPackage,
106
121
  })
107
122
  return {
108
- jlcpcb: (chips ?? []).map((c: any) => `C${c.lcsc}`).slice(0, 3),
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 ?? []).map((t: any) => `C${t.lcsc}`).slice(0, 3),
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 ?? []).map((p: any) => `C${p.lcsc}`).slice(0, 3),
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 ?? []).map((i: any) => `C${i.lcsc}`).slice(0, 3),
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 ?? []).map((c: any) => `C${c.lcsc}`).slice(0, 3),
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 ?? []).map((m: any) => `C${m.lcsc}`).slice(0, 3),
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 ?? []).map((r: any) => `C${r.lcsc}`).slice(0, 3),
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 ?? []).map((s: any) => `C${s.lcsc}`).slice(0, 3),
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 ?? []).map((l: any) => `C${l.lcsc}`).slice(0, 3),
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 ?? []).map((l: any) => `C${l.lcsc}`).slice(0, 3),
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/parts-engine",
3
- "version": "0.0.10",
3
+ "version": "0.0.11",
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
  })