@tscircuit/checks 0.0.199 → 0.0.200

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
@@ -1,5 +1,5 @@
1
1
  import * as circuit_json from 'circuit-json';
2
- import { AnyCircuitElement, PcbPlacementError, PcbPortNotConnectedError, PcbTraceError, PcbComponentOutsideBoardError, PcbViaClearanceError, PcbTraceWarning, PcbTraceMissingError, PcbFootprintOverlapError, PcbPadPadClearanceError, PcbCourtyardOverlapError, PcbComponentMissingCourtyardWarning, PcbTraceTooLongWarning, PcbPadTraceClearanceError, PcbViaTraceClearanceError, SourceComponentMisconfiguredError, SourceComponentPinsUnderspecifiedWarning, SourceNoPowerPinDefinedWarning, SourceNoGroundPinDefinedWarning, SchematicComponentStylingWarning, PcbConnectorNotInAccessibleOrientationWarning, SourceConfusingNetNameWarning } from 'circuit-json';
2
+ import { AnyCircuitElement, PcbPlacementError, PcbPortNotConnectedError, PcbTraceError, PcbComponentOutsideBoardError, PcbViaClearanceError, PcbTraceWarning, PcbTraceMissingError, PcbFootprintOverlapError, PcbPadPadClearanceError, PcbCourtyardOverlapError, PcbComponentMissingCourtyardWarning, PcbTraceTooLongError, PcbPadTraceClearanceError, PcbViaTraceClearanceError, SourceComponentMisconfiguredError, SourceComponentPinsUnderspecifiedWarning, SourceNoPowerPinDefinedWarning, SourceNoGroundPinDefinedWarning, SchematicComponentStylingWarning, PcbConnectorNotInAccessibleOrientationWarning, SourceConfusingNetNameWarning, PcbBusLengthSkewError } from 'circuit-json';
3
3
  import { ConnectivityMap } from 'circuit-json-to-connectivity-map';
4
4
 
5
5
  /** Detect accidental copper contact, rather than enforcing a clearance margin. */
@@ -105,7 +105,7 @@ declare function checkPcbComponentOverlap(circuitJson: AnyCircuitElement[]): Pcb
105
105
  /** Returns warnings for PCB components without courtyards, excluding manually placed vias. */
106
106
  declare function checkPcbComponentsMissingCourtyard(circuitJson: AnyCircuitElement[]): PcbComponentMissingCourtyardWarning[];
107
107
 
108
- declare const checkPcbTraceLengths: (circuitJson: AnyCircuitElement[]) => PcbTraceTooLongWarning[];
108
+ declare const checkPcbTraceLengths: (circuitJson: AnyCircuitElement[]) => PcbTraceTooLongError[];
109
109
 
110
110
  /** Return a routing error when a source trace exceeds its maximum via count. */
111
111
  declare const checkPcbTraceViaCounts: (circuitJson: AnyCircuitElement[]) => PcbTraceError[];
@@ -216,8 +216,8 @@ declare function runAllNetlistChecks(circuitJson: AnyCircuitElement[]): Promise<
216
216
  } | circuit_json.SourceComponentMisconfiguredError | circuit_json.SourceConfusingNetNameWarning)[]>;
217
217
  declare function runAllSchematicChecks(circuitJson: AnyCircuitElement[]): Promise<circuit_json.SchematicComponentStylingWarning[]>;
218
218
  declare function runAllPinSpecificationChecks(circuitJson: AnyCircuitElement[]): Promise<(circuit_json.SourceComponentPinsUnderspecifiedWarning | circuit_json.SourceNoPowerPinDefinedWarning | circuit_json.SourceNoGroundPinDefinedWarning)[]>;
219
- declare function runAllRoutingChecks(circuitJson: AnyCircuitElement[]): Promise<(circuit_json.PcbPlacementError | circuit_json.PcbPortNotConnectedError | circuit_json.PcbTraceError | circuit_json.PcbViaClearanceError | circuit_json.PcbTraceMissingError | circuit_json.PcbPadPadClearanceError | circuit_json.PcbTraceTooLongWarning | circuit_json.PcbPadTraceClearanceError | circuit_json.PcbViaTraceClearanceError)[]>;
220
- declare function runAllChecks(circuitJson: AnyCircuitElement[]): Promise<(circuit_json.PcbPlacementError | circuit_json.PcbPortNotConnectedError | circuit_json.PcbTraceError | circuit_json.PcbComponentOutsideBoardError | circuit_json.PcbViaClearanceError | circuit_json.PcbTraceMissingError | PcbComponentOverlapError | circuit_json.PcbPadPadClearanceError | circuit_json.PcbCourtyardOverlapError | circuit_json.PcbComponentMissingCourtyardWarning | circuit_json.PcbTraceTooLongWarning | circuit_json.PcbPadTraceClearanceError | circuit_json.PcbViaTraceClearanceError | {
219
+ declare function runAllRoutingChecks(circuitJson: AnyCircuitElement[]): Promise<(circuit_json.PcbPlacementError | circuit_json.PcbPortNotConnectedError | circuit_json.PcbTraceError | circuit_json.PcbViaClearanceError | circuit_json.PcbTraceMissingError | circuit_json.PcbPadPadClearanceError | circuit_json.PcbTraceTooLongError | circuit_json.PcbPadTraceClearanceError | circuit_json.PcbViaTraceClearanceError | circuit_json.PcbBusLengthSkewError)[]>;
220
+ declare function runAllChecks(circuitJson: AnyCircuitElement[]): Promise<(circuit_json.PcbPlacementError | circuit_json.PcbPortNotConnectedError | circuit_json.PcbTraceError | circuit_json.PcbComponentOutsideBoardError | circuit_json.PcbViaClearanceError | circuit_json.PcbTraceMissingError | PcbComponentOverlapError | circuit_json.PcbPadPadClearanceError | circuit_json.PcbCourtyardOverlapError | circuit_json.PcbComponentMissingCourtyardWarning | circuit_json.PcbTraceTooLongError | circuit_json.PcbPadTraceClearanceError | circuit_json.PcbViaTraceClearanceError | {
221
221
  type: "source_pin_must_be_connected_error";
222
222
  source_pin_must_be_connected_error_id: string;
223
223
  error_type: "source_pin_must_be_connected_error";
@@ -225,7 +225,7 @@ declare function runAllChecks(circuitJson: AnyCircuitElement[]): Promise<(circui
225
225
  source_component_id: string;
226
226
  source_port_id: string;
227
227
  subcircuit_id?: string;
228
- } | circuit_json.SourceComponentMisconfiguredError | circuit_json.SourceComponentPinsUnderspecifiedWarning | circuit_json.SourceNoPowerPinDefinedWarning | circuit_json.SourceNoGroundPinDefinedWarning | circuit_json.SchematicComponentStylingWarning | circuit_json.SourceConfusingNetNameWarning | circuit_json.PcbConnectorNotInAccessibleOrientationWarning)[]>;
228
+ } | circuit_json.SourceComponentMisconfiguredError | circuit_json.SourceComponentPinsUnderspecifiedWarning | circuit_json.SourceNoPowerPinDefinedWarning | circuit_json.SourceNoGroundPinDefinedWarning | circuit_json.SchematicComponentStylingWarning | circuit_json.PcbBusLengthSkewError | circuit_json.SourceConfusingNetNameWarning | circuit_json.PcbConnectorNotInAccessibleOrientationWarning)[]>;
229
229
 
230
230
  declare function checkConnectorAccessibleOrientation(circuitJson: AnyCircuitElement[]): PcbConnectorNotInAccessibleOrientationWarning[];
231
231
 
@@ -239,4 +239,9 @@ declare function checkTestPointAccessibility(circuitJson: AnyCircuitElement[]):
239
239
  /** Warn once per name when its source nets belong to multiple electrical islands. */
240
240
  declare function checkSameNameNetsAreConnected(circuitJson: AnyCircuitElement[]): SourceConfusingNetNameWarning[];
241
241
 
242
- export { NetManager, type PcbComponentOverlapError, checkAllPinsInComponentAreUnderspecified, checkConnectorAccessibleOrientation, checkCopperPourShorts, 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, consolidatePcbOverlapErrors, dedupePcbDrcErrors, runAllChecks, runAllNetlistChecks, runAllPinSpecificationChecks, runAllPlacementChecks, runAllRoutingChecks, runAllSchematicChecks };
242
+ /** Compare total routed lengths of resolved bus members. Unrouted members are
243
+ * left to connectivity checks, never treated as zero-length routes.
244
+ */
245
+ declare const checkPcbBusLengthSkew: (circuitJson: AnyCircuitElement[]) => PcbBusLengthSkewError[];
246
+
247
+ export { NetManager, type PcbComponentOverlapError, checkAllPinsInComponentAreUnderspecified, checkConnectorAccessibleOrientation, checkCopperPourShorts, checkCopperToBoardEdgeClearance, checkDifferentNetViaSpacing, checkEachPcbPortConnectedToPcbTraces, checkEachPcbTraceNonOverlapping, checkNoGroundPinDefined, checkNoPowerPinDefined, checkPadPadClearance, checkPadTraceClearance, checkPcbBusLengthSkew, checkPcbComponentOverCutout, checkPcbComponentOverlap, checkPcbComponentsMissingCourtyard, checkPcbComponentsOutOfBoard, checkPcbCopperOverKeepout, checkPcbTraceLengths, checkPcbTraceViaCounts, checkPcbTracesOutOfBoard, checkPinMustBeConnected, checkSameNameNetsAreConnected, checkSameNetViaSpacing, checkSchematicComponentExcessiveVerticalPadding, checkSchematicComponentMissingReferenceDesignatorText, checkSchematicComponentPortsOutsideBody, checkSourceTracesHavePcbTraces, checkSourceTracesMatchPcbTraceThickness, checkTestPointAccessibility, checkTracesAreContiguous, checkTwoTerminalSwitchContactsOnDifferentNets, checkViaPadClearance, checkViaTraceClearance, checkViasInPads, checkViasOffBoard, consolidatePcbOverlapErrors, dedupePcbDrcErrors, runAllChecks, runAllNetlistChecks, runAllPinSpecificationChecks, runAllPlacementChecks, runAllRoutingChecks, runAllSchematicChecks };
package/dist/index.js CHANGED
@@ -4137,30 +4137,30 @@ function checkPcbComponentsMissingCourtyard(circuitJson) {
4137
4137
  });
4138
4138
  }
4139
4139
 
4140
- // lib/check-pcb-trace-lengths.ts
4141
- var DEFAULT_VIA_LENGTH_MM = 1.6;
4142
- var getRoutePointPosition = (routePoint) => routePoint.route_type === "through_pad" ? routePoint.start : { x: routePoint.x, y: routePoint.y };
4143
- var getPcbTraceLength = (pcbTrace) => {
4144
- if (pcbTrace.trace_length !== void 0) return pcbTrace.trace_length;
4145
- let traceLength = 0;
4146
- for (let routePointIndex = 0; routePointIndex < pcbTrace.route.length; routePointIndex++) {
4147
- const routePoint = pcbTrace.route[routePointIndex];
4148
- if (!routePoint) continue;
4149
- if (routePoint.route_type === "via") {
4150
- traceLength += DEFAULT_VIA_LENGTH_MM;
4151
- continue;
4140
+ // lib/util/get-pcb-trace-length.ts
4141
+ var getPcbTraceLength = (trace) => {
4142
+ if (trace.trace_length !== void 0) return trace.trace_length;
4143
+ let length = 0;
4144
+ let previousEnd;
4145
+ for (const point2 of trace.route) {
4146
+ const start = point2.route_type === "through_pad" ? point2.start : point2;
4147
+ if (previousEnd)
4148
+ length += Math.hypot(start.x - previousEnd.x, start.y - previousEnd.y);
4149
+ if (point2.route_type === "via") length += 1.6;
4150
+ if (point2.route_type === "through_pad") {
4151
+ length += Math.hypot(
4152
+ point2.end.x - point2.start.x,
4153
+ point2.end.y - point2.start.y
4154
+ );
4155
+ previousEnd = point2.end;
4156
+ } else {
4157
+ previousEnd = point2;
4152
4158
  }
4153
- const nextRoutePoint = pcbTrace.route[routePointIndex + 1];
4154
- if (!nextRoutePoint) continue;
4155
- const routePointPosition = getRoutePointPosition(routePoint);
4156
- const nextRoutePointPosition = getRoutePointPosition(nextRoutePoint);
4157
- traceLength += Math.hypot(
4158
- nextRoutePointPosition.x - routePointPosition.x,
4159
- nextRoutePointPosition.y - routePointPosition.y
4160
- );
4161
4159
  }
4162
- return traceLength;
4160
+ return length;
4163
4161
  };
4162
+
4163
+ // lib/check-pcb-trace-lengths.ts
4164
4164
  var getReferencedPcbPortIds = (pcbTrace) => {
4165
4165
  const pcbPortIds = /* @__PURE__ */ new Set();
4166
4166
  for (const routePoint of pcbTrace.route) {
@@ -4174,7 +4174,7 @@ var getReferencedPcbPortIds = (pcbTrace) => {
4174
4174
  }
4175
4175
  return pcbPortIds;
4176
4176
  };
4177
- var checkPcbTraceLengths = (circuitJson) => {
4177
+ var getPcbTracesBySourceTraceId = (circuitJson) => {
4178
4178
  const sourceTraces = circuitJson.filter(
4179
4179
  (element) => element.type === "source_trace"
4180
4180
  );
@@ -4184,12 +4184,6 @@ var checkPcbTraceLengths = (circuitJson) => {
4184
4184
  const pcbPorts = circuitJson.filter(
4185
4185
  (element) => element.type === "pcb_port"
4186
4186
  );
4187
- const sourceTracesById = new Map(
4188
- sourceTraces.map((sourceTrace) => [
4189
- sourceTrace.source_trace_id,
4190
- sourceTrace
4191
- ])
4192
- );
4193
4187
  const pcbPortIdsBySourcePortId = /* @__PURE__ */ new Map();
4194
4188
  for (const pcbPort of pcbPorts) {
4195
4189
  if (!pcbPort.source_port_id) continue;
@@ -4228,23 +4222,35 @@ var checkPcbTraceLengths = (circuitJson) => {
4228
4222
  );
4229
4223
  }
4230
4224
  }
4231
- const warnings = [];
4232
- for (const pcbTrace of pcbTraces) {
4233
- if (!pcbTrace.source_trace_id) continue;
4234
- const sourceTrace = sourceTracesById.get(pcbTrace.source_trace_id);
4225
+ for (const [id, exactIds] of exactEndpointPcbTraceIdsBySourceTraceId) {
4226
+ pcbTracesBySourceTraceId.set(
4227
+ id,
4228
+ pcbTracesBySourceTraceId.get(id).filter((trace) => exactIds.has(trace.pcb_trace_id))
4229
+ );
4230
+ }
4231
+ return pcbTracesBySourceTraceId;
4232
+ };
4233
+ var checkPcbTraceLengths = (circuitJson) => {
4234
+ const sourceTracesById = new Map(
4235
+ circuitJson.filter((e) => e.type === "source_trace").map((e) => [e.source_trace_id, e])
4236
+ );
4237
+ const pcbTracesBySourceTraceId = getPcbTracesBySourceTraceId(circuitJson);
4238
+ const errors = [];
4239
+ for (const [sourceTraceId, pcbTraces] of pcbTracesBySourceTraceId) {
4240
+ const pcbTrace = pcbTraces[0];
4241
+ const sourceTrace = sourceTracesById.get(sourceTraceId);
4235
4242
  if (!sourceTrace) continue;
4236
4243
  const maximumTraceLength = sourceTrace.max_length;
4237
4244
  if (typeof maximumTraceLength !== "number") continue;
4238
- const exactEndpointPcbTraceIds = exactEndpointPcbTraceIdsBySourceTraceId.get(sourceTrace.source_trace_id);
4239
- if (exactEndpointPcbTraceIds && !exactEndpointPcbTraceIds.has(pcbTrace.pcb_trace_id)) {
4240
- continue;
4241
- }
4242
- const actualTraceLength = getPcbTraceLength(pcbTrace);
4243
- if (actualTraceLength <= maximumTraceLength) continue;
4244
- warnings.push({
4245
- type: "pcb_trace_too_long_warning",
4246
- pcb_trace_too_long_warning_id: `pcb_trace_too_long_warning_${pcbTrace.pcb_trace_id}`,
4247
- warning_type: "pcb_trace_too_long_warning",
4245
+ const actualTraceLength = pcbTraces.reduce(
4246
+ (sum, trace) => sum + getPcbTraceLength(trace),
4247
+ 0
4248
+ );
4249
+ if (actualTraceLength <= maximumTraceLength + 1e-9) continue;
4250
+ errors.push({
4251
+ type: "pcb_trace_too_long_error",
4252
+ pcb_trace_too_long_error_id: `pcb_trace_too_long_error_${pcbTrace.pcb_trace_id}`,
4253
+ error_type: "pcb_trace_too_long_error",
4248
4254
  message: `PCB trace is ${actualTraceLength.toFixed(2)}mm long, exceeding the ${maximumTraceLength}mm maximum`,
4249
4255
  pcb_trace_id: pcbTrace.pcb_trace_id,
4250
4256
  source_trace_id: sourceTrace.source_trace_id,
@@ -4254,7 +4260,7 @@ var checkPcbTraceLengths = (circuitJson) => {
4254
4260
  subcircuit_id: pcbTrace.subcircuit_id ?? sourceTrace.subcircuit_id
4255
4261
  });
4256
4262
  }
4257
- return warnings;
4263
+ return errors;
4258
4264
  };
4259
4265
 
4260
4266
  // lib/check-pcb-trace-via-counts.ts
@@ -5119,6 +5125,47 @@ function checkSchematicComponentPortsOutsideBody(circuitJson) {
5119
5125
  return warnings;
5120
5126
  }
5121
5127
 
5128
+ // lib/check-pcb-bus-length-skew.ts
5129
+ var checkPcbBusLengthSkew = (circuitJson) => {
5130
+ const buses = circuitJson.filter(
5131
+ (e) => e.type === "source_bus"
5132
+ );
5133
+ const tracesBySource = getPcbTracesBySourceTraceId(circuitJson);
5134
+ const errors = [];
5135
+ for (const bus of buses) {
5136
+ if (bus.max_length_skew === void 0) continue;
5137
+ const members = [...new Set(bus.source_trace_ids)].flatMap((id) => {
5138
+ const traces = tracesBySource.get(id)?.filter((t) => t.trace_length !== void 0 || t.route.length > 1);
5139
+ if (!traces?.length) return [];
5140
+ return [
5141
+ {
5142
+ id,
5143
+ traces,
5144
+ length: traces.reduce((sum, t) => sum + getPcbTraceLength(t), 0)
5145
+ }
5146
+ ];
5147
+ });
5148
+ if (members.length < 2) continue;
5149
+ const skew = Math.max(...members.map((m) => m.length)) - Math.min(...members.map((m) => m.length));
5150
+ if (skew <= bus.max_length_skew + 1e-9) continue;
5151
+ errors.push({
5152
+ type: "pcb_bus_length_skew_error",
5153
+ pcb_bus_length_skew_error_id: `pcb_bus_length_skew_error_${bus.source_bus_id}`,
5154
+ error_type: "pcb_bus_length_skew_error",
5155
+ message: `PCB bus ${bus.name ?? bus.source_bus_id} has ${skew.toFixed(2)}mm length skew, exceeding the ${bus.max_length_skew}mm maximum`,
5156
+ source_bus_id: bus.source_bus_id,
5157
+ source_trace_ids: members.map((m) => m.id),
5158
+ pcb_trace_ids: members.flatMap(
5159
+ (m) => m.traces.map((t) => t.pcb_trace_id)
5160
+ ),
5161
+ actual_length_skew: skew,
5162
+ maximum_length_skew: bus.max_length_skew,
5163
+ subcircuit_id: bus.subcircuit_id
5164
+ });
5165
+ }
5166
+ return errors;
5167
+ };
5168
+
5122
5169
  // lib/consolidate-pcb-overlap-errors.ts
5123
5170
  import { getPrimaryId as getPrimaryId10 } from "@tscircuit/circuit-json-util";
5124
5171
  function consolidatePcbOverlapErrors(circuitJson, errors) {
@@ -5607,6 +5654,7 @@ async function runAllRoutingChecks(circuitJson) {
5607
5654
  ...checkEachPcbPortConnectedToPcbTraces(circuitJson),
5608
5655
  ...checkSourceTracesHavePcbTraces(circuitJson),
5609
5656
  ...checkPcbTraceLengths(circuitJson),
5657
+ ...checkPcbBusLengthSkew(circuitJson),
5610
5658
  ...checkPcbTraceViaCounts(circuitJson),
5611
5659
  ...checkEachPcbTraceNonOverlapping(circuitJson),
5612
5660
  ...checkCopperPourShorts(circuitJson),
@@ -5641,6 +5689,7 @@ export {
5641
5689
  checkNoPowerPinDefined,
5642
5690
  checkPadPadClearance,
5643
5691
  checkPadTraceClearance,
5692
+ checkPcbBusLengthSkew,
5644
5693
  checkPcbComponentOverCutout,
5645
5694
  checkPcbComponentOverlap,
5646
5695
  checkPcbComponentsMissingCourtyard,