@tscircuit/checks 0.0.183 → 0.0.185

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/README.md CHANGED
@@ -153,3 +153,10 @@ export const pcb_trace_error = z
153
153
  export type PCBTraceErrorInput = z.input<typeof pcb_trace_error>
154
154
  export type PCBTraceError = z.infer<typeof pcb_trace_error>
155
155
  ```
156
+
157
+
158
+ ### checkSameNameNetsAreConnected
159
+
160
+ Checks whether source nets with exactly the same nonblank name belong to one electrical network, including across subcircuits. Returns one `source_confusing_net_name_warning` per ambiguous name with the affected `source_net_ids`. Connectivity follows source traces, shared ports, and both forms of internal component pin connections; a shared name or scoped connectivity key alone does not connect nets.
161
+
162
+ Included in `runAllNetlistChecks` and `runAllChecks`. This checks logical source connectivity; PCB routing continuity remains a separate check.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as circuit_json from 'circuit-json';
2
- import { AnyCircuitElement, PcbPortNotConnectedError, PcbTraceError, PcbPlacementError, PcbComponentOutsideBoardError, PcbViaClearanceError, PcbTraceWarning, PcbTraceMissingError, PcbFootprintOverlapError, PcbComponentMissingCourtyardWarning, PcbTraceTooLongWarning, PcbPadPadClearanceError, PcbPadTraceClearanceError, PcbViaTraceClearanceError, SourceComponentMisconfiguredError, SourceComponentPinsUnderspecifiedWarning, SourceNoPowerPinDefinedWarning, SourceNoGroundPinDefinedWarning, SchematicComponentStylingWarning, PcbConnectorNotInAccessibleOrientationWarning } from 'circuit-json';
2
+ import { AnyCircuitElement, PcbPortNotConnectedError, PcbTraceError, PcbPlacementError, PcbComponentOutsideBoardError, PcbViaClearanceError, PcbTraceWarning, PcbTraceMissingError, PcbFootprintOverlapError, PcbComponentMissingCourtyardWarning, PcbTraceTooLongWarning, PcbPadPadClearanceError, PcbPadTraceClearanceError, PcbViaTraceClearanceError, SourceComponentMisconfiguredError, SourceComponentPinsUnderspecifiedWarning, SourceNoPowerPinDefinedWarning, SourceNoGroundPinDefinedWarning, SchematicComponentStylingWarning, PcbConnectorNotInAccessibleOrientationWarning, SourceConfusingNetNameWarning } from 'circuit-json';
3
3
  import { ConnectivityMap } from 'circuit-json-to-connectivity-map';
4
4
 
5
5
  declare function checkEachPcbPortConnectedToPcbTraces(circuitJson: AnyCircuitElement[]): PcbPortNotConnectedError[];
@@ -192,7 +192,7 @@ declare function runAllNetlistChecks(circuitJson: AnyCircuitElement[]): Promise<
192
192
  source_component_id: string;
193
193
  source_port_id: string;
194
194
  subcircuit_id?: string;
195
- } | circuit_json.SourceComponentMisconfiguredError)[]>;
195
+ } | circuit_json.SourceComponentMisconfiguredError | circuit_json.SourceConfusingNetNameWarning)[]>;
196
196
  declare function runAllSchematicChecks(circuitJson: AnyCircuitElement[]): Promise<circuit_json.SchematicComponentStylingWarning[]>;
197
197
  declare function runAllPinSpecificationChecks(circuitJson: AnyCircuitElement[]): Promise<(circuit_json.SourceComponentPinsUnderspecifiedWarning | circuit_json.SourceNoPowerPinDefinedWarning | circuit_json.SourceNoGroundPinDefinedWarning)[]>;
198
198
  declare function runAllRoutingChecks(circuitJson: AnyCircuitElement[]): Promise<(circuit_json.PcbPortNotConnectedError | circuit_json.PcbTraceError | circuit_json.PcbViaClearanceError | circuit_json.PcbTraceMissingError | circuit_json.PcbTraceTooLongWarning | circuit_json.PcbPadPadClearanceError | circuit_json.PcbPadTraceClearanceError | circuit_json.PcbViaTraceClearanceError)[]>;
@@ -204,7 +204,7 @@ declare function runAllChecks(circuitJson: AnyCircuitElement[]): Promise<(circui
204
204
  source_component_id: string;
205
205
  source_port_id: string;
206
206
  subcircuit_id?: string;
207
- } | circuit_json.SourceComponentMisconfiguredError | circuit_json.SourceComponentPinsUnderspecifiedWarning | circuit_json.SourceNoPowerPinDefinedWarning | circuit_json.SourceNoGroundPinDefinedWarning | circuit_json.SchematicComponentStylingWarning | circuit_json.PcbConnectorNotInAccessibleOrientationWarning | circuit_json.PcbCourtyardOverlapError)[]>;
207
+ } | circuit_json.SourceComponentMisconfiguredError | circuit_json.SourceComponentPinsUnderspecifiedWarning | circuit_json.SourceNoPowerPinDefinedWarning | circuit_json.SourceNoGroundPinDefinedWarning | circuit_json.SchematicComponentStylingWarning | circuit_json.SourceConfusingNetNameWarning | circuit_json.PcbConnectorNotInAccessibleOrientationWarning | circuit_json.PcbCourtyardOverlapError)[]>;
208
208
 
209
209
  declare function checkConnectorAccessibleOrientation(circuitJson: AnyCircuitElement[]): PcbConnectorNotInAccessibleOrientationWarning[];
210
210
 
@@ -215,4 +215,7 @@ declare function checkConnectorAccessibleOrientation(circuitJson: AnyCircuitElem
215
215
  */
216
216
  declare function checkTestPointAccessibility(circuitJson: AnyCircuitElement[]): PcbPlacementError[];
217
217
 
218
- export { NetManager, checkAllPinsInComponentAreUnderspecified, checkConnectorAccessibleOrientation, checkCopperToBoardEdgeClearance, checkDifferentNetViaSpacing, checkEachPcbPortConnectedToPcbTraces, checkEachPcbTraceNonOverlapping, checkNoGroundPinDefined, checkNoPowerPinDefined, checkPadPadClearance, checkPadTraceClearance, checkPcbComponentOverCutout, checkPcbComponentOverlap, checkPcbComponentsMissingCourtyard, checkPcbComponentsOutOfBoard, checkPcbCopperOverKeepout, checkPcbTraceLengths, checkPcbTraceViaCounts, checkPcbTracesOutOfBoard, checkPinMustBeConnected, checkSameNetViaSpacing, checkSchematicComponentExcessiveVerticalPadding, checkSchematicComponentMissingReferenceDesignatorText, checkSchematicComponentPortsOutsideBody, checkSourceTracesHavePcbTraces, checkSourceTracesMatchPcbTraceThickness, checkTestPointAccessibility, checkTracesAreContiguous, checkTwoTerminalSwitchContactsOnDifferentNets, checkViaPadClearance, checkViaTraceClearance, checkViasInPads, checkViasOffBoard, dedupePcbDrcErrors, runAllChecks, runAllNetlistChecks, runAllPinSpecificationChecks, runAllPlacementChecks, runAllRoutingChecks, runAllSchematicChecks };
218
+ /** Warn once per name when its source nets belong to multiple electrical islands. */
219
+ declare function checkSameNameNetsAreConnected(circuitJson: AnyCircuitElement[]): SourceConfusingNetNameWarning[];
220
+
221
+ export { NetManager, checkAllPinsInComponentAreUnderspecified, checkConnectorAccessibleOrientation, checkCopperToBoardEdgeClearance, checkDifferentNetViaSpacing, checkEachPcbPortConnectedToPcbTraces, checkEachPcbTraceNonOverlapping, checkNoGroundPinDefined, checkNoPowerPinDefined, checkPadPadClearance, checkPadTraceClearance, checkPcbComponentOverCutout, checkPcbComponentOverlap, checkPcbComponentsMissingCourtyard, checkPcbComponentsOutOfBoard, checkPcbCopperOverKeepout, checkPcbTraceLengths, checkPcbTraceViaCounts, checkPcbTracesOutOfBoard, checkPinMustBeConnected, checkSameNameNetsAreConnected, checkSameNetViaSpacing, checkSchematicComponentExcessiveVerticalPadding, checkSchematicComponentMissingReferenceDesignatorText, checkSchematicComponentPortsOutsideBody, checkSourceTracesHavePcbTraces, checkSourceTracesMatchPcbTraceThickness, checkTestPointAccessibility, checkTracesAreContiguous, checkTwoTerminalSwitchContactsOnDifferentNets, checkViaPadClearance, checkViaTraceClearance, checkViasInPads, checkViasOffBoard, dedupePcbDrcErrors, runAllChecks, runAllNetlistChecks, runAllPinSpecificationChecks, runAllPlacementChecks, runAllRoutingChecks, runAllSchematicChecks };
package/dist/index.js CHANGED
@@ -2705,7 +2705,7 @@ function checkSourceTracesHavePcbTraces(circuitJson) {
2705
2705
  }
2706
2706
 
2707
2707
  // lib/check-traces-are-contiguous/check-traces-are-contiguous.ts
2708
- import { pointToSegmentDistance as pointToSegmentDistance2 } from "@tscircuit/math-utils";
2708
+ import { pointToSegmentDistance as pointToSegmentDistance3 } from "@tscircuit/math-utils";
2709
2709
  import {
2710
2710
  getReadableNameForPcbPort as getReadableNameForPcbPort2,
2711
2711
  getReadableNameForPcbTrace
@@ -2714,6 +2714,135 @@ import {
2714
2714
  getFullConnectivityMapFromCircuitJson as getFullConnectivityMapFromCircuitJson7,
2715
2715
  PcbConnectivityMap as PcbConnectivityMap2
2716
2716
  } from "circuit-json-to-connectivity-map";
2717
+
2718
+ // lib/check-traces-are-contiguous/via-contact-index.ts
2719
+ import {
2720
+ all_layers as all_layers2
2721
+ } from "circuit-json";
2722
+ import { getPrimaryId as getPrimaryId3 } from "@tscircuit/circuit-json-util";
2723
+ import { pointToSegmentDistance as pointToSegmentDistance2 } from "@tscircuit/math-utils";
2724
+ var CONTACT_EPSILON = 1e-9;
2725
+ function getViaContactIndex(circuitJson, connectivity) {
2726
+ const index = /* @__PURE__ */ new Map();
2727
+ const pads = getPads(circuitJson);
2728
+ const traces = circuitJson.filter((element) => element.type === "pcb_trace");
2729
+ const vias = circuitJson.filter((element) => element.type === "pcb_via");
2730
+ const board = circuitJson.find((element) => element.type === "pcb_board");
2731
+ const layerCount = board?.num_layers;
2732
+ const innerLayers = all_layers2.filter((layer) => layer.startsWith("inner"));
2733
+ const stack = [
2734
+ "top",
2735
+ ...innerLayers.slice(
2736
+ 0,
2737
+ layerCount === void 0 ? void 0 : Math.max(0, layerCount - 2)
2738
+ ),
2739
+ ...layerCount === 1 ? [] : ["bottom"]
2740
+ ];
2741
+ const add = (id, layers, contact) => {
2742
+ if (![contact.x, contact.y].every(Number.isFinite)) return;
2743
+ const net = connectivity.getNetConnectedToId(id);
2744
+ if (!net) return;
2745
+ const touchesPad = pads.some((pad) => {
2746
+ if (connectivity.getNetConnectedToId(getPrimaryId3(pad)) !== net || !getLayersOfPcbElement(pad).some((layer) => layers.includes(layer)))
2747
+ return false;
2748
+ if (contact.radius === void 0) return isPointInPad(contact, pad);
2749
+ const viaGeometry = {
2750
+ type: "pcb_via",
2751
+ pcb_via_id: id,
2752
+ x: contact.x,
2753
+ y: contact.y,
2754
+ outer_diameter: contact.radius * 2,
2755
+ hole_diameter: 0,
2756
+ layers
2757
+ };
2758
+ return getPadToPadGap(viaGeometry, pad) <= CONTACT_EPSILON;
2759
+ });
2760
+ const touchingTraceIds = /* @__PURE__ */ new Set();
2761
+ for (const trace of traces) {
2762
+ if (trace.route_thickness_mode === "interpolated" || connectivity.getNetConnectedToId(trace.pcb_trace_id) !== net)
2763
+ continue;
2764
+ for (let i = 1; i < trace.route.length; i++) {
2765
+ const a = trace.route[i - 1], b = trace.route[i];
2766
+ if (a.route_type !== "wire" || b.route_type !== "wire" || a.layer !== b.layer || !layers.includes(a.layer) || !Number.isFinite(a.width) || a.width <= 0 || Math.hypot(a.x - b.x, a.y - b.y) <= CONTACT_EPSILON)
2767
+ continue;
2768
+ const reach = contact.radius === void 0 ? 0 : contact.radius + a.width / 2;
2769
+ if (pointToSegmentDistance2(contact, a, b) <= reach + CONTACT_EPSILON) {
2770
+ touchingTraceIds.add(trace.pcb_trace_id);
2771
+ break;
2772
+ }
2773
+ }
2774
+ }
2775
+ const copper = { ...contact, touchesPad, touchingTraceIds };
2776
+ const byLayer = index.get(net) ?? /* @__PURE__ */ new Map();
2777
+ for (const layer of layers) {
2778
+ const contacts = byLayer.get(layer) ?? [];
2779
+ contacts.push(copper);
2780
+ byLayer.set(layer, contacts);
2781
+ }
2782
+ index.set(net, byLayer);
2783
+ };
2784
+ for (const via of vias) {
2785
+ if (!Number.isFinite(via.outer_diameter) || via.outer_diameter <= 0)
2786
+ continue;
2787
+ add(via.pcb_via_id, getLayersOfPcbElement(via), {
2788
+ x: via.x,
2789
+ y: via.y,
2790
+ ownerTraceId: via.pcb_trace_id,
2791
+ radius: via.outer_diameter / 2
2792
+ });
2793
+ }
2794
+ for (const trace of circuitJson) {
2795
+ if (trace.type !== "pcb_trace") continue;
2796
+ for (const point of trace.route) {
2797
+ if (point.route_type !== "via") continue;
2798
+ if (vias.some(
2799
+ (via) => Math.hypot(via.x - point.x, via.y - point.y) <= CONTACT_EPSILON && (via.pcb_trace_id === trace.pcb_trace_id || !via.pcb_trace_id && connectivity.areIdsConnected(
2800
+ via.pcb_via_id,
2801
+ trace.pcb_trace_id
2802
+ ))
2803
+ ))
2804
+ continue;
2805
+ const from = stack.indexOf(point.from_layer);
2806
+ const to = stack.indexOf(point.to_layer);
2807
+ if (from < 0 || to < 0) continue;
2808
+ const diameter = point.outer_diameter;
2809
+ if (diameter !== void 0 && (!Number.isFinite(diameter) || diameter <= 0))
2810
+ continue;
2811
+ add(
2812
+ trace.pcb_trace_id,
2813
+ stack.slice(Math.min(from, to), Math.max(from, to) + 1),
2814
+ {
2815
+ x: point.x,
2816
+ y: point.y,
2817
+ ownerTraceId: trace.pcb_trace_id,
2818
+ radius: diameter === void 0 ? void 0 : diameter / 2
2819
+ }
2820
+ );
2821
+ }
2822
+ }
2823
+ return index;
2824
+ }
2825
+ function endpointTouchesVia({
2826
+ point,
2827
+ width,
2828
+ ownerTrace,
2829
+ index,
2830
+ connectivity
2831
+ }) {
2832
+ if (point.route_type !== "wire" || !Number.isFinite(width) || width <= 0)
2833
+ return false;
2834
+ const net = connectivity.getNetConnectedToId(ownerTrace.pcb_trace_id);
2835
+ if (!net) return false;
2836
+ return (index.get(net)?.get(point.layer) ?? []).some((via) => {
2837
+ if (via.ownerTraceId === ownerTrace.pcb_trace_id) return false;
2838
+ if (!via.touchesPad && ![...via.touchingTraceIds].some((id) => id !== ownerTrace.pcb_trace_id))
2839
+ return false;
2840
+ const contactDistance = via.radius === void 0 ? 0 : via.radius + width / 2;
2841
+ return Math.hypot(point.x - via.x, point.y - via.y) <= contactDistance + CONTACT_EPSILON;
2842
+ });
2843
+ }
2844
+
2845
+ // lib/check-traces-are-contiguous/check-traces-are-contiguous.ts
2717
2846
  var ENDPOINT_CONTACT_EPSILON = 1e-9;
2718
2847
  var TRACE_SEGMENT_GEOMETRY_EPSILON = 1e-9;
2719
2848
  function routePointTouchesPad(point, pad) {
@@ -2775,7 +2904,7 @@ function routePointTouchesLogicallyConnectedTraceCopper({
2775
2904
  for (const segment of candidateSegments) {
2776
2905
  if (segment.trace.pcb_trace_id === ownerTrace.pcb_trace_id) continue;
2777
2906
  const maximumContactDistance = endpointTraceCopperWidth / 2 + segment.start.width / 2 + ENDPOINT_CONTACT_EPSILON;
2778
- if (pointToSegmentDistance2(point, segment.start, segment.end) <= maximumContactDistance) {
2907
+ if (pointToSegmentDistance3(point, segment.start, segment.end) <= maximumContactDistance) {
2779
2908
  return true;
2780
2909
  }
2781
2910
  }
@@ -2879,6 +3008,14 @@ function checkTracesAreContiguous(circuitJson) {
2879
3008
  );
2880
3009
  return traceWireSegmentsByNetAndLayer;
2881
3010
  };
3011
+ let viaContactIndex;
3012
+ const getViaIndex = () => {
3013
+ viaContactIndex ??= getViaContactIndex(
3014
+ circuitJson,
3015
+ getFullConnectivityMap()
3016
+ );
3017
+ return viaContactIndex;
3018
+ };
2882
3019
  const checkedSourceTraceIds = /* @__PURE__ */ new Set();
2883
3020
  for (const pad of pcbSmtPads) {
2884
3021
  if (pad.pcb_port_id) {
@@ -3068,8 +3205,20 @@ function checkTracesAreContiguous(circuitJson) {
3068
3205
  traceWireSegmentsByNetAndLayer: getTraceWireSegmentIndex(),
3069
3206
  fullConnectivityMap: getFullConnectivityMap()
3070
3207
  });
3071
- const firstIsConnected = firstConnectsToAnyPad || firstConnectsToLogicallyConnectedTraceCopper;
3072
- const lastIsConnected = lastConnectsToAnyPad || lastConnectsToLogicallyConnectedTraceCopper;
3208
+ const firstIsConnected = firstConnectsToAnyPad || firstConnectsToLogicallyConnectedTraceCopper || firstEndpointTraceCopperWidth !== void 0 && endpointTouchesVia({
3209
+ point: firstPoint,
3210
+ width: firstEndpointTraceCopperWidth,
3211
+ ownerTrace: trace,
3212
+ index: getViaIndex(),
3213
+ connectivity: getFullConnectivityMap()
3214
+ });
3215
+ const lastIsConnected = lastConnectsToAnyPad || lastConnectsToLogicallyConnectedTraceCopper || lastEndpointTraceCopperWidth !== void 0 && endpointTouchesVia({
3216
+ point: lastPoint,
3217
+ width: lastEndpointTraceCopperWidth,
3218
+ ownerTrace: trace,
3219
+ index: getViaIndex(),
3220
+ connectivity: getFullConnectivityMap()
3221
+ });
3073
3222
  const endpointsAreSame = firstPoint.route_type === "wire" && lastPoint.route_type === "wire" && firstPoint.layer === lastPoint.layer && Math.hypot(firstPoint.x - lastPoint.x, firstPoint.y - lastPoint.y) <= ENDPOINT_CONTACT_EPSILON;
3074
3223
  if (!firstIsConnected && firstPoint.route_type === "wire") {
3075
3224
  errors.push({
@@ -3185,7 +3334,7 @@ function checkPcbTracesOutOfBoard(circuitJson, config = {}) {
3185
3334
  import {
3186
3335
  cju as cju6,
3187
3336
  getBoundsOfPcbElements as getBoundsOfPcbElements5,
3188
- getPrimaryId as getPrimaryId3
3337
+ getPrimaryId as getPrimaryId4
3189
3338
  } from "@tscircuit/circuit-json-util";
3190
3339
  import { doBoundsOverlap as doBoundsOverlap3 } from "@tscircuit/math-utils";
3191
3340
  import { getFullConnectivityMapFromCircuitJson as getFullConnectivityMapFromCircuitJson8 } from "circuit-json-to-connectivity-map";
@@ -3221,7 +3370,7 @@ var formatOverlapElementDescription = (circuitJson, element) => {
3221
3370
  if ("pcb_port_id" in element && element.pcb_port_id) {
3222
3371
  return getReadableNameForPort(circuitJson, element.pcb_port_id);
3223
3372
  }
3224
- const id = getPrimaryId3(element);
3373
+ const id = getPrimaryId4(element);
3225
3374
  const readableName = getReadableNameForElementId(circuitJson, id);
3226
3375
  return readableName === "element" ? `[${id}]` : readableName;
3227
3376
  };
@@ -3234,7 +3383,7 @@ function checkPcbComponentOverlap(circuitJson) {
3234
3383
  const courtyards = circuitJson.filter(isCourtyardElement);
3235
3384
  const componentMap = /* @__PURE__ */ new Map();
3236
3385
  for (const pad of smtPads) {
3237
- const componentId = pad.pcb_component_id || `standalone_pad_${getPrimaryId3(pad)}`;
3386
+ const componentId = pad.pcb_component_id || `standalone_pad_${getPrimaryId4(pad)}`;
3238
3387
  if (!componentMap.has(componentId)) {
3239
3388
  componentMap.set(componentId, {
3240
3389
  component_id: componentId,
@@ -3244,7 +3393,7 @@ function checkPcbComponentOverlap(circuitJson) {
3244
3393
  componentMap.get(componentId).elements.push(pad);
3245
3394
  }
3246
3395
  for (const hole of platedHoles) {
3247
- const componentId = hole.pcb_component_id || `standalone_plated_hole_${getPrimaryId3(hole)}`;
3396
+ const componentId = hole.pcb_component_id || `standalone_plated_hole_${getPrimaryId4(hole)}`;
3248
3397
  if (!componentMap.has(componentId)) {
3249
3398
  componentMap.set(componentId, {
3250
3399
  component_id: componentId,
@@ -3254,7 +3403,7 @@ function checkPcbComponentOverlap(circuitJson) {
3254
3403
  componentMap.get(componentId).elements.push(hole);
3255
3404
  }
3256
3405
  for (const hole of holes) {
3257
- const componentId = hole.pcb_component_id || `standalone_hole_${getPrimaryId3(hole)}`;
3406
+ const componentId = hole.pcb_component_id || `standalone_hole_${getPrimaryId4(hole)}`;
3258
3407
  if (!componentMap.has(componentId)) {
3259
3408
  componentMap.set(componentId, {
3260
3409
  component_id: componentId,
@@ -3290,8 +3439,8 @@ function checkPcbComponentOverlap(circuitJson) {
3290
3439
  }
3291
3440
  for (const elem1 of comp1.elements) {
3292
3441
  for (const elem2 of comp2.elements) {
3293
- const id1 = getPrimaryId3(elem1);
3294
- const id2 = getPrimaryId3(elem2);
3442
+ const id1 = getPrimaryId4(elem1);
3443
+ const id2 = getPrimaryId4(elem2);
3295
3444
  if ((isCourtyardElement(elem1) || isCourtyardElement(elem2)) && elem1.type !== "pcb_hole" && elem2.type !== "pcb_hole") {
3296
3445
  continue;
3297
3446
  }
@@ -3544,7 +3693,7 @@ var checkPcbTraceViaCounts = (circuitJson) => {
3544
3693
 
3545
3694
  // lib/check-pad-pad-clearance.ts
3546
3695
  import {
3547
- getPrimaryId as getPrimaryId4,
3696
+ getPrimaryId as getPrimaryId5,
3548
3697
  getReadableNameForElement as getReadableNameForElement6
3549
3698
  } from "@tscircuit/circuit-json-util";
3550
3699
  import { formatMm } from "format-si-unit";
@@ -3563,17 +3712,17 @@ function checkPadPadClearance(circuitJson, {
3563
3712
  const spatialIndex = new SpatialObjectIndex({
3564
3713
  objects: pads,
3565
3714
  getBounds: getPadBounds,
3566
- getId: (pad) => getPrimaryId4(pad)
3715
+ getId: (pad) => getPrimaryId5(pad)
3567
3716
  });
3568
3717
  const errors = /* @__PURE__ */ new Map();
3569
3718
  for (const padA of pads) {
3570
- const padAId = getPrimaryId4(padA);
3719
+ const padAId = getPrimaryId5(padA);
3571
3720
  const nearbyPads = spatialIndex.getObjectsInBounds(
3572
3721
  getPadBounds(padA),
3573
3722
  minClearance
3574
3723
  );
3575
3724
  for (const padB of nearbyPads) {
3576
- const padBId = getPrimaryId4(padB);
3725
+ const padBId = getPrimaryId5(padB);
3577
3726
  if (padAId === padBId) continue;
3578
3727
  if (!getLayersOfPcbElement(padA).some(
3579
3728
  (layer) => getLayersOfPcbElement(padB).includes(layer)
@@ -3609,7 +3758,7 @@ function checkPadPadClearance(circuitJson, {
3609
3758
 
3610
3759
  // lib/check-pad-trace-clearance.ts
3611
3760
  import {
3612
- getPrimaryId as getPrimaryId5,
3761
+ getPrimaryId as getPrimaryId6,
3613
3762
  getReadableNameForElement as getReadableNameForElement7
3614
3763
  } from "@tscircuit/circuit-json-util";
3615
3764
  import { formatMm as formatMm2 } from "format-si-unit";
@@ -3629,7 +3778,7 @@ function checkPadTraceClearance(circuitJson, {
3629
3778
  const spatialIndex = new SpatialObjectIndex({
3630
3779
  objects: pads,
3631
3780
  getBounds: getPadBounds,
3632
- getId: (pad) => getPrimaryId5(pad)
3781
+ getId: (pad) => getPrimaryId6(pad)
3633
3782
  });
3634
3783
  const errors = /* @__PURE__ */ new Map();
3635
3784
  const overlappingPairIds = /* @__PURE__ */ new Set();
@@ -3639,7 +3788,7 @@ function checkPadTraceClearance(circuitJson, {
3639
3788
  minClearance + segment.thickness / 2
3640
3789
  );
3641
3790
  for (const pad of nearbyPads) {
3642
- const padId = getPrimaryId5(pad);
3791
+ const padId = getPrimaryId6(pad);
3643
3792
  if (!getLayersOfPcbElement(pad).includes(segment.layer)) continue;
3644
3793
  if (connMap.areIdsConnected(segment.pcb_trace_id, padId)) continue;
3645
3794
  const pairId = `${padId}_${segment.pcb_trace_id}`;
@@ -3725,7 +3874,7 @@ function checkViaTraceClearance(circuitJson, {
3725
3874
 
3726
3875
  // lib/check-via-pad-clearance.ts
3727
3876
  import {
3728
- getPrimaryId as getPrimaryId6,
3877
+ getPrimaryId as getPrimaryId7,
3729
3878
  getReadableNameForElement as getReadableNameForElement9
3730
3879
  } from "@tscircuit/circuit-json-util";
3731
3880
  import { formatMm as formatMm4 } from "format-si-unit";
@@ -3747,7 +3896,7 @@ function checkViaPadClearance(circuitJson, {
3747
3896
  const padIndex = new SpatialObjectIndex({
3748
3897
  objects: pads,
3749
3898
  getBounds: getPadBounds,
3750
- getId: getPrimaryId6
3899
+ getId: getPrimaryId7
3751
3900
  });
3752
3901
  const errors = [];
3753
3902
  for (const via of vias) {
@@ -3756,7 +3905,7 @@ function checkViaPadClearance(circuitJson, {
3756
3905
  requiredClearance
3757
3906
  );
3758
3907
  for (const pad of nearbyPads) {
3759
- const padId = getPrimaryId6(pad);
3908
+ const padId = getPrimaryId7(pad);
3760
3909
  if (!getLayersOfPcbElement(via).some(
3761
3910
  (layer) => getLayersOfPcbElement(pad).includes(layer)
3762
3911
  )) {
@@ -3786,7 +3935,7 @@ function checkViaPadClearance(circuitJson, {
3786
3935
  }
3787
3936
 
3788
3937
  // lib/check-vias-in-pads.ts
3789
- import { getPrimaryId as getPrimaryId7 } from "@tscircuit/circuit-json-util";
3938
+ import { getPrimaryId as getPrimaryId8 } from "@tscircuit/circuit-json-util";
3790
3939
  import { getFullConnectivityMapFromCircuitJson as getFullConnectivityMapFromCircuitJson13 } from "circuit-json-to-connectivity-map";
3791
3940
  function checkViasInPads(circuitJson) {
3792
3941
  const board = getPcbBoard(circuitJson);
@@ -3800,18 +3949,18 @@ function checkViasInPads(circuitJson) {
3800
3949
  if (vias.length === 0 || pads.length === 0) return [];
3801
3950
  const connMap = getFullConnectivityMapFromCircuitJson13(circuitJson);
3802
3951
  const padOrdinals = new Map(
3803
- pads.map((pad, index) => [getPrimaryId7(pad), index])
3952
+ pads.map((pad, index) => [getPrimaryId8(pad), index])
3804
3953
  );
3805
3954
  const padIndex = new SpatialObjectIndex({
3806
3955
  objects: pads,
3807
3956
  getBounds: getPadBounds,
3808
- getId: getPrimaryId7
3957
+ getId: getPrimaryId8
3809
3958
  });
3810
3959
  const errors = [];
3811
3960
  for (const via of vias) {
3812
3961
  const nearbyPads = padIndex.getObjectsInBounds(getPadBounds(via));
3813
3962
  for (const pad of nearbyPads) {
3814
- const padId = getPrimaryId7(pad);
3963
+ const padId = getPrimaryId8(pad);
3815
3964
  const viaLayers = getLayersOfPcbElement(via);
3816
3965
  const padLayers = getLayersOfPcbElement(pad);
3817
3966
  if (!viaLayers.some((layer) => padLayers.includes(layer))) continue;
@@ -4359,6 +4508,66 @@ function checkSchematicComponentPortsOutsideBody(circuitJson) {
4359
4508
  return warnings;
4360
4509
  }
4361
4510
 
4511
+ // lib/check-same-name-nets-are-connected.ts
4512
+ function checkSameNameNetsAreConnected(circuitJson) {
4513
+ const parents = /* @__PURE__ */ new Map();
4514
+ const find = (id) => {
4515
+ let root = id;
4516
+ while (parents.has(root) && parents.get(root) !== root) {
4517
+ root = parents.get(root);
4518
+ }
4519
+ while (parents.has(id) && parents.get(id) !== root) {
4520
+ const next = parents.get(id);
4521
+ parents.set(id, root);
4522
+ id = next;
4523
+ }
4524
+ return root;
4525
+ };
4526
+ const connect = (ids) => {
4527
+ if (ids.length < 2) return;
4528
+ const root = find(ids[0]);
4529
+ for (const id of ids.slice(1)) parents.set(find(id), root);
4530
+ };
4531
+ const netsByName = /* @__PURE__ */ new Map();
4532
+ for (const element of circuitJson) {
4533
+ if (element.type === "source_net" && element.name.trim()) {
4534
+ const nets = netsByName.get(element.name) ?? [];
4535
+ nets.push(element);
4536
+ netsByName.set(element.name, nets);
4537
+ }
4538
+ if (element.type === "source_trace") {
4539
+ connect([
4540
+ ...element.connected_source_net_ids.map((id) => `net:${id}`),
4541
+ ...element.connected_source_port_ids.map((id) => `port:${id}`)
4542
+ ]);
4543
+ }
4544
+ if (element.type === "source_component_internal_connection") {
4545
+ connect(element.source_port_ids.map((id) => `port:${id}`));
4546
+ }
4547
+ if (element.type === "source_component") {
4548
+ for (const ids of element.internally_connected_source_port_ids ?? []) {
4549
+ connect(ids.map((id) => `port:${id}`));
4550
+ }
4551
+ }
4552
+ }
4553
+ const warnings = [];
4554
+ for (const [name, nets] of netsByName) {
4555
+ const islands = new Set(nets.map((net) => find(`net:${net.source_net_id}`)));
4556
+ if (islands.size < 2) continue;
4557
+ const ids = nets.map((net) => net.source_net_id).sort();
4558
+ warnings.push({
4559
+ type: "source_confusing_net_name_warning",
4560
+ source_confusing_net_name_warning_id: `source_confusing_net_name_warning_${ids[0]}`,
4561
+ warning_type: "source_confusing_net_name_warning",
4562
+ message: `Nets named "${name}" are not all connected (${islands.size} separate electrical networks). Connect them or use distinct names to avoid confusion.`,
4563
+ source_net_ids: ids,
4564
+ net_name: name,
4565
+ ...nets.every((net) => net.subcircuit_id === nets[0].subcircuit_id) ? { subcircuit_id: nets[0].subcircuit_id } : {}
4566
+ });
4567
+ }
4568
+ return warnings;
4569
+ }
4570
+
4362
4571
  // lib/check-connector-accessible-orientation.ts
4363
4572
  import { getBoardBounds } from "@tscircuit/circuit-json-util";
4364
4573
  function getFacingDirectionFromInsertionDirection(component) {
@@ -4645,6 +4854,7 @@ async function runAllPlacementChecks(circuitJson) {
4645
4854
  async function runAllNetlistChecks(circuitJson) {
4646
4855
  return [
4647
4856
  ...checkPinMustBeConnected(circuitJson),
4857
+ ...checkSameNameNetsAreConnected(circuitJson),
4648
4858
  ...checkTwoTerminalSwitchContactsOnDifferentNets(circuitJson)
4649
4859
  ];
4650
4860
  }
@@ -4708,6 +4918,7 @@ export {
4708
4918
  checkPcbTraceViaCounts,
4709
4919
  checkPcbTracesOutOfBoard,
4710
4920
  checkPinMustBeConnected,
4921
+ checkSameNameNetsAreConnected,
4711
4922
  checkSameNetViaSpacing,
4712
4923
  checkSchematicComponentExcessiveVerticalPadding,
4713
4924
  checkSchematicComponentMissingReferenceDesignatorText,