@tscircuit/parts-engine 0.0.12 → 0.0.14

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,17 @@
1
1
  {
2
2
  "lockfileVersion": 1,
3
+ "configVersion": 0,
3
4
  "workspaces": {
4
5
  "": {
5
6
  "name": "@tscircuit/parts-engine",
7
+ "dependencies": {
8
+ "easyeda": "^0.0.253",
9
+ },
6
10
  "devDependencies": {
7
11
  "@biomejs/biome": "^1.9.4",
8
- "@tscircuit/props": "^0.0.238",
12
+ "@tscircuit/props": "^0.0.500",
9
13
  "@types/bun": "latest",
10
- "circuit-json": "^0.0.213",
14
+ "circuit-json": "^0.0.406",
11
15
  "tsup": "^8.4.0",
12
16
  },
13
17
  "peerDependencies": {
@@ -138,15 +142,7 @@
138
142
 
139
143
  "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.40.0", "", { "os": "win32", "cpu": "x64" }, "sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ=="],
140
144
 
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=="],
145
+ "@tscircuit/props": ["@tscircuit/props@0.0.500", "", { "peerDependencies": { "circuit-json": "*", "react": "*", "zod": "*" } }, "sha512-WHQfU9mrHTOwOA/qA1nMQKzU1+umWIcEppjoAOE/k+nV11izq6n8CemQZgdzen0mqnfmVn2eX9APAkwiTTApdg=="],
150
146
 
151
147
  "@types/bun": ["@types/bun@1.2.10", "", { "dependencies": { "bun-types": "1.2.10" } }, "sha512-eilv6WFM3M0c9ztJt7/g80BDusK98z/FrFwseZgT4bXCq2vPhXD4z8R3oddmAn+R/Nmz9vBn4kweJKmGTZj+lg=="],
152
148
 
@@ -172,7 +168,7 @@
172
168
 
173
169
  "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
174
170
 
175
- "circuit-json": ["circuit-json@0.0.213", "", { "dependencies": { "nanoid": "^5.0.7", "zod": "*" } }, "sha512-WgKoSYyvhI+anWo1EzTBEgNQSyh68zgpW+7X3SPmpQwIkybB01j23uKp+SQPZ0U6iHRE5p84TuixWN0K6vApPQ=="],
171
+ "circuit-json": ["circuit-json@0.0.406", "", {}, "sha512-V9Ob7LJWQu++Sgy7e0/vVeIe5Gu7oeV0kDRPYeh6lSH9c5T80NrU8+AQiEmny1+E/f+fMzRMarN1BIPjumB5PQ=="],
176
172
 
177
173
  "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
178
174
 
@@ -188,6 +184,8 @@
188
184
 
189
185
  "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
190
186
 
187
+ "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=="],
188
+
191
189
  "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
192
190
 
193
191
  "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 +224,10 @@
226
224
 
227
225
  "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
226
 
229
- "nanoid": ["nanoid@5.1.5", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw=="],
230
-
231
227
  "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
232
228
 
233
229
  "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="],
234
230
 
235
- "parsel-js": ["parsel-js@1.2.1", "", {}, "sha512-omFBig09mUh/NjBGba4DxVFAsqCY4C/6UYIaJuDOxJw2GlpgUJdPlNF301971gCP3Gt727+F+NZIXN483VAKIg=="],
236
-
237
231
  "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
238
232
 
239
233
  "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 +278,6 @@
284
278
 
285
279
  "tr46": ["tr46@1.0.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA=="],
286
280
 
287
- "transformation-matrix": ["transformation-matrix@2.16.1", "", {}, "sha512-tdtC3wxVEuzU7X/ydL131Q3JU5cPMEn37oqVLITjRDSDsnSHVFzW2JiCLfZLIQEgWzZHdSy3J6bZzvKEN24jGA=="],
288
-
289
281
  "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="],
290
282
 
291
283
  "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="],
@@ -308,12 +300,6 @@
308
300
 
309
301
  "zod": ["zod@3.25.64", "", {}, "sha512-hbP9FpSZf7pkS7hRVUrOjhwKJNyampPgtXKc3AN6DsWtoHsg2Sb4SQaS4Tcay380zSwd2VPo9G9180emBACp5g=="],
310
302
 
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
303
  "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
318
304
 
319
305
  "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,16 @@
1
1
  {
2
2
  "name": "@tscircuit/parts-engine",
3
- "version": "0.0.12",
3
+ "version": "0.0.14",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
+ "dependencies": {
7
+ "easyeda": "^0.0.253"
8
+ },
6
9
  "devDependencies": {
7
10
  "@biomejs/biome": "^1.9.4",
8
- "@tscircuit/props": "^0.0.238",
11
+ "@tscircuit/props": "^0.0.500",
9
12
  "@types/bun": "latest",
10
- "circuit-json": "^0.0.213",
13
+ "circuit-json": "^0.0.406",
11
14
  "tsup": "^8.4.0"
12
15
  },
13
16
  "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",