@tscircuit/parts-engine 0.0.1 → 0.0.3

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/bun.lock CHANGED
@@ -5,9 +5,9 @@
5
5
  "name": "@tscircuit/parts-engine",
6
6
  "devDependencies": {
7
7
  "@biomejs/biome": "^1.9.4",
8
- "@tscircuit/props": "^0.0.172",
8
+ "@tscircuit/props": "^0.0.227",
9
9
  "@types/bun": "latest",
10
- "circuit-json": "^0.0.159",
10
+ "circuit-json": "^0.0.209",
11
11
  "tsup": "^8.4.0",
12
12
  },
13
13
  "peerDependencies": {
@@ -142,7 +142,7 @@
142
142
 
143
143
  "@tscircuit/manual-edit-events": ["@tscircuit/manual-edit-events@0.0.6", "", { "dependencies": { "zod": "^3.23.8" } }, "sha512-PLgy+/Dsw1YcnNVNqfieNGTNIaRKRJ70Jt2LcSMljwaBOtsiOwtdzj24xCYO9XzJUZc7opKytShMlx863PehTQ=="],
144
144
 
145
- "@tscircuit/props": ["@tscircuit/props@0.0.172", "", { "peerDependencies": { "@tscircuit/layout": "*", "circuit-json": "*", "react": "*", "zod": "*" } }, "sha512-RKC8g5kBy8+XnT7gjvhXPYR9hogEQJ9Nh0MMRAC3rMyqO3kBCuB2UZduEUwvREyoo42mwN2qlyydDlnIu41Ztg=="],
145
+ "@tscircuit/props": ["@tscircuit/props@0.0.227", "", { "peerDependencies": { "@tscircuit/layout": "*", "circuit-json": "*", "react": "*", "zod": "*" } }, "sha512-vJMZ2vHPX3nhfYCwCoijp/r+w1SLM3zocVSdofr6VQpV4Ct8JrLJUJ+h3AhKPttD8kunZ66jbWMlC9wA+U7iNQ=="],
146
146
 
147
147
  "@tscircuit/schematic-autolayout": ["@tscircuit/schematic-autolayout@0.0.6", "", { "dependencies": { "@tscircuit/soup-util": "^0.0.38", "transformation-matrix": "^2.16.1" } }, "sha512-34cQxtlSylBKyHkzaMBCynaWJgN9c/mWm7cz63StTYIafKmfFs383K8Xoc4QX8HXCvVrHYl1aK15onZua9MxeA=="],
148
148
 
@@ -172,7 +172,7 @@
172
172
 
173
173
  "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
174
174
 
175
- "circuit-json": ["circuit-json@0.0.159", "", { "dependencies": { "nanoid": "^5.0.7", "zod": "^3.23.6" } }, "sha512-NW2xGkLGhjCas6EMvbSjnpak9GV9+axJZnTh6fdu4UHVj97EMMtZOZs9/n4AEyjKexZ9SOknQiW7fTaUkvdnGA=="],
175
+ "circuit-json": ["circuit-json@0.0.209", "", { "dependencies": { "nanoid": "^5.0.7", "zod": "^3.25.64" } }, "sha512-cu/LQQS7XPGgAfDvwbusQqJbPyMdYRkKN4jMvi837TuCSXa0Xt7cBvSqkQekyipXuAtqnLJiaAucFVHpMUNyWA=="],
176
176
 
177
177
  "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
178
178
 
@@ -306,7 +306,11 @@
306
306
 
307
307
  "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
308
308
 
309
- "zod": ["zod@3.24.3", "", {}, "sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg=="],
309
+ "zod": ["zod@3.25.64", "", {}, "sha512-hbP9FpSZf7pkS7hRVUrOjhwKJNyampPgtXKc3AN6DsWtoHsg2Sb4SQaS4Tcay380zSwd2VPo9G9180emBACp5g=="],
310
+
311
+ "@tscircuit/layout/zod": ["zod@3.24.3", "", {}, "sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg=="],
312
+
313
+ "@tscircuit/manual-edit-events/zod": ["zod@3.24.3", "", {}, "sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg=="],
310
314
 
311
315
  "@tscircuit/schematic-autolayout/@tscircuit/soup-util": ["@tscircuit/soup-util@0.0.38", "", { "dependencies": { "parsel-js": "^1.1.2" }, "peerDependencies": { "circuit-json": "*", "transformation-matrix": "*", "zod": "*" } }, "sha512-GdcuFxk+qnJZv+eI7ZoJ1MJEseFgRyaztMtQ/OXA2SUnxyPEH0UTy9vkhKTm+8GTePryEgdXcc65TgUyrr44ww=="],
312
316
 
@@ -54,9 +54,9 @@ export const jlcPartsEngine: PartsEngine = {
54
54
  sourceComponent.type === "source_component" &&
55
55
  sourceComponent.ftype === "simple_pin_header"
56
56
  ) {
57
- let pitch
57
+ let pitch: number | undefined
58
58
  if (footprinterString?.includes("_p")) {
59
- pitch = footprinterString.split("_p")[1]
59
+ pitch = Number(footprinterString.split("_p")[1])
60
60
  }
61
61
  const { headers } = await getJlcPartsCached(
62
62
  "headers",
@@ -74,6 +74,127 @@ export const jlcPartsEngine: PartsEngine = {
74
74
  return {
75
75
  jlcpcb: headers.map((h: any) => `C${h.lcsc}`).slice(0, 3),
76
76
  }
77
+ } else if (
78
+ sourceComponent.type === "source_component" &&
79
+ sourceComponent.ftype === "simple_potentiometer"
80
+ ) {
81
+ const { potentiometers } = await getJlcPartsCached("potentiometers", {
82
+ resistance: sourceComponent.max_resistance,
83
+ package: footprinterString,
84
+ })
85
+ return {
86
+ jlcpcb: potentiometers.map((p: any) => `C${p.lcsc}`).slice(0, 3),
87
+ }
88
+ } else if (
89
+ sourceComponent.type === "source_component" &&
90
+ sourceComponent.ftype === "simple_diode"
91
+ ) {
92
+ const { diodes } = await getJlcPartsCached("diodes", {
93
+ package: footprinterString,
94
+ })
95
+ return {
96
+ jlcpcb: diodes.map((d: any) => `C${d.lcsc}`).slice(0, 3),
97
+ }
98
+ } else if (
99
+ sourceComponent.type === "source_component" &&
100
+ sourceComponent.ftype === "simple_chip"
101
+ ) {
102
+ const { chips } = await getJlcPartsCached("chips", {
103
+ package: footprinterString,
104
+ })
105
+ return {
106
+ jlcpcb: chips.map((c: any) => `C${c.lcsc}`).slice(0, 3),
107
+ }
108
+ } else if (
109
+ sourceComponent.type === "source_component" &&
110
+ sourceComponent.ftype === "simple_transistor"
111
+ ) {
112
+ const { transistors } = await getJlcPartsCached("transistors", {
113
+ package: footprinterString,
114
+ transistor_type: sourceComponent.transistor_type,
115
+ })
116
+ return {
117
+ jlcpcb: transistors.map((t: any) => `C${t.lcsc}`).slice(0, 3),
118
+ }
119
+ } else if (
120
+ sourceComponent.type === "source_component" &&
121
+ sourceComponent.ftype === "simple_power_source"
122
+ ) {
123
+ const { power_sources } = await getJlcPartsCached("power_sources", {
124
+ voltage: sourceComponent.voltage,
125
+ package: footprinterString,
126
+ })
127
+ return {
128
+ jlcpcb: power_sources.map((p: any) => `C${p.lcsc}`).slice(0, 3),
129
+ }
130
+ } else if (
131
+ sourceComponent.type === "source_component" &&
132
+ sourceComponent.ftype === "simple_inductor"
133
+ ) {
134
+ const { inductors } = await getJlcPartsCached("inductors", {
135
+ inductance: sourceComponent.inductance,
136
+ package: footprinterString,
137
+ })
138
+ return {
139
+ jlcpcb: inductors.map((i: any) => `C${i.lcsc}`).slice(0, 3),
140
+ }
141
+ } else if (
142
+ sourceComponent.type === "source_component" &&
143
+ sourceComponent.ftype === "simple_crystal"
144
+ ) {
145
+ const { crystals } = await getJlcPartsCached("crystals", {
146
+ frequency: sourceComponent.frequency,
147
+ load_capacitance: sourceComponent.load_capacitance,
148
+ package: footprinterString,
149
+ })
150
+ return {
151
+ jlcpcb: crystals.map((c: any) => `C${c.lcsc}`).slice(0, 3),
152
+ }
153
+ } else if (
154
+ sourceComponent.type === "source_component" &&
155
+ sourceComponent.ftype === "simple_mosfet"
156
+ ) {
157
+ const { mosfets } = await getJlcPartsCached("mosfets", {
158
+ package: footprinterString,
159
+ mosfet_mode: sourceComponent.mosfet_mode,
160
+ channel_type: sourceComponent.channel_type,
161
+ })
162
+ return {
163
+ jlcpcb: mosfets.map((m: any) => `C${m.lcsc}`).slice(0, 3),
164
+ }
165
+ } else if (
166
+ sourceComponent.type === "source_component" &&
167
+ sourceComponent.ftype === "simple_resonator"
168
+ ) {
169
+ const { resonators } = await getJlcPartsCached("resonators", {
170
+ frequency: sourceComponent.frequency,
171
+ package: footprinterString,
172
+ })
173
+ return {
174
+ jlcpcb: resonators.map((r: any) => `C${r.lcsc}`).slice(0, 3),
175
+ }
176
+ } else if (
177
+ sourceComponent.type === "source_component" &&
178
+ sourceComponent.ftype === "simple_switch"
179
+ ) {
180
+ const { switches } = await getJlcPartsCached("switches", {
181
+ switch_type: sourceComponent.type,
182
+ package: footprinterString,
183
+ })
184
+ return {
185
+ jlcpcb: switches.map((s: any) => `C${s.lcsc}`).slice(0, 3),
186
+ }
187
+ }
188
+ else if (
189
+ sourceComponent.type === "source_component" &&
190
+ sourceComponent.ftype === "simple_led"
191
+ ) {
192
+ const { leds } = await getJlcPartsCached("leds", {
193
+ package: footprinterString,
194
+ })
195
+ return {
196
+ jlcpcb: leds.map((l: any) => `C${l.lcsc}`).slice(0, 3),
197
+ }
77
198
  }
78
199
  return {}
79
200
  },
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@tscircuit/parts-engine",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "devDependencies": {
7
7
  "@biomejs/biome": "^1.9.4",
8
- "@tscircuit/props": "^0.0.172",
8
+ "@tscircuit/props": "^0.0.227",
9
9
  "@types/bun": "latest",
10
- "circuit-json": "^0.0.159",
10
+ "circuit-json": "^0.0.209",
11
11
  "tsup": "^8.4.0"
12
12
  },
13
13
  "scripts": {
@@ -19,6 +19,13 @@ describe("jlcPartsEngine", () => {
19
19
  }),
20
20
  } as Response
21
21
  }
22
+ if (url.includes("/potentiometers/")) {
23
+ return {
24
+ json: async () => ({
25
+ potentiometers: [{ lcsc: "1234" }, { lcsc: "5678" }, { lcsc: "9012" }],
26
+ }),
27
+ } as Response
28
+ }
22
29
  if (url.includes("/headers/")) {
23
30
  return {
24
31
  json: async () => ({
@@ -26,6 +33,69 @@ describe("jlcPartsEngine", () => {
26
33
  }),
27
34
  } as Response
28
35
  }
36
+ if (url.includes("/diodes/")) {
37
+ return {
38
+ json: async () => ({
39
+ diodes: [{ lcsc: "4567" }, { lcsc: "8901" }, { lcsc: "2345" }],
40
+ }),
41
+ } as Response
42
+ }
43
+ if (url.includes("/chips/")) {
44
+ return {
45
+ json: async () => ({
46
+ chips: [{ lcsc: "5678" }, { lcsc: "9012" }, { lcsc: "3456" }],
47
+ }),
48
+ } as Response
49
+ }
50
+ if (url.includes("/transistors/")) {
51
+ return {
52
+ json: async () => ({
53
+ transistors: [{ lcsc: "6789" }, { lcsc: "0123" }, { lcsc: "4567" }],
54
+ }),
55
+ } as Response
56
+ }
57
+ if (url.includes("/power_sources/")) {
58
+ return {
59
+ json: async () => ({
60
+ power_sources: [{ lcsc: "7890" }, { lcsc: "1234" }, { lcsc: "5678" }],
61
+ }),
62
+ } as Response
63
+ }
64
+ if (url.includes("/inductors/")) {
65
+ return {
66
+ json: async () => ({
67
+ inductors: [{ lcsc: "8901" }, { lcsc: "2345" }, { lcsc: "6789" }],
68
+ }),
69
+ } as Response
70
+ }
71
+ if (url.includes("/crystals/")) {
72
+ return {
73
+ json: async () => ({
74
+ crystals: [{ lcsc: "9012" }, { lcsc: "3456" }, { lcsc: "7890" }],
75
+ }),
76
+ } as Response
77
+ }
78
+ if (url.includes("/mosfets/")) {
79
+ return {
80
+ json: async () => ({
81
+ mosfets: [{ lcsc: "0123" }, { lcsc: "4567" }, { lcsc: "8901" }],
82
+ }),
83
+ } as Response
84
+ }
85
+ if (url.includes("/resonators/")) {
86
+ return {
87
+ json: async () => ({
88
+ resonators: [{ lcsc: "1234" }, { lcsc: "5678" }, { lcsc: "9012" }],
89
+ }),
90
+ } as Response
91
+ }
92
+ if (url.includes("/switches/")) {
93
+ return {
94
+ json: async () => ({
95
+ switches: [{ lcsc: "2345" }, { lcsc: "6789" }, { lcsc: "0123" }],
96
+ }),
97
+ } as Response
98
+ }
29
99
  return {} as Response
30
100
  }) as unknown as typeof fetch
31
101
  })
@@ -88,6 +158,197 @@ describe("jlcPartsEngine", () => {
88
158
  })
89
159
  })
90
160
 
161
+ // potentiometers
162
+ test("should find potentiometers", async () => {
163
+ const potentiometer: AnySourceComponent = {
164
+ type: "source_component",
165
+ ftype: "simple_potentiometer",
166
+ source_component_id: "source_component_0",
167
+ name: "P1",
168
+ max_resistance: 10000,
169
+ }
170
+
171
+ const result = await jlcPartsEngine.findPart({
172
+ sourceComponent: potentiometer,
173
+ footprinterString: "10k",
174
+ })
175
+
176
+ expect(result).toEqual({
177
+ jlcpcb: ["C1234", "C5678", "C9012"],
178
+ })
179
+ })
180
+
181
+ test("should find diode parts", async () => {
182
+ const diode: AnySourceComponent = {
183
+ type: "source_component",
184
+ ftype: "simple_diode",
185
+ source_component_id: "source_component_0",
186
+ name: "D1",
187
+ }
188
+
189
+ const result = await jlcPartsEngine.findPart({
190
+ sourceComponent: diode,
191
+ footprinterString: "SOD-123",
192
+ })
193
+
194
+ expect(result).toEqual({
195
+ jlcpcb: ["C4567", "C8901", "C2345"],
196
+ })
197
+ })
198
+
199
+ test("should find chip parts", async () => {
200
+ const chip: AnySourceComponent = {
201
+ type: "source_component",
202
+ ftype: "simple_chip",
203
+ source_component_id: "source_component_0",
204
+ name: "U1",
205
+ }
206
+
207
+ const result = await jlcPartsEngine.findPart({
208
+ sourceComponent: chip,
209
+ footprinterString: "SOIC-8",
210
+ })
211
+
212
+ expect(result).toEqual({
213
+ jlcpcb: ["C5678", "C9012", "C3456"],
214
+ })
215
+ })
216
+
217
+ test("should find transistor parts", async () => {
218
+ const transistor: AnySourceComponent = {
219
+ type: "source_component",
220
+ ftype: "simple_transistor",
221
+ transistor_type: "npn",
222
+ source_component_id: "source_component_0",
223
+ name: "Q1",
224
+ }
225
+
226
+ const result = await jlcPartsEngine.findPart({
227
+ sourceComponent: transistor,
228
+ footprinterString: "SOT-23",
229
+ })
230
+
231
+ expect(result).toEqual({
232
+ jlcpcb: ["C6789", "C0123", "C4567"],
233
+ })
234
+ })
235
+
236
+ test("should find power source parts", async () => {
237
+ const powerSource: AnySourceComponent = {
238
+ type: "source_component",
239
+ ftype: "simple_power_source",
240
+ voltage: 5,
241
+ source_component_id: "source_component_0",
242
+ name: "V1",
243
+ }
244
+
245
+ const result = await jlcPartsEngine.findPart({
246
+ sourceComponent: powerSource,
247
+ footprinterString: "SOT-223",
248
+ })
249
+
250
+ expect(result).toEqual({
251
+ jlcpcb: ["C7890", "C1234", "C5678"],
252
+ })
253
+ })
254
+
255
+ test("should find inductor parts", async () => {
256
+ const inductor: AnySourceComponent = {
257
+ type: "source_component",
258
+ ftype: "simple_inductor",
259
+ inductance: 100,
260
+ source_component_id: "source_component_0",
261
+ name: "L1",
262
+ }
263
+
264
+ const result = await jlcPartsEngine.findPart({
265
+ sourceComponent: inductor,
266
+ footprinterString: "0603",
267
+ })
268
+
269
+ expect(result).toEqual({
270
+ jlcpcb: ["C8901", "C2345", "C6789"],
271
+ })
272
+ })
273
+
274
+ test("should find crystal parts", async () => {
275
+ const crystal: AnySourceComponent = {
276
+ type: "source_component",
277
+ ftype: "simple_crystal",
278
+ frequency: 16000000,
279
+ load_capacitance: 20,
280
+ source_component_id: "source_component_0",
281
+ name: "X1",
282
+ }
283
+
284
+ const result = await jlcPartsEngine.findPart({
285
+ sourceComponent: crystal,
286
+ footprinterString: "HC-49S",
287
+ })
288
+
289
+ expect(result).toEqual({
290
+ jlcpcb: ["C9012", "C3456", "C7890"],
291
+ })
292
+ })
293
+
294
+ test("should find MOSFET parts", async () => {
295
+ const mosfet: AnySourceComponent = {
296
+ type: "source_component",
297
+ ftype: "simple_mosfet",
298
+ mosfet_mode: "enhancement",
299
+ channel_type: "n",
300
+ source_component_id: "source_component_0",
301
+ name: "M1",
302
+ }
303
+
304
+ const result = await jlcPartsEngine.findPart({
305
+ sourceComponent: mosfet,
306
+ footprinterString: "SOT-23",
307
+ })
308
+
309
+ expect(result).toEqual({
310
+ jlcpcb: ["C0123", "C4567", "C8901"],
311
+ })
312
+ })
313
+
314
+ test("should find resonator parts", async () => {
315
+ const resonator: AnySourceComponent = {
316
+ type: "source_component",
317
+ ftype: "simple_resonator",
318
+ frequency: 16000000,
319
+ load_capacitance: 20,
320
+ source_component_id: "source_component_0",
321
+ name: "Y1",
322
+ }
323
+
324
+ const result = await jlcPartsEngine.findPart({
325
+ sourceComponent: resonator,
326
+ footprinterString: "SMD",
327
+ })
328
+
329
+ expect(result).toEqual({
330
+ jlcpcb: ["C1234", "C5678", "C9012"],
331
+ })
332
+ })
333
+
334
+ test("should find switch parts", async () => {
335
+ const switch_: AnySourceComponent = {
336
+ type: "source_component",
337
+ ftype: "simple_switch",
338
+ source_component_id: "source_component_0",
339
+ name: "SW1",
340
+ }
341
+
342
+ const result = await jlcPartsEngine.findPart({
343
+ sourceComponent: switch_,
344
+ footprinterString: "SMD",
345
+ })
346
+
347
+ expect(result).toEqual({
348
+ jlcpcb: ["C2345", "C6789", "C0123"],
349
+ })
350
+ })
351
+
91
352
  test("should return empty object for unknown component types", async () => {
92
353
  const unknown: AnySourceComponent = {
93
354
  type: "source_component",