From 468df697dc225233446c067ccfa804ff01a02dc0 Mon Sep 17 00:00:00 2001 From: seveibar Date: Wed, 22 Jul 2026 21:31:57 -0700 Subject: [PATCH 1/5] Propagate crystal trace length constraints across nets --- lib/components/normal-components/Board.ts | 5 ++ ...up_doInitialSourceAddConnectivityMapKey.ts | 11 ++- ...pagate-crystal-trace-length-constraints.ts | 74 +++++++++++++++++++ ...et-max-length-from-connected-components.ts | 45 ++++++++--- .../crystal-custom-trace-length.test.tsx | 40 ++++++++++ .../crystal-trace-too-long-warning.test.tsx | 57 ++++++++------ 6 files changed, 193 insertions(+), 39 deletions(-) create mode 100644 lib/components/primitive-components/Group/propagate-crystal-trace-length-constraints.ts create mode 100644 tests/components/normal-components/crystal-custom-trace-length.test.tsx diff --git a/lib/components/normal-components/Board.ts b/lib/components/normal-components/Board.ts index a2f6cb198..a62ee776a 100644 --- a/lib/components/normal-components/Board.ts +++ b/lib/components/normal-components/Board.ts @@ -21,6 +21,7 @@ import { Group } from "../primitive-components/Group/Group" import type { SubcircuitI } from "../primitive-components/Group/Subcircuit/SubcircuitI" import { Subcircuit_doInitialRenderIsolatedSubcircuits } from "../primitive-components/Group/Subcircuit/Subcircuit_doInitialRenderIsolatedSubcircuits" import { Subcircuit_getSubcircuitPropHash } from "../primitive-components/Group/Subcircuit_getSubcircuitPropHash" +import { insertPcbTraceTooLongWarnings } from "../primitive-components/Group/insert-pcb-trace-too-long-warnings" import type { BoardI } from "./BoardI" import { Board_doInitialPcbPlacementDesignRuleChecks } from "./Board_doInitialPcbPlacementDesignRuleChecks" @@ -695,6 +696,10 @@ export class Board this._queueAsyncEffect("board:drc-checks", async () => { try { await runDrcChecks(subcircuitCircuitJson) + insertPcbTraceTooLongWarnings({ + db, + subcircuitId: this.subcircuit_id!, + }) this._drcChecksComplete = true } finally { this._drcChecksInProgress = false diff --git a/lib/components/primitive-components/Group/Group_doInitialSourceAddConnectivityMapKey.ts b/lib/components/primitive-components/Group/Group_doInitialSourceAddConnectivityMapKey.ts index 62a8f5c8b..23ffc1070 100644 --- a/lib/components/primitive-components/Group/Group_doInitialSourceAddConnectivityMapKey.ts +++ b/lib/components/primitive-components/Group/Group_doInitialSourceAddConnectivityMapKey.ts @@ -1,15 +1,16 @@ -import { ConnectivityMap } from "circuit-json-to-connectivity-map" -import type { Group } from "./Group" import type { SourceTrace } from "circuit-json" -import type { TraceI } from "../Trace/TraceI" +import { ConnectivityMap } from "circuit-json-to-connectivity-map" +import type { Trace } from "../Trace/Trace" import type { Via } from "../Via" +import type { Group } from "./Group" +import { propagateCrystalTraceLengthConstraints } from "./propagate-crystal-trace-length-constraints" export function Group_doInitialSourceAddConnectivityMapKey(group: Group) { if (!group.isSubcircuit) return const { db } = group.root! // Find all traces that belong to this subcircuit, generate a connectivity // map, and add source_trace.subcircuit_connectivity_map_key - const traces = group.selectAll("trace") as TraceI[] + const traces = group.selectAll("trace") as Trace[] const vias = group.selectAll("via") as Via[] const nets = group.selectAll("net") as any[] const connMap = new ConnectivityMap({}) @@ -52,6 +53,8 @@ export function Group_doInitialSourceAddConnectivityMapKey(group: Group) { }) } + propagateCrystalTraceLengthConstraints({ db, traces }) + // Update source_port.subcircuit_connectivity_map_key for ports connected to the same net const allSourcePortIds = new Set() for (const trace of traces) { diff --git a/lib/components/primitive-components/Group/propagate-crystal-trace-length-constraints.ts b/lib/components/primitive-components/Group/propagate-crystal-trace-length-constraints.ts new file mode 100644 index 000000000..d60954850 --- /dev/null +++ b/lib/components/primitive-components/Group/propagate-crystal-trace-length-constraints.ts @@ -0,0 +1,74 @@ +import type { CircuitJsonUtilObjects } from "@tscircuit/circuit-json-util" +import type { SourceTrace } from "circuit-json" +import type { Trace } from "../Trace/Trace" +import { getMaxLengthFromConnectedCrystals } from "../Trace/trace-utils/get-max-length-from-connected-components" + +type SubcircuitConnectivityMapKey = NonNullable< + SourceTrace["subcircuit_connectivity_map_key"] +> + +export const propagateCrystalTraceLengthConstraints = ({ + db, + traces, +}: { + db: CircuitJsonUtilObjects + traces: Trace[] +}) => { + const crystalMaxLengthsBySubcircuitConnectivityMapKey = new Map< + SubcircuitConnectivityMapKey, + number + >() + + for (const trace of traces) { + if (!trace.source_trace_id) continue + + const sourceTrace = db.source_trace.get(trace.source_trace_id) + const subcircuitConnectivityMapKey = + sourceTrace?.subcircuit_connectivity_map_key + if (!subcircuitConnectivityMapKey) continue + + const connectedPorts = trace._findConnectedPorts().ports + if (!connectedPorts) continue + + const crystalMaxLength = getMaxLengthFromConnectedCrystals(connectedPorts, { + db, + }) + if (crystalMaxLength === undefined) continue + + const existingCrystalMaxLength = + crystalMaxLengthsBySubcircuitConnectivityMapKey.get( + subcircuitConnectivityMapKey, + ) + crystalMaxLengthsBySubcircuitConnectivityMapKey.set( + subcircuitConnectivityMapKey, + existingCrystalMaxLength === undefined + ? crystalMaxLength + : Math.min(existingCrystalMaxLength, crystalMaxLength), + ) + } + + for (const trace of traces) { + if (!trace.source_trace_id) continue + + const sourceTrace = db.source_trace.get(trace.source_trace_id) + const subcircuitConnectivityMapKey = + sourceTrace?.subcircuit_connectivity_map_key + if (!sourceTrace || !subcircuitConnectivityMapKey) continue + + const crystalMaxLength = + crystalMaxLengthsBySubcircuitConnectivityMapKey.get( + subcircuitConnectivityMapKey, + ) + if ( + crystalMaxLength === undefined || + (sourceTrace.max_length != null && + sourceTrace.max_length <= crystalMaxLength) + ) { + continue + } + + db.source_trace.update(sourceTrace.source_trace_id, { + max_length: crystalMaxLength, + }) + } +} diff --git a/lib/components/primitive-components/Trace/trace-utils/get-max-length-from-connected-components.ts b/lib/components/primitive-components/Trace/trace-utils/get-max-length-from-connected-components.ts index b92290e1d..7ea84dc8a 100644 --- a/lib/components/primitive-components/Trace/trace-utils/get-max-length-from-connected-components.ts +++ b/lib/components/primitive-components/Trace/trace-utils/get-max-length-from-connected-components.ts @@ -1,6 +1,34 @@ import type { CircuitJsonUtilObjects } from "@tscircuit/circuit-json-util" import type { Port } from "../../Port" +export const getMaxLengthFromConnectedCrystals = ( + ports: Port[], + { db }: { db: CircuitJsonUtilObjects }, +): number | undefined => { + const crystalMaxLengths = ports + .map((port) => { + const sourcePort = db.source_port.get(port.source_port_id!) + if (!sourcePort?.source_component_id) return null + + const sourceComponent = db.source_component.get( + sourcePort.source_component_id, + ) + if (sourceComponent?.ftype !== "simple_crystal") return null + + const crystalProps = ( + port.parent as unknown as { + _parsedProps?: { maxTraceLength?: number } + } + )?._parsedProps + + return crystalProps?.maxTraceLength ?? 10 + }) + .filter((length): length is number => typeof length === "number") + + if (crystalMaxLengths.length === 0) return undefined + return Math.min(...crystalMaxLengths) +} + export const getMaxLengthFromConnectedComponents = ( ports: Port[], { db }: { db: CircuitJsonUtilObjects }, @@ -18,19 +46,14 @@ export const getMaxLengthFromConnectedComponents = ( return sourceComponent.max_decoupling_trace_length } - if (sourceComponent?.ftype === "simple_crystal") { - const crystalProps = ( - port.parent as unknown as { - _parsedProps?: { maxTraceLength?: number } - } - )?._parsedProps - - return crystalProps?.maxTraceLength ?? 10 - } - return null }) - .filter((length): length is number => length !== null) + .filter((length): length is number => typeof length === "number") + + const crystalMaxLength = getMaxLengthFromConnectedCrystals(ports, { db }) + if (crystalMaxLength !== undefined) { + componentMaxLengths.push(crystalMaxLength) + } if (componentMaxLengths.length === 0) return undefined return Math.min(...componentMaxLengths) diff --git a/tests/components/normal-components/crystal-custom-trace-length.test.tsx b/tests/components/normal-components/crystal-custom-trace-length.test.tsx new file mode 100644 index 000000000..99f977759 --- /dev/null +++ b/tests/components/normal-components/crystal-custom-trace-length.test.tsx @@ -0,0 +1,40 @@ +import { expect, test } from "bun:test" +import { getTestFixture } from "tests/fixtures/get-test-fixture" + +test("configured crystal maximum trace length propagates across its net", () => { + const { circuit } = getTestFixture() + + circuit.add( + + + + + + + + + + + + , + ) + + circuit.render() + + const sourceTraces = circuit.db.source_trace.list() + expect( + Object.fromEntries( + sourceTraces.map((trace) => [trace.display_name, trace.max_length]), + ), + ).toEqual({ + ".Y1 > .pin1 to net.XTAL_OUT": 5, + ".U1 > .XTAL_OUT to net.XTAL_OUT": 5, + ".C1 > .pin1 to net.XTAL_OUT": 5, + ".C2 > .pin1 to net.UNRELATED": undefined, + }) +}) diff --git a/tests/components/normal-components/crystal-trace-too-long-warning.test.tsx b/tests/components/normal-components/crystal-trace-too-long-warning.test.tsx index 899f44677..feae9baf5 100644 --- a/tests/components/normal-components/crystal-trace-too-long-warning.test.tsx +++ b/tests/components/normal-components/crystal-trace-too-long-warning.test.tsx @@ -1,46 +1,55 @@ import { expect, test } from "bun:test" import { getTestFixture } from "tests/fixtures/get-test-fixture" -test("crystal traces warn above the default or configured maximum length", () => { +test("traces on a crystal net inherit its maximum length and warn when too long", async () => { const { circuit } = getTestFixture() circuit.add( - + + - - - - + - - + + + , ) - circuit.render() + await circuit.renderUntilSettled() const sourceTraces = circuit.db.source_trace.list() - expect(sourceTraces.map((trace) => trace.max_length)).toEqual([10, 20]) + expect(sourceTraces.map((trace) => trace.max_length)).toEqual([10, 10, 10]) const warnings = circuit.db.pcb_trace_too_long_warning.list() - expect(warnings).toHaveLength(1) - expect(warnings[0]).toMatchObject({ - source_trace_id: sourceTraces[0].source_trace_id, - maximum_trace_length: 10, - }) - expect(warnings[0].actual_trace_length).toBeGreaterThan(10) + expect(warnings).toHaveLength(2) + expect(warnings.map((warning) => warning.source_trace_id).sort()).toEqual( + [sourceTraces[0].source_trace_id, sourceTraces[1].source_trace_id].sort(), + ) + expect( + warnings.every( + (warning) => + warning.maximum_trace_length === 10 && + warning.actual_trace_length > warning.maximum_trace_length, + ), + ).toBe(true) }) From 823b12e2e88e41a6801c631ce9cff9e18016251c Mon Sep 17 00:00:00 2001 From: seveibar Date: Fri, 24 Jul 2026 10:48:36 -0700 Subject: [PATCH 2/5] Route trace length warnings through DRC checks --- lib/components/normal-components/Board.ts | 5 --- .../primitive-components/Group/Group.ts | 6 --- .../insert-pcb-trace-too-long-warnings.ts | 44 ------------------- 3 files changed, 55 deletions(-) delete mode 100644 lib/components/primitive-components/Group/insert-pcb-trace-too-long-warnings.ts diff --git a/lib/components/normal-components/Board.ts b/lib/components/normal-components/Board.ts index a62ee776a..a2f6cb198 100644 --- a/lib/components/normal-components/Board.ts +++ b/lib/components/normal-components/Board.ts @@ -21,7 +21,6 @@ import { Group } from "../primitive-components/Group/Group" import type { SubcircuitI } from "../primitive-components/Group/Subcircuit/SubcircuitI" import { Subcircuit_doInitialRenderIsolatedSubcircuits } from "../primitive-components/Group/Subcircuit/Subcircuit_doInitialRenderIsolatedSubcircuits" import { Subcircuit_getSubcircuitPropHash } from "../primitive-components/Group/Subcircuit_getSubcircuitPropHash" -import { insertPcbTraceTooLongWarnings } from "../primitive-components/Group/insert-pcb-trace-too-long-warnings" import type { BoardI } from "./BoardI" import { Board_doInitialPcbPlacementDesignRuleChecks } from "./Board_doInitialPcbPlacementDesignRuleChecks" @@ -696,10 +695,6 @@ export class Board this._queueAsyncEffect("board:drc-checks", async () => { try { await runDrcChecks(subcircuitCircuitJson) - insertPcbTraceTooLongWarnings({ - db, - subcircuitId: this.subcircuit_id!, - }) this._drcChecksComplete = true } finally { this._drcChecksInProgress = false diff --git a/lib/components/primitive-components/Group/Group.ts b/lib/components/primitive-components/Group/Group.ts index 358da096e..7e902c6ab 100644 --- a/lib/components/primitive-components/Group/Group.ts +++ b/lib/components/primitive-components/Group/Group.ts @@ -88,7 +88,6 @@ import type { ISubcircuit } from "./Subcircuit/ISubcircuit" import { addPortIdsToTracesAtJumperPads } from "./add-port-ids-to-traces-at-jumper-pads" import { getSourceTraceIdForRoutedTrace } from "./get-source-trace-id-for-routed-trace" import { insertAutoplacedJumpers } from "./insert-autoplaced-jumpers" -import { insertPcbTraceTooLongWarnings } from "./insert-pcb-trace-too-long-warnings" import { deleteExistingPcbTracesReplacedBy, getExistingPcbTracesForReroute, @@ -2061,11 +2060,6 @@ export class Group = typeof groupProps> }) } } - - insertPcbTraceTooLongWarnings({ - db, - subcircuitId: this.subcircuit_id!, - }) } } diff --git a/lib/components/primitive-components/Group/insert-pcb-trace-too-long-warnings.ts b/lib/components/primitive-components/Group/insert-pcb-trace-too-long-warnings.ts deleted file mode 100644 index d94759da3..000000000 --- a/lib/components/primitive-components/Group/insert-pcb-trace-too-long-warnings.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { CircuitJsonUtilObjects } from "@tscircuit/circuit-json-util" -import { getTraceLength } from "../Trace/trace-utils/compute-trace-length" - -export const insertPcbTraceTooLongWarnings = ({ - db, - subcircuitId, -}: { - db: CircuitJsonUtilObjects - subcircuitId: string -}) => { - for (const warning of db.pcb_trace_too_long_warning.list()) { - if (warning.subcircuit_id === subcircuitId) { - db.pcb_trace_too_long_warning.delete( - warning.pcb_trace_too_long_warning_id, - ) - } - } - - const pcbTraces = db.pcb_trace - .list() - .filter((pcbTrace) => pcbTrace.subcircuit_id === subcircuitId) - - for (const pcbTrace of pcbTraces) { - if (!pcbTrace.source_trace_id) continue - - const sourceTrace = db.source_trace.get(pcbTrace.source_trace_id) - const maximumTraceLength = sourceTrace?.max_length - if (maximumTraceLength === undefined) continue - - const actualTraceLength = - pcbTrace.trace_length ?? getTraceLength(pcbTrace.route) - if (actualTraceLength <= maximumTraceLength) continue - - db.pcb_trace_too_long_warning.insert({ - warning_type: "pcb_trace_too_long_warning", - message: `PCB trace is ${actualTraceLength.toFixed(2)}mm long, exceeding the ${maximumTraceLength}mm maximum`, - pcb_trace_id: pcbTrace.pcb_trace_id, - source_trace_id: pcbTrace.source_trace_id, - actual_trace_length: actualTraceLength, - maximum_trace_length: maximumTraceLength, - subcircuit_id: subcircuitId, - }) - } -} From 04e1288a4bd89e343f245d3a7d99465686a50992 Mon Sep 17 00:00:00 2001 From: seveibar Date: Fri, 24 Jul 2026 11:28:43 -0700 Subject: [PATCH 3/5] Apply trace constraints from the crystal render phase --- lib/components/normal-components/Crystal.ts | 60 ++++++++++++++- ...up_doInitialSourceAddConnectivityMapKey.ts | 7 +- ...pagate-crystal-trace-length-constraints.ts | 74 ------------------- ...et-max-length-from-connected-components.ts | 33 --------- .../crystal-custom-trace-length.test.tsx | 6 +- 5 files changed, 63 insertions(+), 117 deletions(-) delete mode 100644 lib/components/primitive-components/Group/propagate-crystal-trace-length-constraints.ts diff --git a/lib/components/normal-components/Crystal.ts b/lib/components/normal-components/Crystal.ts index 9a4940c95..97d9cb87d 100644 --- a/lib/components/normal-components/Crystal.ts +++ b/lib/components/normal-components/Crystal.ts @@ -1,10 +1,20 @@ import { type CrystalPinLabels, crystalProps } from "@tscircuit/props" +import type { + SourcePort, + SourceSimpleCrystalInput, + SourceTrace, +} from "circuit-json" +import { formatSiUnit } from "format-si-unit" import { type BaseSymbolName, type Ftype } from "lib/utils/constants" import { NormalComponent } from "../base-components/NormalComponent/NormalComponent" -import type { SourceSimpleCrystalInput } from "circuit-json" -import { formatSiUnit } from "format-si-unit" type CrystalPorts = CrystalPinLabels +type SourcePortId = SourcePort["source_port_id"] +type SubcircuitConnectivityMapKey = NonNullable< + SourceTrace["subcircuit_connectivity_map_key"] +> + +const DEFAULT_CRYSTAL_MAX_TRACE_LENGTH_MM = 10 export class Crystal extends NormalComponent< typeof crystalProps, @@ -69,4 +79,50 @@ export class Crystal extends NormalComponent< this.source_component_id = source_component.source_component_id } + + override doInitialSourceDesignRuleChecks(): void { + super.doInitialSourceDesignRuleChecks() + if (!this.source_component_id) return + + const { db } = this.root! + const maximumTraceLength = + this._parsedProps.maxTraceLength ?? DEFAULT_CRYSTAL_MAX_TRACE_LENGTH_MM + const crystalSourcePortIds = new Set() + const crystalConnectivityMapKeys = new Set() + + for (const sourcePort of db.source_port.list()) { + if (sourcePort.source_component_id !== this.source_component_id) continue + + crystalSourcePortIds.add(sourcePort.source_port_id) + if (sourcePort.subcircuit_connectivity_map_key) { + crystalConnectivityMapKeys.add( + sourcePort.subcircuit_connectivity_map_key, + ) + } + } + + for (const sourceTrace of db.source_trace.list()) { + const isDirectlyConnectedToCrystal = + sourceTrace.connected_source_port_ids.some((sourcePortId) => + crystalSourcePortIds.has(sourcePortId), + ) + const isOnCrystalNet = + sourceTrace.subcircuit_connectivity_map_key !== undefined && + crystalConnectivityMapKeys.has( + sourceTrace.subcircuit_connectivity_map_key, + ) + + if (!isDirectlyConnectedToCrystal && !isOnCrystalNet) continue + if ( + typeof sourceTrace.max_length === "number" && + sourceTrace.max_length <= maximumTraceLength + ) { + continue + } + + db.source_trace.update(sourceTrace.source_trace_id, { + max_length: maximumTraceLength, + }) + } + } } diff --git a/lib/components/primitive-components/Group/Group_doInitialSourceAddConnectivityMapKey.ts b/lib/components/primitive-components/Group/Group_doInitialSourceAddConnectivityMapKey.ts index 23ffc1070..dded34eb8 100644 --- a/lib/components/primitive-components/Group/Group_doInitialSourceAddConnectivityMapKey.ts +++ b/lib/components/primitive-components/Group/Group_doInitialSourceAddConnectivityMapKey.ts @@ -1,16 +1,15 @@ import type { SourceTrace } from "circuit-json" import { ConnectivityMap } from "circuit-json-to-connectivity-map" -import type { Trace } from "../Trace/Trace" +import type { TraceI } from "../Trace/TraceI" import type { Via } from "../Via" import type { Group } from "./Group" -import { propagateCrystalTraceLengthConstraints } from "./propagate-crystal-trace-length-constraints" export function Group_doInitialSourceAddConnectivityMapKey(group: Group) { if (!group.isSubcircuit) return const { db } = group.root! // Find all traces that belong to this subcircuit, generate a connectivity // map, and add source_trace.subcircuit_connectivity_map_key - const traces = group.selectAll("trace") as Trace[] + const traces = group.selectAll("trace") as TraceI[] const vias = group.selectAll("via") as Via[] const nets = group.selectAll("net") as any[] const connMap = new ConnectivityMap({}) @@ -53,8 +52,6 @@ export function Group_doInitialSourceAddConnectivityMapKey(group: Group) { }) } - propagateCrystalTraceLengthConstraints({ db, traces }) - // Update source_port.subcircuit_connectivity_map_key for ports connected to the same net const allSourcePortIds = new Set() for (const trace of traces) { diff --git a/lib/components/primitive-components/Group/propagate-crystal-trace-length-constraints.ts b/lib/components/primitive-components/Group/propagate-crystal-trace-length-constraints.ts deleted file mode 100644 index d60954850..000000000 --- a/lib/components/primitive-components/Group/propagate-crystal-trace-length-constraints.ts +++ /dev/null @@ -1,74 +0,0 @@ -import type { CircuitJsonUtilObjects } from "@tscircuit/circuit-json-util" -import type { SourceTrace } from "circuit-json" -import type { Trace } from "../Trace/Trace" -import { getMaxLengthFromConnectedCrystals } from "../Trace/trace-utils/get-max-length-from-connected-components" - -type SubcircuitConnectivityMapKey = NonNullable< - SourceTrace["subcircuit_connectivity_map_key"] -> - -export const propagateCrystalTraceLengthConstraints = ({ - db, - traces, -}: { - db: CircuitJsonUtilObjects - traces: Trace[] -}) => { - const crystalMaxLengthsBySubcircuitConnectivityMapKey = new Map< - SubcircuitConnectivityMapKey, - number - >() - - for (const trace of traces) { - if (!trace.source_trace_id) continue - - const sourceTrace = db.source_trace.get(trace.source_trace_id) - const subcircuitConnectivityMapKey = - sourceTrace?.subcircuit_connectivity_map_key - if (!subcircuitConnectivityMapKey) continue - - const connectedPorts = trace._findConnectedPorts().ports - if (!connectedPorts) continue - - const crystalMaxLength = getMaxLengthFromConnectedCrystals(connectedPorts, { - db, - }) - if (crystalMaxLength === undefined) continue - - const existingCrystalMaxLength = - crystalMaxLengthsBySubcircuitConnectivityMapKey.get( - subcircuitConnectivityMapKey, - ) - crystalMaxLengthsBySubcircuitConnectivityMapKey.set( - subcircuitConnectivityMapKey, - existingCrystalMaxLength === undefined - ? crystalMaxLength - : Math.min(existingCrystalMaxLength, crystalMaxLength), - ) - } - - for (const trace of traces) { - if (!trace.source_trace_id) continue - - const sourceTrace = db.source_trace.get(trace.source_trace_id) - const subcircuitConnectivityMapKey = - sourceTrace?.subcircuit_connectivity_map_key - if (!sourceTrace || !subcircuitConnectivityMapKey) continue - - const crystalMaxLength = - crystalMaxLengthsBySubcircuitConnectivityMapKey.get( - subcircuitConnectivityMapKey, - ) - if ( - crystalMaxLength === undefined || - (sourceTrace.max_length != null && - sourceTrace.max_length <= crystalMaxLength) - ) { - continue - } - - db.source_trace.update(sourceTrace.source_trace_id, { - max_length: crystalMaxLength, - }) - } -} diff --git a/lib/components/primitive-components/Trace/trace-utils/get-max-length-from-connected-components.ts b/lib/components/primitive-components/Trace/trace-utils/get-max-length-from-connected-components.ts index 7ea84dc8a..573a0a46a 100644 --- a/lib/components/primitive-components/Trace/trace-utils/get-max-length-from-connected-components.ts +++ b/lib/components/primitive-components/Trace/trace-utils/get-max-length-from-connected-components.ts @@ -1,34 +1,6 @@ import type { CircuitJsonUtilObjects } from "@tscircuit/circuit-json-util" import type { Port } from "../../Port" -export const getMaxLengthFromConnectedCrystals = ( - ports: Port[], - { db }: { db: CircuitJsonUtilObjects }, -): number | undefined => { - const crystalMaxLengths = ports - .map((port) => { - const sourcePort = db.source_port.get(port.source_port_id!) - if (!sourcePort?.source_component_id) return null - - const sourceComponent = db.source_component.get( - sourcePort.source_component_id, - ) - if (sourceComponent?.ftype !== "simple_crystal") return null - - const crystalProps = ( - port.parent as unknown as { - _parsedProps?: { maxTraceLength?: number } - } - )?._parsedProps - - return crystalProps?.maxTraceLength ?? 10 - }) - .filter((length): length is number => typeof length === "number") - - if (crystalMaxLengths.length === 0) return undefined - return Math.min(...crystalMaxLengths) -} - export const getMaxLengthFromConnectedComponents = ( ports: Port[], { db }: { db: CircuitJsonUtilObjects }, @@ -50,11 +22,6 @@ export const getMaxLengthFromConnectedComponents = ( }) .filter((length): length is number => typeof length === "number") - const crystalMaxLength = getMaxLengthFromConnectedCrystals(ports, { db }) - if (crystalMaxLength !== undefined) { - componentMaxLengths.push(crystalMaxLength) - } - if (componentMaxLengths.length === 0) return undefined return Math.min(...componentMaxLengths) } diff --git a/tests/components/normal-components/crystal-custom-trace-length.test.tsx b/tests/components/normal-components/crystal-custom-trace-length.test.tsx index 99f977759..a945e5596 100644 --- a/tests/components/normal-components/crystal-custom-trace-length.test.tsx +++ b/tests/components/normal-components/crystal-custom-trace-length.test.tsx @@ -1,7 +1,7 @@ import { expect, test } from "bun:test" import { getTestFixture } from "tests/fixtures/get-test-fixture" -test("configured crystal maximum trace length propagates across its net", () => { +test("configured crystal maximum propagates without replacing stricter limits", () => { const { circuit } = getTestFixture() circuit.add( @@ -15,7 +15,7 @@ test("configured crystal maximum trace length propagates across its net", () => maxTraceLength="5mm" /> - + @@ -34,7 +34,7 @@ test("configured crystal maximum trace length propagates across its net", () => ).toEqual({ ".Y1 > .pin1 to net.XTAL_OUT": 5, ".U1 > .XTAL_OUT to net.XTAL_OUT": 5, - ".C1 > .pin1 to net.XTAL_OUT": 5, + ".C1 > .pin1 to net.XTAL_OUT": 3, ".C2 > .pin1 to net.UNRELATED": undefined, }) }) From 94d3b39b75f293b28d3b0683c317f81329364ec9 Mon Sep 17 00:00:00 2001 From: seveibar Date: Fri, 24 Jul 2026 12:00:45 -0700 Subject: [PATCH 4/5] Update @tscircuit/checks for trace length DRC --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 72693a93e..52d3cdce1 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "@tscircuit/alphabet": "0.0.25", "@tscircuit/breakout-point-solver": "github:tscircuit/breakout-point-solver#bac9629", "@tscircuit/capacity-autorouter": "^0.0.710", - "@tscircuit/checks": "0.0.145", + "@tscircuit/checks": "0.0.146", "@tscircuit/circuit-json-util": "^0.0.100", "@tscircuit/common": "^0.0.20", "@tscircuit/copper-pour-solver": "0.0.39", From 976cd85513f2aef88ebc50e5d8608f8a0dc71cd6 Mon Sep 17 00:00:00 2001 From: seveibar Date: Fri, 24 Jul 2026 12:04:22 -0700 Subject: [PATCH 5/5] chore: retrigger CI