@tscircuit/parts-engine 0.0.12 → 0.0.13

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
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "lockfileVersion": 1,
3
+ "configVersion": 0,
3
4
  "workspaces": {
4
5
  "": {
5
6
  "name": "@tscircuit/parts-engine",
6
7
  "devDependencies": {
7
8
  "@biomejs/biome": "^1.9.4",
8
- "@tscircuit/props": "^0.0.238",
9
+ "@tscircuit/props": "^0.0.500",
9
10
  "@types/bun": "latest",
10
- "circuit-json": "^0.0.213",
11
+ "circuit-json": "^0.0.406",
12
+ "easyeda": "^0.0.253",
11
13
  "tsup": "^8.4.0",
12
14
  },
13
15
  "peerDependencies": {
@@ -138,15 +140,7 @@
138
140
 
139
141
  "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.40.0", "", { "os": "win32", "cpu": "x64" }, "sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ=="],
140
142
 
141
- "@tscircuit/layout": ["@tscircuit/layout@0.0.29", "", { "dependencies": { "@tscircuit/soup-util": "*", "transformation-matrix": "^2.16.1", "zod": "*" }, "peerDependencies": { "@tscircuit/manual-edit-events": "*", "@tscircuit/schematic-autolayout": "*", "circuit-json": "*" } }, "sha512-3V1SikE147UT/ag8/BRX5oBjYc6H0ZdV+7Et+ljp8fMyQy2P9EMbNKjS0yaXI1SSNgxfnEmDWqImw1JB0oWeXg=="],
142
-
143
- "@tscircuit/manual-edit-events": ["@tscircuit/manual-edit-events@0.0.6", "", { "dependencies": { "zod": "^3.23.8" } }, "sha512-PLgy+/Dsw1YcnNVNqfieNGTNIaRKRJ70Jt2LcSMljwaBOtsiOwtdzj24xCYO9XzJUZc7opKytShMlx863PehTQ=="],
144
-
145
- "@tscircuit/props": ["@tscircuit/props@0.0.238", "", { "peerDependencies": { "@tscircuit/layout": "*", "circuit-json": "*", "react": "*", "zod": "*" } }, "sha512-Mq9CScwlc/zd6wgTWGBKTN2x/qarImr1Um3dt0a/WY76pPIRdjnsznN+7IZVmNxY3H/RD6CbCNjgc0DKphWYIg=="],
146
-
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
-
149
- "@tscircuit/soup-util": ["@tscircuit/soup-util@0.0.41", "", { "dependencies": { "parsel-js": "^1.1.2" }, "peerDependencies": { "circuit-json": "*", "transformation-matrix": "*", "zod": "*" } }, "sha512-47JKWBUKkRVHhad0HhBbdOJxB6v/eiac46beiKRBMlJqiZ1gPGI276v9iZfpF7c4hXR69cURcgiwuA5vowrFEg=="],
143
+ "@tscircuit/props": ["@tscircuit/props@0.0.500", "", { "peerDependencies": { "circuit-json": "*", "react": "*", "zod": "*" } }, "sha512-WHQfU9mrHTOwOA/qA1nMQKzU1+umWIcEppjoAOE/k+nV11izq6n8CemQZgdzen0mqnfmVn2eX9APAkwiTTApdg=="],
150
144
 
151
145
  "@types/bun": ["@types/bun@1.2.10", "", { "dependencies": { "bun-types": "1.2.10" } }, "sha512-eilv6WFM3M0c9ztJt7/g80BDusK98z/FrFwseZgT4bXCq2vPhXD4z8R3oddmAn+R/Nmz9vBn4kweJKmGTZj+lg=="],
152
146
 
@@ -172,7 +166,7 @@
172
166
 
173
167
  "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
174
168
 
175
- "circuit-json": ["circuit-json@0.0.213", "", { "dependencies": { "nanoid": "^5.0.7", "zod": "*" } }, "sha512-WgKoSYyvhI+anWo1EzTBEgNQSyh68zgpW+7X3SPmpQwIkybB01j23uKp+SQPZ0U6iHRE5p84TuixWN0K6vApPQ=="],
169
+ "circuit-json": ["circuit-json@0.0.406", "", {}, "sha512-V9Ob7LJWQu++Sgy7e0/vVeIe5Gu7oeV0kDRPYeh6lSH9c5T80NrU8+AQiEmny1+E/f+fMzRMarN1BIPjumB5PQ=="],
176
170
 
177
171
  "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
178
172
 
@@ -188,6 +182,8 @@
188
182
 
189
183
  "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
190
184
 
185
+ "easyeda": ["easyeda@0.0.253", "", { "peerDependencies": { "typescript": "^5.5.2", "zod": "3" }, "bin": { "easyeda-converter": "dist/main.cjs", "easyeda": "dist/main.cjs" } }, "sha512-kB39WFoZxAmfQ3nETPj7yUq5PbPKUGEVtrVToAuKMQZimC2JJR61k6UsoK0QSk+q1R6RsfWj4v8tKHXXZ97UfQ=="],
186
+
191
187
  "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
192
188
 
193
189
  "esbuild": ["esbuild@0.25.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.3", "@esbuild/android-arm": "0.25.3", "@esbuild/android-arm64": "0.25.3", "@esbuild/android-x64": "0.25.3", "@esbuild/darwin-arm64": "0.25.3", "@esbuild/darwin-x64": "0.25.3", "@esbuild/freebsd-arm64": "0.25.3", "@esbuild/freebsd-x64": "0.25.3", "@esbuild/linux-arm": "0.25.3", "@esbuild/linux-arm64": "0.25.3", "@esbuild/linux-ia32": "0.25.3", "@esbuild/linux-loong64": "0.25.3", "@esbuild/linux-mips64el": "0.25.3", "@esbuild/linux-ppc64": "0.25.3", "@esbuild/linux-riscv64": "0.25.3", "@esbuild/linux-s390x": "0.25.3", "@esbuild/linux-x64": "0.25.3", "@esbuild/netbsd-arm64": "0.25.3", "@esbuild/netbsd-x64": "0.25.3", "@esbuild/openbsd-arm64": "0.25.3", "@esbuild/openbsd-x64": "0.25.3", "@esbuild/sunos-x64": "0.25.3", "@esbuild/win32-arm64": "0.25.3", "@esbuild/win32-ia32": "0.25.3", "@esbuild/win32-x64": "0.25.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q=="],
@@ -226,14 +222,10 @@
226
222
 
227
223
  "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="],
228
224
 
229
- "nanoid": ["nanoid@5.1.5", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw=="],
230
-
231
225
  "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
232
226
 
233
227
  "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="],
234
228
 
235
- "parsel-js": ["parsel-js@1.2.1", "", {}, "sha512-omFBig09mUh/NjBGba4DxVFAsqCY4C/6UYIaJuDOxJw2GlpgUJdPlNF301971gCP3Gt727+F+NZIXN483VAKIg=="],
236
-
237
229
  "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
238
230
 
239
231
  "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
@@ -284,8 +276,6 @@
284
276
 
285
277
  "tr46": ["tr46@1.0.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA=="],
286
278
 
287
- "transformation-matrix": ["transformation-matrix@2.16.1", "", {}, "sha512-tdtC3wxVEuzU7X/ydL131Q3JU5cPMEn37oqVLITjRDSDsnSHVFzW2JiCLfZLIQEgWzZHdSy3J6bZzvKEN24jGA=="],
288
-
289
279
  "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="],
290
280
 
291
281
  "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="],
@@ -308,12 +298,6 @@
308
298
 
309
299
  "zod": ["zod@3.25.64", "", {}, "sha512-hbP9FpSZf7pkS7hRVUrOjhwKJNyampPgtXKc3AN6DsWtoHsg2Sb4SQaS4Tcay380zSwd2VPo9G9180emBACp5g=="],
310
300
 
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=="],
314
-
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=="],
316
-
317
301
  "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
318
302
 
319
303
  "string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
@@ -1,5 +1,10 @@
1
1
  import type { PartsEngine, SupplierPartNumbers } from "@tscircuit/props"
2
2
  import { getJlcpcbPackageName } from "./footprint-translators/index"
3
+ import {
4
+ fetchEasyEDAComponent,
5
+ EasyEdaJsonSchema,
6
+ convertEasyEdaJsonToCircuitJson,
7
+ } from "easyeda"
3
8
 
4
9
  export const cache = new Map<string, any>()
5
10
 
@@ -244,7 +249,43 @@ export const jlcPartsEngine: PartsEngine = {
244
249
  .map((l: any) => `C${l.lcsc}`)
245
250
  .slice(0, 3),
246
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
+ }
247
266
  }
248
267
  return {}
249
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
+ },
250
291
  }
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@tscircuit/parts-engine",
3
- "version": "0.0.12",
3
+ "version": "0.0.13",
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.238",
8
+ "@tscircuit/props": "^0.0.500",
9
9
  "@types/bun": "latest",
10
- "circuit-json": "^0.0.213",
10
+ "circuit-json": "^0.0.406",
11
+ "easyeda": "^0.0.253",
11
12
  "tsup": "^8.4.0"
12
13
  },
13
14
  "scripts": {
@@ -0,0 +1,33 @@
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
+ }, 100000)
@@ -105,6 +105,17 @@ describe("jlcPartsEngine", () => {
105
105
  }),
106
106
  } as Response
107
107
  }
108
+ if (url.includes("/usb_c_connectors/")) {
109
+ return {
110
+ json: async () => ({
111
+ usb_c_connectors: [
112
+ { lcsc: "165948" },
113
+ { lcsc: "165949" },
114
+ { lcsc: "165950" },
115
+ ],
116
+ }),
117
+ } as Response
118
+ }
108
119
  return {} as Response
109
120
  }) as unknown as typeof fetch
110
121
  })
@@ -395,6 +406,24 @@ describe("jlcPartsEngine", () => {
395
406
  })
396
407
  })
397
408
 
409
+ test("should find usb_c connector parts", async () => {
410
+ const connector = {
411
+ type: "source_component",
412
+ ftype: "simple_connector",
413
+ standard: "usb_c",
414
+ source_component_id: "source_component_0",
415
+ name: "J1",
416
+ } as AnySourceComponent
417
+
418
+ const result = await jlcPartsEngine.findPart({
419
+ sourceComponent: connector,
420
+ })
421
+
422
+ expect(result).toEqual({
423
+ jlcpcb: ["C165948", "C165949", "C165950"],
424
+ })
425
+ })
426
+
398
427
  test("should return empty object for unknown component types", async () => {
399
428
  const unknown: AnySourceComponent = {
400
429
  type: "source_component",