@tscircuit/checks 0.0.170 → 0.0.171

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
@@ -20,6 +20,7 @@ and output an array of arrays for any issues found.
20
20
  | [`checkEachPcbTraceNonOverlapping`](./lib/check-each-pcb-trace-non-overlapping/check-each-pcb-trace-non-overlapping.ts) | Returns `pcb_trace_error` when `pcb_trace` segments physically overlap incompatible geometry on the same layer. Pad/via near-misses are reported by the typed clearance checks instead. |
21
21
  | [`checkPcbComponentOverlap`](./lib/check-pcb-components-overlap/checkPcbComponentOverlap.ts) | Returns `pcb_footprint_overlap_error` when footprint elements from different components overlap in disallowed ways. |
22
22
  | [`checkPcbComponentsOutOfBoard`](./lib/check-pcb-components-out-of-board/checkPcbComponentsOutOfBoard.ts) | Returns `pcb_placement_error` when PCB components do not fit inside the board area. |
23
+ | [`checkPcbCopperOverKeepout`](./lib/check-pcb-copper-over-keepout.ts) | Returns one `pcb_placement_error` per non-excluded component or via whose copper overlaps a keepout on a shared layer. |
23
24
  | [`checkPcbTracesOutOfBoard`](./lib/check-trace-out-of-board/checkTraceOutOfBoard.ts) | Returns `pcb_trace_error` when any trace segment or via extends beyond the board boundary. |
24
25
  | [`checkPadTraceClearance`](./lib/check-pad-trace-clearance.ts) | Returns `pcb_pad_trace_clearance_error` when a pad and unrelated trace have a positive gap below the minimum clearance. Physical overlaps are reported by `checkEachPcbTraceNonOverlapping`. |
25
26
  | [`checkViaTraceClearance`](./lib/check-via-trace-clearance.ts) | Returns `pcb_via_trace_clearance_error` when a via and unrelated trace have a positive gap below the minimum clearance. Physical overlaps are reported by `checkEachPcbTraceNonOverlapping`. |
@@ -34,7 +35,7 @@ and output an array of arrays for any issues found.
34
35
 
35
36
  | Function | Description |
36
37
  | --- | --- |
37
- | [`runAllPlacementChecks`](./lib/run-all-checks.ts) | Runs placement checks (`checkCopperToBoardEdgeClearance`, `checkPcbComponentsOutOfBoard`, `checkPcbComponentOverlap`, `checkPadPadClearance`, `checkCourtyardOverlap`, `checkConnectorAccessibleOrientation`, and `checkTestPointAccessibility`). |
38
+ | [`runAllPlacementChecks`](./lib/run-all-checks.ts) | Runs placement checks (`checkCopperToBoardEdgeClearance`, `checkPcbComponentsOutOfBoard`, `checkPcbCopperOverKeepout`, `checkPcbComponentOverlap`, `checkPadPadClearance`, `checkCourtyardOverlap`, `checkConnectorAccessibleOrientation`, and `checkTestPointAccessibility`). |
38
39
  | [`runAllNetlistChecks`](./lib/run-all-checks.ts) | Runs netlist connectivity checks (currently `checkPinMustBeConnected`). |
39
40
  | [`runAllPinSpecificationChecks`](./lib/run-all-checks.ts) | Runs pin specification checks (e.g. `checkAllPinsInComponentAreUnderspecified`, `checkNoPowerPinDefined`, and `checkNoGroundPinDefined`). |
40
41
  | [`runAllSchematicChecks`](./lib/run-all-checks.ts) | Runs schematic-layout checks (currently `checkSchematicComponentExcessiveVerticalPadding`). |
package/dist/index.d.ts CHANGED
@@ -41,6 +41,8 @@ declare function checkPcbComponentsOutOfBoard(circuitJson: AnyCircuitElement[]):
41
41
  */
42
42
  declare function checkPcbComponentOverCutout(circuitJson: AnyCircuitElement[]): PcbPlacementError[];
43
43
 
44
+ declare function checkPcbCopperOverKeepout(circuitJson: AnyCircuitElement[]): PcbPlacementError[];
45
+
44
46
  declare function checkSameNetViaSpacing(circuitJson: AnyCircuitElement[], { connMap, minClearance, }?: {
45
47
  connMap?: ConnectivityMap;
46
48
  minClearance?: number;
@@ -198,4 +200,4 @@ declare function checkConnectorAccessibleOrientation(circuitJson: AnyCircuitElem
198
200
  */
199
201
  declare function checkTestPointAccessibility(circuitJson: AnyCircuitElement[]): PcbPlacementError[];
200
202
 
201
- export { NetManager, checkAllPinsInComponentAreUnderspecified, checkConnectorAccessibleOrientation, checkCopperToBoardEdgeClearance, checkDifferentNetViaSpacing, checkEachPcbPortConnectedToPcbTraces, checkEachPcbTraceNonOverlapping, checkNoGroundPinDefined, checkNoPowerPinDefined, checkPadPadClearance, checkPadTraceClearance, checkPcbComponentOverCutout, checkPcbComponentOverlap, checkPcbComponentsMissingCourtyard, checkPcbComponentsOutOfBoard, checkPcbTraceLengths, checkPcbTraceViaCounts, checkPcbTracesOutOfBoard, checkPinMustBeConnected, checkSameNetViaSpacing, checkSchematicComponentExcessiveVerticalPadding, checkSourceTracesHavePcbTraces, checkSourceTracesMatchPcbTraceThickness, checkTestPointAccessibility, checkTracesAreContiguous, checkViaPadClearance, checkViaTraceClearance, checkViasInPads, checkViasOffBoard, dedupePcbDrcErrors, runAllChecks, runAllNetlistChecks, runAllPinSpecificationChecks, runAllPlacementChecks, runAllRoutingChecks, runAllSchematicChecks };
203
+ export { NetManager, checkAllPinsInComponentAreUnderspecified, checkConnectorAccessibleOrientation, checkCopperToBoardEdgeClearance, checkDifferentNetViaSpacing, checkEachPcbPortConnectedToPcbTraces, checkEachPcbTraceNonOverlapping, checkNoGroundPinDefined, checkNoPowerPinDefined, checkPadPadClearance, checkPadTraceClearance, checkPcbComponentOverCutout, checkPcbComponentOverlap, checkPcbComponentsMissingCourtyard, checkPcbComponentsOutOfBoard, checkPcbCopperOverKeepout, checkPcbTraceLengths, checkPcbTraceViaCounts, checkPcbTracesOutOfBoard, checkPinMustBeConnected, checkSameNetViaSpacing, checkSchematicComponentExcessiveVerticalPadding, checkSourceTracesHavePcbTraces, checkSourceTracesMatchPcbTraceThickness, checkTestPointAccessibility, checkTracesAreContiguous, checkViaPadClearance, checkViaTraceClearance, checkViasInPads, checkViasOffBoard, dedupePcbDrcErrors, runAllChecks, runAllNetlistChecks, runAllPinSpecificationChecks, runAllPlacementChecks, runAllRoutingChecks, runAllSchematicChecks };
package/dist/index.js CHANGED
@@ -605,8 +605,27 @@ var getPcbBoard = (circuitJson) => circuitJson.find((el) => el.type === "pcb_boa
605
605
  var getBoardDrcValue = (board, key) => board?.[key];
606
606
 
607
607
  // lib/check-pad-clearance/common.ts
608
- var getPadBounds = (pad) => getBoundsOfPcbElements2([pad]);
608
+ var getPadBounds = (pad) => {
609
+ if (pad.type === "pcb_keepout") {
610
+ if (pad.shape === "circle") {
611
+ return {
612
+ minX: pad.center.x - pad.radius,
613
+ minY: pad.center.y - pad.radius,
614
+ maxX: pad.center.x + pad.radius,
615
+ maxY: pad.center.y + pad.radius
616
+ };
617
+ }
618
+ return {
619
+ minX: pad.center.x - pad.width / 2,
620
+ minY: pad.center.y - pad.height / 2,
621
+ maxX: pad.center.x + pad.width / 2,
622
+ maxY: pad.center.y + pad.height / 2
623
+ };
624
+ }
625
+ return getBoundsOfPcbElements2([pad]);
626
+ };
609
627
  var getPadCenter = (pad) => {
628
+ if (pad.type === "pcb_keepout") return pad.center;
610
629
  const bounds = getPadBounds(pad);
611
630
  return midpoint(
612
631
  { x: bounds.minX, y: bounds.minY },
@@ -614,6 +633,7 @@ var getPadCenter = (pad) => {
614
633
  );
615
634
  };
616
635
  var getPadRadius = (pad) => {
636
+ if (pad.type === "pcb_keepout" && pad.shape === "circle") return pad.radius;
617
637
  const bounds = getPadBounds(pad);
618
638
  return Math.min(bounds.maxX - bounds.minX, bounds.maxY - bounds.minY) / 2;
619
639
  };
@@ -629,6 +649,32 @@ var getCircleShape = (pad) => {
629
649
  };
630
650
  };
631
651
  var getPolygonShape = (pad) => {
652
+ if (pad.type === "pcb_keepout") {
653
+ if (pad.shape !== "rect") {
654
+ throw new Error(`Expected rectangular keepout, got ${pad.shape}`);
655
+ }
656
+ return {
657
+ kind: "polygon",
658
+ points: [
659
+ {
660
+ x: pad.center.x - pad.width / 2,
661
+ y: pad.center.y - pad.height / 2
662
+ },
663
+ {
664
+ x: pad.center.x + pad.width / 2,
665
+ y: pad.center.y - pad.height / 2
666
+ },
667
+ {
668
+ x: pad.center.x + pad.width / 2,
669
+ y: pad.center.y + pad.height / 2
670
+ },
671
+ {
672
+ x: pad.center.x - pad.width / 2,
673
+ y: pad.center.y + pad.height / 2
674
+ }
675
+ ]
676
+ };
677
+ }
632
678
  if (pad.type === "pcb_smtpad" && (pad.shape === "polygon" || pad.shape === "rotated_rect")) {
633
679
  return {
634
680
  kind: "polygon",
@@ -2340,6 +2386,62 @@ function checkPcbComponentOverCutout(circuitJson) {
2340
2386
  return errors;
2341
2387
  }
2342
2388
 
2389
+ // lib/check-pcb-copper-over-keepout.ts
2390
+ import { cju as cju3, getPrimaryId as getPrimaryId2 } from "@tscircuit/circuit-json-util";
2391
+ var getErrorOwnerId = (copper) => "pcb_component_id" in copper && copper.pcb_component_id ? copper.pcb_component_id : getPrimaryId2(copper);
2392
+ var getReadableCopperName = (circuitJson, copper) => {
2393
+ if ("pcb_component_id" in copper && copper.pcb_component_id) {
2394
+ const pcbComponent = circuitJson.find(
2395
+ (element) => element.type === "pcb_component" && element.pcb_component_id === copper.pcb_component_id
2396
+ );
2397
+ const sourceComponent = pcbComponent?.type === "pcb_component" ? circuitJson.find(
2398
+ (element) => element.type === "source_component" && element.source_component_id === pcbComponent.source_component_id
2399
+ ) : void 0;
2400
+ const componentName = sourceComponent?.type === "source_component" && sourceComponent.name ? sourceComponent.name : getReadableNameForComponent(circuitJson, copper.pcb_component_id);
2401
+ return `component ${componentName}`;
2402
+ }
2403
+ return copper.type === "pcb_via" ? `via ${copper.pcb_via_id}` : `${copper.type} ${getPrimaryId2(copper)}`;
2404
+ };
2405
+ function checkPcbCopperOverKeepout(circuitJson) {
2406
+ const keepouts = cju3(circuitJson).pcb_keepout.list();
2407
+ if (keepouts.length === 0) return [];
2408
+ const copper = [
2409
+ ...getPads(circuitJson),
2410
+ ...cju3(circuitJson).pcb_via.list()
2411
+ ];
2412
+ const errors = /* @__PURE__ */ new Map();
2413
+ for (const keepout of keepouts) {
2414
+ const excludedComponentIds = new Set(
2415
+ keepout.excluded_pcb_component_ids ?? []
2416
+ );
2417
+ for (const copperElement of copper) {
2418
+ const copperComponentId = "pcb_component_id" in copperElement ? copperElement.pcb_component_id : void 0;
2419
+ if (copperComponentId && excludedComponentIds.has(copperComponentId)) {
2420
+ continue;
2421
+ }
2422
+ const copperLayers = getLayersOfPcbElement(copperElement);
2423
+ if (!copperLayers.some((layer) => keepout.layers.includes(layer))) {
2424
+ continue;
2425
+ }
2426
+ if (getPadToPadGap(copperElement, keepout) > EPSILON) continue;
2427
+ const ownerId = getErrorOwnerId(copperElement);
2428
+ const errorId = `copper_over_keepout_${ownerId}_${keepout.pcb_keepout_id}`;
2429
+ if (errors.has(errorId)) continue;
2430
+ errors.set(errorId, {
2431
+ type: "pcb_placement_error",
2432
+ pcb_placement_error_id: errorId,
2433
+ error_type: "pcb_placement_error",
2434
+ message: `Copper for ${getReadableCopperName(
2435
+ circuitJson,
2436
+ copperElement
2437
+ )} overlaps ${keepout.description ? `PCB keepout "${keepout.description}"` : "a PCB keepout"}`,
2438
+ subcircuit_id: copperElement.subcircuit_id ?? keepout.subcircuit_id
2439
+ });
2440
+ }
2441
+ }
2442
+ return [...errors.values()];
2443
+ }
2444
+
2343
2445
  // lib/check-same-net-via-spacing.ts
2344
2446
  import { getReadableNameForElement as getReadableNameForElement4 } from "@tscircuit/circuit-json-util";
2345
2447
  import {
@@ -2457,11 +2559,11 @@ function checkDifferentNetViaSpacing(circuitJson, {
2457
2559
  }
2458
2560
 
2459
2561
  // lib/check-source-traces-match-pcb-trace-thickness.ts
2460
- import { cju as cju3 } from "@tscircuit/circuit-json-util";
2562
+ import { cju as cju4 } from "@tscircuit/circuit-json-util";
2461
2563
  import { getFullConnectivityMapFromCircuitJson as getFullConnectivityMapFromCircuitJson5 } from "circuit-json-to-connectivity-map";
2462
2564
  function checkSourceTracesMatchPcbTraceThickness(circuitJson) {
2463
2565
  const warnings = [];
2464
- const db = cju3(circuitJson);
2566
+ const db = cju4(circuitJson);
2465
2567
  const sourceTraces = db.source_trace.list();
2466
2568
  const pcbTraces = db.pcb_trace.list();
2467
2569
  const pcbPorts = db.pcb_port.list();
@@ -2877,7 +2979,7 @@ function checkTracesAreContiguous(circuitJson) {
2877
2979
  }
2878
2980
 
2879
2981
  // lib/check-trace-out-of-board/checkTraceOutOfBoard.ts
2880
- import { cju as cju4 } from "@tscircuit/circuit-json-util";
2982
+ import { cju as cju5 } from "@tscircuit/circuit-json-util";
2881
2983
  import { segmentToSegmentMinDistance as segmentToSegmentMinDistance4 } from "@tscircuit/math-utils";
2882
2984
  function getBoardPolygonPoints(board) {
2883
2985
  if (board.outline && board.outline.length > 0) {
@@ -2908,7 +3010,7 @@ function checkPcbTracesOutOfBoard(circuitJson, config = {}) {
2908
3010
  const margin = config.margin ?? getBoardDrcValue(board, "min_board_edge_clearance") ?? jlcMinTolerances.min_board_edge_clearance;
2909
3011
  const boardPoints = getBoardPolygonPoints(board);
2910
3012
  if (!boardPoints) return errors;
2911
- const pcbTraces = cju4(circuitJson).pcb_trace.list();
3013
+ const pcbTraces = cju5(circuitJson).pcb_trace.list();
2912
3014
  for (const trace of pcbTraces) {
2913
3015
  if (trace.route.length < 2) continue;
2914
3016
  for (let i = 0; i < trace.route.length - 1; i++) {
@@ -2957,9 +3059,9 @@ function checkPcbTracesOutOfBoard(circuitJson, config = {}) {
2957
3059
 
2958
3060
  // lib/check-pcb-components-overlap/checkPcbComponentOverlap.ts
2959
3061
  import {
2960
- cju as cju5,
3062
+ cju as cju6,
2961
3063
  getBoundsOfPcbElements as getBoundsOfPcbElements5,
2962
- getPrimaryId as getPrimaryId2
3064
+ getPrimaryId as getPrimaryId3
2963
3065
  } from "@tscircuit/circuit-json-util";
2964
3066
  import { doBoundsOverlap as doBoundsOverlap3 } from "@tscircuit/math-utils";
2965
3067
  import { getFullConnectivityMapFromCircuitJson as getFullConnectivityMapFromCircuitJson7 } from "circuit-json-to-connectivity-map";
@@ -2995,20 +3097,20 @@ var formatOverlapElementDescription = (circuitJson, element) => {
2995
3097
  if ("pcb_port_id" in element && element.pcb_port_id) {
2996
3098
  return getReadableNameForPort(circuitJson, element.pcb_port_id);
2997
3099
  }
2998
- const id = getPrimaryId2(element);
3100
+ const id = getPrimaryId3(element);
2999
3101
  const readableName = getReadableNameForElementId(circuitJson, id);
3000
3102
  return readableName === "element" ? `[${id}]` : readableName;
3001
3103
  };
3002
3104
  function checkPcbComponentOverlap(circuitJson) {
3003
3105
  const errors = [];
3004
3106
  const connMap = getFullConnectivityMapFromCircuitJson7(circuitJson);
3005
- const smtPads = cju5(circuitJson).pcb_smtpad.list();
3006
- const platedHoles = cju5(circuitJson).pcb_plated_hole.list();
3007
- const holes = cju5(circuitJson).pcb_hole.list();
3107
+ const smtPads = cju6(circuitJson).pcb_smtpad.list();
3108
+ const platedHoles = cju6(circuitJson).pcb_plated_hole.list();
3109
+ const holes = cju6(circuitJson).pcb_hole.list();
3008
3110
  const courtyards = circuitJson.filter(isCourtyardElement);
3009
3111
  const componentMap = /* @__PURE__ */ new Map();
3010
3112
  for (const pad of smtPads) {
3011
- const componentId = pad.pcb_component_id || `standalone_pad_${getPrimaryId2(pad)}`;
3113
+ const componentId = pad.pcb_component_id || `standalone_pad_${getPrimaryId3(pad)}`;
3012
3114
  if (!componentMap.has(componentId)) {
3013
3115
  componentMap.set(componentId, {
3014
3116
  component_id: componentId,
@@ -3018,7 +3120,7 @@ function checkPcbComponentOverlap(circuitJson) {
3018
3120
  componentMap.get(componentId).elements.push(pad);
3019
3121
  }
3020
3122
  for (const hole of platedHoles) {
3021
- const componentId = hole.pcb_component_id || `standalone_plated_hole_${getPrimaryId2(hole)}`;
3123
+ const componentId = hole.pcb_component_id || `standalone_plated_hole_${getPrimaryId3(hole)}`;
3022
3124
  if (!componentMap.has(componentId)) {
3023
3125
  componentMap.set(componentId, {
3024
3126
  component_id: componentId,
@@ -3028,7 +3130,7 @@ function checkPcbComponentOverlap(circuitJson) {
3028
3130
  componentMap.get(componentId).elements.push(hole);
3029
3131
  }
3030
3132
  for (const hole of holes) {
3031
- const componentId = hole.pcb_component_id || `standalone_hole_${getPrimaryId2(hole)}`;
3133
+ const componentId = hole.pcb_component_id || `standalone_hole_${getPrimaryId3(hole)}`;
3032
3134
  if (!componentMap.has(componentId)) {
3033
3135
  componentMap.set(componentId, {
3034
3136
  component_id: componentId,
@@ -3064,8 +3166,8 @@ function checkPcbComponentOverlap(circuitJson) {
3064
3166
  }
3065
3167
  for (const elem1 of comp1.elements) {
3066
3168
  for (const elem2 of comp2.elements) {
3067
- const id1 = getPrimaryId2(elem1);
3068
- const id2 = getPrimaryId2(elem2);
3169
+ const id1 = getPrimaryId3(elem1);
3170
+ const id2 = getPrimaryId3(elem2);
3069
3171
  if ((isCourtyardElement(elem1) || isCourtyardElement(elem2)) && elem1.type !== "pcb_hole" && elem2.type !== "pcb_hole") {
3070
3172
  continue;
3071
3173
  }
@@ -3260,7 +3362,7 @@ var checkPcbTraceViaCounts = (circuitJson) => {
3260
3362
 
3261
3363
  // lib/check-pad-pad-clearance.ts
3262
3364
  import {
3263
- getPrimaryId as getPrimaryId3,
3365
+ getPrimaryId as getPrimaryId4,
3264
3366
  getReadableNameForElement as getReadableNameForElement6
3265
3367
  } from "@tscircuit/circuit-json-util";
3266
3368
  import { formatMm } from "format-si-unit";
@@ -3279,17 +3381,17 @@ function checkPadPadClearance(circuitJson, {
3279
3381
  const spatialIndex = new SpatialObjectIndex({
3280
3382
  objects: pads,
3281
3383
  getBounds: getPadBounds,
3282
- getId: (pad) => getPrimaryId3(pad)
3384
+ getId: (pad) => getPrimaryId4(pad)
3283
3385
  });
3284
3386
  const errors = /* @__PURE__ */ new Map();
3285
3387
  for (const padA of pads) {
3286
- const padAId = getPrimaryId3(padA);
3388
+ const padAId = getPrimaryId4(padA);
3287
3389
  const nearbyPads = spatialIndex.getObjectsInBounds(
3288
3390
  getPadBounds(padA),
3289
3391
  minClearance
3290
3392
  );
3291
3393
  for (const padB of nearbyPads) {
3292
- const padBId = getPrimaryId3(padB);
3394
+ const padBId = getPrimaryId4(padB);
3293
3395
  if (padAId === padBId) continue;
3294
3396
  if (!getLayersOfPcbElement(padA).some(
3295
3397
  (layer) => getLayersOfPcbElement(padB).includes(layer)
@@ -3325,7 +3427,7 @@ function checkPadPadClearance(circuitJson, {
3325
3427
 
3326
3428
  // lib/check-pad-trace-clearance.ts
3327
3429
  import {
3328
- getPrimaryId as getPrimaryId4,
3430
+ getPrimaryId as getPrimaryId5,
3329
3431
  getReadableNameForElement as getReadableNameForElement7
3330
3432
  } from "@tscircuit/circuit-json-util";
3331
3433
  import { formatMm as formatMm2 } from "format-si-unit";
@@ -3345,7 +3447,7 @@ function checkPadTraceClearance(circuitJson, {
3345
3447
  const spatialIndex = new SpatialObjectIndex({
3346
3448
  objects: pads,
3347
3449
  getBounds: getPadBounds,
3348
- getId: (pad) => getPrimaryId4(pad)
3450
+ getId: (pad) => getPrimaryId5(pad)
3349
3451
  });
3350
3452
  const errors = /* @__PURE__ */ new Map();
3351
3453
  const overlappingPairIds = /* @__PURE__ */ new Set();
@@ -3355,7 +3457,7 @@ function checkPadTraceClearance(circuitJson, {
3355
3457
  minClearance + segment.thickness / 2
3356
3458
  );
3357
3459
  for (const pad of nearbyPads) {
3358
- const padId = getPrimaryId4(pad);
3460
+ const padId = getPrimaryId5(pad);
3359
3461
  if (!getLayersOfPcbElement(pad).includes(segment.layer)) continue;
3360
3462
  if (connMap.areIdsConnected(segment.pcb_trace_id, padId)) continue;
3361
3463
  const pairId = `${padId}_${segment.pcb_trace_id}`;
@@ -3441,7 +3543,7 @@ function checkViaTraceClearance(circuitJson, {
3441
3543
 
3442
3544
  // lib/check-via-pad-clearance.ts
3443
3545
  import {
3444
- getPrimaryId as getPrimaryId5,
3546
+ getPrimaryId as getPrimaryId6,
3445
3547
  getReadableNameForElement as getReadableNameForElement9
3446
3548
  } from "@tscircuit/circuit-json-util";
3447
3549
  import { formatMm as formatMm4 } from "format-si-unit";
@@ -3463,7 +3565,7 @@ function checkViaPadClearance(circuitJson, {
3463
3565
  const padIndex = new SpatialObjectIndex({
3464
3566
  objects: pads,
3465
3567
  getBounds: getPadBounds,
3466
- getId: getPrimaryId5
3568
+ getId: getPrimaryId6
3467
3569
  });
3468
3570
  const errors = [];
3469
3571
  for (const via of vias) {
@@ -3472,7 +3574,7 @@ function checkViaPadClearance(circuitJson, {
3472
3574
  requiredClearance
3473
3575
  );
3474
3576
  for (const pad of nearbyPads) {
3475
- const padId = getPrimaryId5(pad);
3577
+ const padId = getPrimaryId6(pad);
3476
3578
  if (!getLayersOfPcbElement(via).some(
3477
3579
  (layer) => getLayersOfPcbElement(pad).includes(layer)
3478
3580
  )) {
@@ -3502,7 +3604,7 @@ function checkViaPadClearance(circuitJson, {
3502
3604
  }
3503
3605
 
3504
3606
  // lib/check-vias-in-pads.ts
3505
- import { getPrimaryId as getPrimaryId6 } from "@tscircuit/circuit-json-util";
3607
+ import { getPrimaryId as getPrimaryId7 } from "@tscircuit/circuit-json-util";
3506
3608
  function checkViasInPads(circuitJson) {
3507
3609
  const board = getPcbBoard(circuitJson);
3508
3610
  if (board && "is_via_in_pad_allowed" in board && board.is_via_in_pad_allowed === true) {
@@ -3514,12 +3616,12 @@ function checkViasInPads(circuitJson) {
3514
3616
  const pads = getPads(circuitJson);
3515
3617
  if (vias.length === 0 || pads.length === 0) return [];
3516
3618
  const padOrdinals = new Map(
3517
- pads.map((pad, index) => [getPrimaryId6(pad), index])
3619
+ pads.map((pad, index) => [getPrimaryId7(pad), index])
3518
3620
  );
3519
3621
  const padIndex = new SpatialObjectIndex({
3520
3622
  objects: pads,
3521
3623
  getBounds: getPadBounds,
3522
- getId: getPrimaryId6
3624
+ getId: getPrimaryId7
3523
3625
  });
3524
3626
  const errors = [];
3525
3627
  for (const via of vias) {
@@ -3534,7 +3636,7 @@ function checkViasInPads(circuitJson) {
3534
3636
  const padLayers = getLayersOfPcbElement(pad);
3535
3637
  if (!viaLayers.some((layer) => padLayers.includes(layer))) continue;
3536
3638
  if (!isPointInPad(via, pad)) continue;
3537
- const padId = getPrimaryId6(pad);
3639
+ const padId = getPrimaryId7(pad);
3538
3640
  const padOrdinal = padOrdinals.get(padId) ?? 0;
3539
3641
  const padName = getReadableNameForFootprintPad(
3540
3642
  circuitJson,
@@ -3633,7 +3735,7 @@ function checkPinMustBeConnected(circuitJson) {
3633
3735
  }
3634
3736
 
3635
3737
  // lib/check-all-pins-in-component-are-underspecified.ts
3636
- import { cju as cju6 } from "@tscircuit/circuit-json-util";
3738
+ import { cju as cju7 } from "@tscircuit/circuit-json-util";
3637
3739
  var PIN_ATTRIBUTE_KEYS = [
3638
3740
  "must_be_connected",
3639
3741
  "provides_power",
@@ -3678,7 +3780,7 @@ function hasAnyPinAttribute(port) {
3678
3780
  }
3679
3781
  function checkAllPinsInComponentAreUnderspecified(circuitJson) {
3680
3782
  const warnings = [];
3681
- const db = cju6(circuitJson);
3783
+ const db = cju7(circuitJson);
3682
3784
  const sourceComponents = db.source_component.list();
3683
3785
  const sourcePorts = db.source_port.list();
3684
3786
  const portsByComponent = /* @__PURE__ */ new Map();
@@ -3710,10 +3812,10 @@ function checkAllPinsInComponentAreUnderspecified(circuitJson) {
3710
3812
  }
3711
3813
 
3712
3814
  // lib/check-no-power-pin-defined.ts
3713
- import { cju as cju7 } from "@tscircuit/circuit-json-util";
3815
+ import { cju as cju8 } from "@tscircuit/circuit-json-util";
3714
3816
  function checkNoPowerPinDefined(circuitJson) {
3715
3817
  const warnings = [];
3716
- const db = cju7(circuitJson);
3818
+ const db = cju8(circuitJson);
3717
3819
  const sourceComponents = db.source_component.list();
3718
3820
  const sourcePorts = db.source_port.list();
3719
3821
  const portsByComponent = /* @__PURE__ */ new Map();
@@ -3745,10 +3847,10 @@ function checkNoPowerPinDefined(circuitJson) {
3745
3847
  }
3746
3848
 
3747
3849
  // lib/check-no-ground-pin-defined.ts
3748
- import { cju as cju8 } from "@tscircuit/circuit-json-util";
3850
+ import { cju as cju9 } from "@tscircuit/circuit-json-util";
3749
3851
  function checkNoGroundPinDefined(circuitJson) {
3750
3852
  const warnings = [];
3751
- const db = cju8(circuitJson);
3853
+ const db = cju9(circuitJson);
3752
3854
  const sourceComponents = db.source_component.list();
3753
3855
  const sourcePorts = db.source_port.list();
3754
3856
  const portsByComponent = /* @__PURE__ */ new Map();
@@ -4124,6 +4226,7 @@ async function runAllPlacementChecks(circuitJson) {
4124
4226
  ...checkViasInPads(circuitJson),
4125
4227
  ...checkPcbComponentsOutOfBoard(circuitJson),
4126
4228
  ...checkPcbComponentOverCutout(circuitJson),
4229
+ ...checkPcbCopperOverKeepout(circuitJson),
4127
4230
  ...checkPcbComponentOverlap(circuitJson),
4128
4231
  ...checkPcbComponentsMissingCourtyard(circuitJson),
4129
4232
  ...checkPadPadClearance(circuitJson),
@@ -4186,6 +4289,7 @@ export {
4186
4289
  checkPcbComponentOverlap,
4187
4290
  checkPcbComponentsMissingCourtyard,
4188
4291
  checkPcbComponentsOutOfBoard,
4292
+ checkPcbCopperOverKeepout,
4189
4293
  checkPcbTraceLengths,
4190
4294
  checkPcbTraceViaCounts,
4191
4295
  checkPcbTracesOutOfBoard,