@tscircuit/core 0.0.50 → 0.0.52

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/dist/index.d.ts CHANGED
@@ -78,7 +78,7 @@ declare abstract class Renderable implements IRenderable {
78
78
  */
79
79
  runRenderPhase(phase: RenderPhase): void;
80
80
  runRenderPhaseForChildren(phase: RenderPhase): void;
81
- renderError(message: string | PCBTraceError | PCBPlacementError): void;
81
+ renderError(message: string | Omit<PCBTraceError, "pcb_error_id"> | Omit<PCBPlacementError, "pcb_error_id">): void;
82
82
  }
83
83
 
84
84
  interface BaseComponentConfig {
@@ -229,6 +229,7 @@ declare abstract class PrimitiveComponent<ZodProps extends ZodType = any> extend
229
229
  }): PrimitiveComponent | null;
230
230
  getAvailablePcbLayers(): string[];
231
231
  getDescendants(): PrimitiveComponent[];
232
+ renderError(message: Parameters<typeof Renderable.prototype.renderError>[0]): void;
232
233
  getString(): string;
233
234
  get [Symbol.toStringTag](): string;
234
235
  }
package/dist/index.js CHANGED
@@ -125,6 +125,7 @@ var Renderable = class {
125
125
  if (typeof message === "string") {
126
126
  throw new Error(message);
127
127
  }
128
+ throw new Error(JSON.stringify(message, null, 2));
128
129
  }
129
130
  };
130
131
 
@@ -487,6 +488,15 @@ var PrimitiveComponent = class extends Renderable {
487
488
  }
488
489
  return descendants;
489
490
  }
491
+ // TODO we shouldn't need to override this, errors can be rendered and handled
492
+ // by the Renderable class, however, the Renderable class currently doesn't
493
+ // have access to the database or cleanup
494
+ renderError(message) {
495
+ if (typeof message === "string") {
496
+ return super.renderError(message);
497
+ }
498
+ this.root?.db.pcb_error.insert(message);
499
+ }
490
500
  getString() {
491
501
  const { lowercaseComponentName: cname, _parsedProps: props, parent } = this;
492
502
  if (parent?.props?.name && props?.name) {
@@ -2213,6 +2223,17 @@ function getClosest(point, candidates) {
2213
2223
 
2214
2224
  // lib/components/primitive-components/Trace.ts
2215
2225
  import "zod";
2226
+
2227
+ // lib/utils/try-now.ts
2228
+ function tryNow(fn) {
2229
+ try {
2230
+ return [fn(), null];
2231
+ } catch (e) {
2232
+ return [null, e];
2233
+ }
2234
+ }
2235
+
2236
+ // lib/components/primitive-components/Trace.ts
2216
2237
  var portToObjective = (port) => {
2217
2238
  const portPosition = port._getGlobalPcbPositionAfterLayout();
2218
2239
  return {
@@ -2390,10 +2411,6 @@ searched component ${targetComponent.getString()}, which has ports: ${targetComp
2390
2411
  );
2391
2412
  return;
2392
2413
  }
2393
- const pcbElements = db.toArray().filter(
2394
- (elm) => elm.type === "pcb_smtpad" || elm.type === "pcb_trace" || elm.type === "pcb_plated_hole" || elm.type === "pcb_hole" || elm.type === "source_port" || elm.type === "pcb_port" || elm.type === "source_trace" || elm.type === "pcb_keepout"
2395
- );
2396
- const source_trace = db.source_trace.get(this.source_trace_id);
2397
2414
  const hints = ports.flatMap(
2398
2415
  (port) => port.matchedComponents.filter((c) => c.componentName === "TraceHint")
2399
2416
  );
@@ -2441,7 +2458,22 @@ searched component ${targetComponent.getString()}, which has ports: ${targetComp
2441
2458
  );
2442
2459
  return;
2443
2460
  }
2444
- const obstacles = getObstaclesFromSoup(this.root.db.toArray());
2461
+ const [obstacles, err] = tryNow(
2462
+ () => getObstaclesFromSoup(this.root.db.toArray())
2463
+ );
2464
+ if (err) {
2465
+ this.renderError({
2466
+ type: "pcb_error",
2467
+ error_type: "pcb_trace_error",
2468
+ message: `Error getting obstacles for autorouting: ${err.message}`,
2469
+ source_trace_id: this.source_trace_id,
2470
+ center: { x: 0, y: 0 },
2471
+ pcb_port_ids: ports.map((p) => p.pcb_port_id),
2472
+ pcb_trace_id: this.pcb_trace_id,
2473
+ pcb_component_ids: []
2474
+ });
2475
+ return;
2476
+ }
2445
2477
  markObstaclesAsConnected(
2446
2478
  obstacles,
2447
2479
  orderedRouteObjectives,
@@ -2493,11 +2525,33 @@ searched component ${targetComponent.getString()}, which has ports: ${targetComp
2493
2525
  }
2494
2526
  }
2495
2527
  });
2496
- const traces = ijump.solveAndMapToTraces();
2528
+ let traces = null;
2529
+ try {
2530
+ traces = ijump.solveAndMapToTraces();
2531
+ } catch (e) {
2532
+ this.renderError({
2533
+ type: "pcb_error",
2534
+ error_type: "pcb_trace_error",
2535
+ message: `error solving route: ${e.message}`,
2536
+ source_trace_id: this.source_trace_id,
2537
+ center: { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 },
2538
+ pcb_port_ids: ports.map((p) => p.pcb_port_id),
2539
+ pcb_trace_id: this.pcb_trace_id,
2540
+ pcb_component_ids: ports.map((p) => p.pcb_component_id)
2541
+ });
2542
+ }
2543
+ if (!traces) return;
2497
2544
  if (traces.length === 0) {
2498
- this.renderError(
2499
- `Could not find a route between ${JSON.stringify(a)} and ${JSON.stringify(b)} for ${this}`
2500
- );
2545
+ this.renderError({
2546
+ type: "pcb_error",
2547
+ error_type: "pcb_trace_error",
2548
+ message: `Could not find a route for ${this}`,
2549
+ source_trace_id: this.source_trace_id,
2550
+ center: { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 },
2551
+ pcb_port_ids: ports.map((p) => p.pcb_port_id),
2552
+ pcb_trace_id: this.pcb_trace_id,
2553
+ pcb_component_ids: ports.map((p) => p.pcb_component_id)
2554
+ });
2501
2555
  return;
2502
2556
  }
2503
2557
  const [trace] = traces;
@@ -442,6 +442,17 @@ export abstract class PrimitiveComponent<
442
442
  return descendants
443
443
  }
444
444
 
445
+ // TODO we shouldn't need to override this, errors can be rendered and handled
446
+ // by the Renderable class, however, the Renderable class currently doesn't
447
+ // have access to the database or cleanup
448
+ renderError(message: Parameters<typeof Renderable.prototype.renderError>[0]) {
449
+ if (typeof message === "string") {
450
+ return super.renderError(message)
451
+ }
452
+ // TODO this needs to be cleaned up at some point!
453
+ this.root?.db.pcb_error.insert(message)
454
+ }
455
+
445
456
  getString(): string {
446
457
  const { lowercaseComponentName: cname, _parsedProps: props, parent } = this
447
458
  if (parent?.props?.name && props?.name) {
@@ -110,11 +110,17 @@ export abstract class Renderable implements IRenderable {
110
110
  }
111
111
  }
112
112
 
113
- renderError(message: string | PCBTraceError | PCBPlacementError) {
113
+ renderError(
114
+ message:
115
+ | string
116
+ | Omit<PCBTraceError, "pcb_error_id">
117
+ | Omit<PCBPlacementError, "pcb_error_id">,
118
+ ) {
114
119
  // TODO add to render phase error list and try to add position or
115
120
  // relationships etc.
116
121
  if (typeof message === "string") {
117
122
  throw new Error(message)
118
123
  }
124
+ throw new Error(JSON.stringify(message, null, 2))
119
125
  }
120
126
  }
@@ -19,6 +19,7 @@ import type {
19
19
  Obstacle,
20
20
  SimpleRouteConnection,
21
21
  SimpleRouteJson,
22
+ SimplifiedPcbTrace,
22
23
  } from "lib/utils/autorouting/SimpleRouteJson"
23
24
  import { computeObstacleBounds } from "lib/utils/autorouting/computeObstacleBounds"
24
25
  import { projectPointInDirection } from "lib/utils/projectPointInDirection"
@@ -37,6 +38,7 @@ import {
37
38
  isMatchingPathSelector,
38
39
  isMatchingSelector,
39
40
  } from "lib/utils/selector-matching"
41
+ import { tryNow } from "lib/utils/try-now"
40
42
 
41
43
  type PcbRouteObjective =
42
44
  | RouteHintPoint
@@ -285,22 +287,6 @@ export class Trace extends PrimitiveComponent<typeof traceProps> {
285
287
  return
286
288
  }
287
289
 
288
- const pcbElements: AnySoupElement[] = db
289
- .toArray()
290
- .filter(
291
- (elm) =>
292
- elm.type === "pcb_smtpad" ||
293
- elm.type === "pcb_trace" ||
294
- elm.type === "pcb_plated_hole" ||
295
- elm.type === "pcb_hole" ||
296
- elm.type === "source_port" ||
297
- elm.type === "pcb_port" ||
298
- elm.type === "source_trace" ||
299
- elm.type === "pcb_keepout",
300
- )
301
-
302
- const source_trace = db.source_trace.get(this.source_trace_id!)!
303
-
304
290
  const hints = ports.flatMap((port) =>
305
291
  port.matchedComponents.filter((c) => c.componentName === "TraceHint"),
306
292
  ) as TraceHint[]
@@ -372,7 +358,24 @@ export class Trace extends PrimitiveComponent<typeof traceProps> {
372
358
 
373
359
  // Cache the PCB obstacles, they'll be needed for each segment between
374
360
  // ports/hints
375
- const obstacles = getObstaclesFromSoup(this.root!.db.toArray())
361
+ const [obstacles, err] = tryNow(() =>
362
+ getObstaclesFromSoup(this.root!.db.toArray()),
363
+ )
364
+
365
+ if (err) {
366
+ this.renderError({
367
+ type: "pcb_error",
368
+ error_type: "pcb_trace_error",
369
+ message: `Error getting obstacles for autorouting: ${err.message}`,
370
+ source_trace_id: this.source_trace_id!,
371
+ center: { x: 0, y: 0 },
372
+ pcb_port_ids: ports.map((p) => p.pcb_port_id!),
373
+ pcb_trace_id: this.pcb_trace_id!,
374
+ pcb_component_ids: [],
375
+ })
376
+ return
377
+ }
378
+
376
379
  markObstaclesAsConnected(
377
380
  obstacles,
378
381
  orderedRouteObjectives,
@@ -437,11 +440,33 @@ export class Trace extends PrimitiveComponent<typeof traceProps> {
437
440
  },
438
441
  },
439
442
  })
440
- const traces = ijump.solveAndMapToTraces()
443
+ let traces: SimplifiedPcbTrace[] | null = null
444
+ try {
445
+ traces = ijump.solveAndMapToTraces()
446
+ } catch (e: any) {
447
+ this.renderError({
448
+ type: "pcb_error",
449
+ error_type: "pcb_trace_error",
450
+ message: `error solving route: ${e.message}`,
451
+ source_trace_id: this.source_trace_id!,
452
+ center: { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 },
453
+ pcb_port_ids: ports.map((p) => p.pcb_port_id!),
454
+ pcb_trace_id: this.pcb_trace_id!,
455
+ pcb_component_ids: ports.map((p) => p.pcb_component_id!),
456
+ })
457
+ }
458
+ if (!traces) return
441
459
  if (traces.length === 0) {
442
- this.renderError(
443
- `Could not find a route between ${JSON.stringify(a)} and ${JSON.stringify(b)} for ${this}`,
444
- )
460
+ this.renderError({
461
+ type: "pcb_error",
462
+ error_type: "pcb_trace_error",
463
+ message: `Could not find a route for ${this}`,
464
+ source_trace_id: this.source_trace_id!,
465
+ center: { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 },
466
+ pcb_port_ids: ports.map((p) => p.pcb_port_id!),
467
+ pcb_trace_id: this.pcb_trace_id!,
468
+ pcb_component_ids: ports.map((p) => p.pcb_component_id!),
469
+ })
445
470
  return
446
471
  }
447
472
  // TODO ijump returns multiple traces for some reason
@@ -0,0 +1,7 @@
1
+ export function tryNow<T>(fn: () => T): [T, null] | [null, Error] {
2
+ try {
3
+ return [fn(), null]
4
+ } catch (e: any) {
5
+ return [null, e]
6
+ }
7
+ }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@tscircuit/core",
3
3
  "module": "index.ts",
4
4
  "type": "module",
5
- "version": "0.0.50",
5
+ "version": "0.0.52",
6
6
  "types": "dist/index.d.ts",
7
7
  "main": "dist/index.js",
8
8
  "files": [
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@lume/kiwi": "^0.4.3",
37
- "@tscircuit/infgrid-ijump-astar": "^0.0.10",
37
+ "@tscircuit/infgrid-ijump-astar": "^0.0.11",
38
38
  "@tscircuit/props": "^0.0.62",
39
39
  "@tscircuit/soup": "^0.0.67",
40
40
  "@tscircuit/soup-util": "^0.0.23",