@tscircuit/core 0.0.1140 → 0.0.1141

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.
Files changed (2) hide show
  1. package/dist/index.js +149 -43
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3885,6 +3885,64 @@ var getViaDiameterDefaultsWithOverrides = (overrides, pcbStyle) => {
3885
3885
  };
3886
3886
  };
3887
3887
 
3888
+ // lib/components/primitive-components/Port/areAllPcbPrimitivesOverlapping.ts
3889
+ var areAllPcbPrimitivesOverlapping = (pcbPrimitives) => {
3890
+ if (pcbPrimitives.length <= 1) return true;
3891
+ const bounds = pcbPrimitives.map((p) => {
3892
+ const circuitBounds = p._getPcbCircuitJsonBounds();
3893
+ return {
3894
+ left: circuitBounds.bounds.left,
3895
+ right: circuitBounds.bounds.right,
3896
+ top: circuitBounds.bounds.top,
3897
+ bottom: circuitBounds.bounds.bottom
3898
+ };
3899
+ });
3900
+ const overlaps = Array(bounds.length).fill(false).map(() => Array(bounds.length).fill(false));
3901
+ for (let i = 0; i < bounds.length; i++) {
3902
+ for (let j = i + 1; j < bounds.length; j++) {
3903
+ const a = bounds[i];
3904
+ const b = bounds[j];
3905
+ overlaps[i][j] = overlaps[j][i] = !(a.right < b.left || a.left > b.right || a.bottom > b.top || a.top < b.bottom);
3906
+ }
3907
+ }
3908
+ const visited = /* @__PURE__ */ new Set();
3909
+ const dfs = (node) => {
3910
+ visited.add(node);
3911
+ for (let i = 0; i < bounds.length; i++) {
3912
+ if (overlaps[node][i] && !visited.has(i)) {
3913
+ dfs(i);
3914
+ }
3915
+ }
3916
+ };
3917
+ dfs(0);
3918
+ return visited.size === bounds.length;
3919
+ };
3920
+
3921
+ // lib/components/primitive-components/Trace/getPcbSelectorErrorForTracePort.ts
3922
+ function formatPcbPrimitiveForError(component) {
3923
+ const portHints = component._parsedProps?.portHints ?? [];
3924
+ const aliases = portHints.filter(Boolean);
3925
+ if (aliases.length > 0) {
3926
+ return `<${component.lowercaseComponentName}(${aliases.map((alias) => `.${alias}`).join(", ")}) />`;
3927
+ }
3928
+ return `<${component.lowercaseComponentName} />`;
3929
+ }
3930
+ function getPcbSelectorErrorForTracePort(selector, port) {
3931
+ if (port.pcb_port_id) return null;
3932
+ const pcbMatches = port.matchedComponents.filter((c) => c.isPcbPrimitive);
3933
+ const parentName = port.getParentNormalComponent()?.props.name ?? port.parent?.props.name ?? "unknown";
3934
+ const rawPinSelectors = Array.from(
3935
+ new Set(
3936
+ port.getNameAndAliases().filter((alias) => /^pin\d+$/.test(alias)).map((alias) => `${parentName}.${alias}`)
3937
+ )
3938
+ );
3939
+ if (pcbMatches.length > 1 && !areAllPcbPrimitivesOverlapping(pcbMatches)) {
3940
+ const suggestion = rawPinSelectors.length > 0 ? ` Use a raw pin selector like ${rawPinSelectors.map((s) => `"${s}"`).join(" or ")}.` : "";
3941
+ return `Trace selector "${selector}" resolved to "${parentName}.${port.props.name}", but that target maps to multiple non-overlapping PCB pads: ${pcbMatches.map((c) => formatPcbPrimitiveForError(c)).join(", ")}.${suggestion}`;
3942
+ }
3943
+ return null;
3944
+ }
3945
+
3888
3946
  // lib/components/primitive-components/Trace/Trace_doInitialPcbTraceRender.ts
3889
3947
  var portToObjective = (port) => {
3890
3948
  const portPosition = port._getGlobalPcbPositionAfterLayout();
@@ -3928,10 +3986,12 @@ function Trace_doInitialPcbTraceRender(trace) {
3928
3986
  }
3929
3987
  let allPortsFound;
3930
3988
  let ports;
3989
+ let portsWithSelectors;
3931
3990
  try {
3932
3991
  const connectedPorts = trace._findConnectedPorts();
3933
3992
  allPortsFound = connectedPorts.allPortsFound;
3934
3993
  ports = connectedPorts.ports ?? [];
3994
+ portsWithSelectors = connectedPorts.portsWithSelectors ?? [];
3935
3995
  } catch (error) {
3936
3996
  if (error instanceof TraceConnectionError) {
3937
3997
  db.source_trace_not_connected_error.insert({
@@ -3945,6 +4005,20 @@ function Trace_doInitialPcbTraceRender(trace) {
3945
4005
  }
3946
4006
  const portsConnectedOnPcbViaNet = [];
3947
4007
  if (!allPortsFound) return;
4008
+ const pcbSelectorError = portsWithSelectors.map(
4009
+ ({ selector, port }) => getPcbSelectorErrorForTracePort(selector, port)
4010
+ ).find(Boolean);
4011
+ if (pcbSelectorError) {
4012
+ db.pcb_trace_error.insert({
4013
+ error_type: "pcb_trace_error",
4014
+ source_trace_id: trace.source_trace_id,
4015
+ message: pcbSelectorError,
4016
+ pcb_trace_id: trace.pcb_trace_id,
4017
+ pcb_component_ids: [],
4018
+ pcb_port_ids: ports.map((p) => p.pcb_port_id).filter(Boolean)
4019
+ });
4020
+ return;
4021
+ }
3948
4022
  const portsWithoutMatchedPcbPrimitive = [];
3949
4023
  for (const port of ports) {
3950
4024
  if (!port._hasMatchedPcbPrimitive()) {
@@ -4368,6 +4442,20 @@ function Trace_doInitialPcbManualTraceRender(trace) {
4368
4442
  throw error;
4369
4443
  }
4370
4444
  if (!allPortsFound) return;
4445
+ const pcbSelectorError = portsWithSelectors.map(
4446
+ ({ selector, port }) => getPcbSelectorErrorForTracePort(selector, port)
4447
+ ).find(Boolean);
4448
+ if (pcbSelectorError) {
4449
+ db.pcb_trace_error.insert({
4450
+ error_type: "pcb_trace_error",
4451
+ source_trace_id: trace.source_trace_id,
4452
+ message: pcbSelectorError,
4453
+ pcb_trace_id: trace.pcb_trace_id,
4454
+ pcb_component_ids: [],
4455
+ pcb_port_ids: ports.map((p) => p.pcb_port_id).filter(Boolean)
4456
+ });
4457
+ return;
4458
+ }
4371
4459
  const portsWithoutMatchedPcbPrimitive = [];
4372
4460
  for (const port of ports) {
4373
4461
  if (!port._hasMatchedPcbPrimitive()) {
@@ -4491,6 +4579,18 @@ function Trace_doInitialPcbManualTraceRender(trace) {
4491
4579
  });
4492
4580
  continue;
4493
4581
  }
4582
+ const pcbTargetError = getPcbSelectorErrorForTracePort(pt, resolvedPort);
4583
+ if (pcbTargetError) {
4584
+ db.pcb_trace_error.insert({
4585
+ error_type: "pcb_trace_error",
4586
+ source_trace_id: trace.source_trace_id,
4587
+ message: pcbTargetError,
4588
+ pcb_trace_id: trace.pcb_trace_id,
4589
+ pcb_component_ids: [],
4590
+ pcb_port_ids: []
4591
+ });
4592
+ return;
4593
+ }
4494
4594
  const portPos = resolvedPort._getGlobalPcbPositionAfterLayout();
4495
4595
  coordinates = { x: portPos.x, y: portPos.y };
4496
4596
  isGlobalPosition = true;
@@ -5262,14 +5362,27 @@ var createInstanceFromReactElement = (reactElm) => {
5262
5362
  import "circuit-json";
5263
5363
  import "zod";
5264
5364
 
5365
+ // lib/utils/schematic/getPinNumberFromPinLabelsKey.ts
5366
+ var PIN_LABELS_KEY_RE = /^(?:pin)?(\d+)$/;
5367
+ var getPinNumberFromPinLabelsKey = (pinKey) => {
5368
+ const match = pinKey.match(PIN_LABELS_KEY_RE);
5369
+ if (!match) return null;
5370
+ return Number.parseInt(match[1], 10);
5371
+ };
5372
+
5265
5373
  // lib/utils/schematic/parsePinNumberFromLabelsOrThrow.ts
5266
5374
  var parsePinNumberFromLabelsOrThrow = (pinNumberOrLabel, pinLabels) => {
5267
5375
  if (typeof pinNumberOrLabel === "number") {
5268
5376
  return pinNumberOrLabel;
5269
5377
  }
5378
+ const directPinNumber = getPinNumberFromPinLabelsKey(pinNumberOrLabel);
5379
+ if (directPinNumber !== null) {
5380
+ return directPinNumber;
5381
+ }
5270
5382
  if (pinNumberOrLabel.startsWith("pin")) {
5271
- const pinNumber = Number(pinNumberOrLabel.slice(3));
5272
- return pinNumber;
5383
+ throw new Error(
5384
+ `Invalid pinLabels key "${pinNumberOrLabel}". Expected "pin\${number}" (e.g. pin1, pin2).`
5385
+ );
5273
5386
  }
5274
5387
  if (!pinLabels) {
5275
5388
  throw new Error(
@@ -5279,7 +5392,13 @@ var parsePinNumberFromLabelsOrThrow = (pinNumberOrLabel, pinLabels) => {
5279
5392
  for (const pinNumberKey in pinLabels) {
5280
5393
  const aliases = Array.isArray(pinLabels[pinNumberKey]) ? pinLabels[pinNumberKey] : [pinLabels[pinNumberKey]];
5281
5394
  if (aliases.includes(pinNumberOrLabel)) {
5282
- return Number(pinNumberKey.replace("pin", ""));
5395
+ const pinNumber = getPinNumberFromPinLabelsKey(pinNumberKey);
5396
+ if (pinNumber === null) {
5397
+ throw new Error(
5398
+ `Invalid pinLabels key "${pinNumberKey}". Expected "pin\${number}" (e.g. pin1, pin2).`
5399
+ );
5400
+ }
5401
+ return pinNumber;
5283
5402
  }
5284
5403
  }
5285
5404
  throw new Error(
@@ -8360,39 +8479,6 @@ import "schematic-symbols";
8360
8479
  import { applyToPoint as applyToPoint16, compose as compose4, translate as translate3 } from "transformation-matrix";
8361
8480
  import { z as z7 } from "zod";
8362
8481
 
8363
- // lib/components/primitive-components/Port/areAllPcbPrimitivesOverlapping.ts
8364
- var areAllPcbPrimitivesOverlapping = (pcbPrimitives) => {
8365
- if (pcbPrimitives.length <= 1) return true;
8366
- const bounds = pcbPrimitives.map((p) => {
8367
- const circuitBounds = p._getPcbCircuitJsonBounds();
8368
- return {
8369
- left: circuitBounds.bounds.left,
8370
- right: circuitBounds.bounds.right,
8371
- top: circuitBounds.bounds.top,
8372
- bottom: circuitBounds.bounds.bottom
8373
- };
8374
- });
8375
- const overlaps = Array(bounds.length).fill(false).map(() => Array(bounds.length).fill(false));
8376
- for (let i = 0; i < bounds.length; i++) {
8377
- for (let j = i + 1; j < bounds.length; j++) {
8378
- const a = bounds[i];
8379
- const b = bounds[j];
8380
- overlaps[i][j] = overlaps[j][i] = !(a.right < b.left || a.left > b.right || a.bottom > b.top || a.top < b.bottom);
8381
- }
8382
- }
8383
- const visited = /* @__PURE__ */ new Set();
8384
- const dfs = (node) => {
8385
- visited.add(node);
8386
- for (let i = 0; i < bounds.length; i++) {
8387
- if (overlaps[node][i] && !visited.has(i)) {
8388
- dfs(i);
8389
- }
8390
- }
8391
- };
8392
- dfs(0);
8393
- return visited.size === bounds.length;
8394
- };
8395
-
8396
8482
  // lib/components/primitive-components/Port/getCenterOfPcbPrimitives.ts
8397
8483
  var getCenterOfPcbPrimitives = (pcbPrimitives) => {
8398
8484
  if (pcbPrimitives.length === 0) {
@@ -10384,6 +10470,21 @@ var NormalComponent3 = class extends PrimitiveComponent2 {
10384
10470
  invalidPinLabelsMessages = messages;
10385
10471
  }
10386
10472
  super(filteredProps);
10473
+ if (filteredProps.pinLabels && !Array.isArray(filteredProps.pinLabels)) {
10474
+ const invalidPinKey = Object.keys(filteredProps.pinLabels).find(
10475
+ (pinKey) => getPinNumberFromPinLabelsKey(pinKey) === null
10476
+ );
10477
+ if (invalidPinKey) {
10478
+ throw new InvalidProps(this.lowercaseComponentName, this.props, {
10479
+ _errors: [],
10480
+ pinLabels: {
10481
+ _errors: [
10482
+ `Invalid pinLabels key "${invalidPinKey}". Expected "pin\${number}" (e.g. pin1, pin2).`
10483
+ ]
10484
+ }
10485
+ });
10486
+ }
10487
+ }
10387
10488
  this._invalidPinLabelMessages = invalidPinLabelsMessages;
10388
10489
  this._addChildrenFromStringFootprint();
10389
10490
  this.initPorts();
@@ -10476,21 +10577,26 @@ var NormalComponent3 = class extends PrimitiveComponent2 {
10476
10577
  }
10477
10578
  const pinLabels = this._parsedProps.pinLabels;
10478
10579
  if (pinLabels) {
10479
- for (let [pinNumber, label] of Object.entries(pinLabels)) {
10480
- pinNumber = pinNumber.replace("pin", "");
10580
+ for (const [pinKey, label] of Object.entries(pinLabels)) {
10581
+ const pinNumber = getPinNumberFromPinLabelsKey(pinKey);
10582
+ if (pinNumber === null) {
10583
+ throw new Error(
10584
+ `Invalid pinLabels key "${pinKey}". Expected "pin\${number}" (e.g. pin1, pin2).`
10585
+ );
10586
+ }
10481
10587
  let existingPort = portsToCreate.find(
10482
- (p) => p._parsedProps.pinNumber === Number(pinNumber)
10588
+ (p) => p._parsedProps.pinNumber === pinNumber
10483
10589
  );
10484
10590
  const primaryLabel = Array.isArray(label) ? label[0] : label;
10485
10591
  const otherLabels = Array.isArray(label) ? label.slice(1) : [];
10486
10592
  if (!existingPort) {
10487
10593
  existingPort = new Port(
10488
10594
  {
10489
- pinNumber: parseInt(pinNumber),
10595
+ pinNumber,
10490
10596
  name: primaryLabel,
10491
10597
  aliases: [
10492
10598
  ...otherLabels,
10493
- ...opts.additionalAliases?.[`pin${parseInt(pinNumber)}`] ?? []
10599
+ ...opts.additionalAliases?.[`pin${pinNumber}`] ?? []
10494
10600
  ]
10495
10601
  },
10496
10602
  {
@@ -11274,7 +11380,7 @@ var NormalComponent3 = class extends PrimitiveComponent2 {
11274
11380
  if (Array.isArray(pinLabels)) {
11275
11381
  return pinLabels.length;
11276
11382
  }
11277
- const pinNumbers = Object.keys(pinLabels).map((k) => k.startsWith("pin") ? parseInt(k.slice(3)) : parseInt(k)).filter((n) => !Number.isNaN(n));
11383
+ const pinNumbers = Object.keys(pinLabels).map((k) => getPinNumberFromPinLabelsKey(k)).filter((n) => n !== null && !Number.isNaN(n));
11278
11384
  if (pinNumbers.length > 0) {
11279
11385
  return Math.max(...pinNumbers);
11280
11386
  }
@@ -18849,7 +18955,7 @@ import { identity as identity5 } from "transformation-matrix";
18849
18955
  var package_default = {
18850
18956
  name: "@tscircuit/core",
18851
18957
  type: "module",
18852
- version: "0.0.1139",
18958
+ version: "0.0.1140",
18853
18959
  types: "dist/index.d.ts",
18854
18960
  main: "dist/index.js",
18855
18961
  module: "dist/index.js",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/core",
3
3
  "type": "module",
4
- "version": "0.0.1140",
4
+ "version": "0.0.1141",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",