From 32b68edd31944654780a3294a2ea2d11ba9b09c7 Mon Sep 17 00:00:00 2001 From: seveibar Date: Mon, 27 Jul 2026 11:10:03 -0700 Subject: [PATCH 1/3] feat: add fanout autorouter bus props --- README.md | 4 ++++ generated/COMPONENT_TYPES.md | 21 ++++++++++++++++++++- generated/PROPS_OVERVIEW.md | 6 ++++++ lib/components/bus.ts | 29 +++++++++++++++++++++++++++++ lib/components/group.ts | 8 ++++++++ package.json | 2 +- tests/autorouter.test.ts | 10 ++++++++++ tests/bus.test.ts | 2 ++ 8 files changed, 80 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 57ee539d..e47dc098 100644 --- a/README.md +++ b/README.md @@ -437,6 +437,10 @@ export interface BusProps { name?: string; /** Trace names or port selectors for the connections in the bus. */ connections: string[]; + /** Direction in which this complete bus should leave its source footprint. */ + pcbFanoutDirection?: BusPcbFanoutDirection; + /** Board edge or corner toward which this complete bus should fan out. */ + pcbFanoutPreferredExit?: BusPcbFanoutPreferredExit; } ``` diff --git a/generated/COMPONENT_TYPES.md b/generated/COMPONENT_TYPES.md index 0b9f15d3..b5ce0248 100644 --- a/generated/COMPONENT_TYPES.md +++ b/generated/COMPONENT_TYPES.md @@ -1285,11 +1285,26 @@ export const breakoutPointProps = pcbLayoutProps export interface BusProps { name?: string connections: string[] + pcbFanoutDirection?: BusPcbFanoutDirection + pcbFanoutPreferredExit?: BusPcbFanoutPreferredExit } -/** Trace names or port selectors for the connections in the bus. */ +/** Board edge or corner toward which this complete bus should fan out. */ export const busProps = z.object({ name: z.string().optional(), connections: z.array(z.string()).min(2), + pcbFanoutDirection: z.enum(["left", "right", "up", "down"]).optional(), + pcbFanoutPreferredExit: z + .enum([ + "left", + "right", + "top", + "bottom", + "top_left", + "top_right", + "bottom_left", + "bottom_right", + ]) + .optional(), }) ``` @@ -2347,6 +2362,8 @@ export interface AutorouterConfig { | "krt" | "freerouting" | "laser_prefab" // Prefabricated PCB with laser copper ablation + | "single_layer_fanout" + | "fanout" | /** @deprecated Use "auto_jumper" */ "auto-jumper" | /** @deprecated Use "sequential_trace" */ "sequential-trace" | /** @deprecated Use "auto_local" */ "auto-local" @@ -2392,6 +2409,8 @@ export const autorouterConfig = z.object({ "krt", "freerouting", "laser_prefab", + "single_layer_fanout", + "fanout", "auto-jumper", "sequential-trace", "auto-local", diff --git a/generated/PROPS_OVERVIEW.md b/generated/PROPS_OVERVIEW.md index a1a77650..d140f359 100644 --- a/generated/PROPS_OVERVIEW.md +++ b/generated/PROPS_OVERVIEW.md @@ -166,6 +166,8 @@ export interface AutorouterConfig { | "krt" | "freerouting" | "laser_prefab" // Prefabricated PCB with laser copper ablation + | "single_layer_fanout" + | "fanout" | /** @deprecated Use "auto_jumper" */ "auto-jumper" | /** @deprecated Use "sequential_trace" */ "sequential-trace" | /** @deprecated Use "auto_local" */ "auto-local" @@ -412,6 +414,10 @@ export interface BusProps { name?: string /** Trace names or port selectors for the connections in the bus. */ connections: string[] + /** Direction in which this complete bus should leave its source footprint. */ + pcbFanoutDirection?: BusPcbFanoutDirection + /** Board edge or corner toward which this complete bus should fan out. */ + pcbFanoutPreferredExit?: BusPcbFanoutPreferredExit } diff --git a/lib/components/bus.ts b/lib/components/bus.ts index 0eed3577..d2c28283 100644 --- a/lib/components/bus.ts +++ b/lib/components/bus.ts @@ -1,6 +1,18 @@ import { expectTypesMatch } from "lib/typecheck" import { z } from "zod" +export type BusPcbFanoutDirection = "left" | "right" | "up" | "down" + +export type BusPcbFanoutPreferredExit = + | "left" + | "right" + | "top" + | "bottom" + | "top_left" + | "top_right" + | "bottom_left" + | "bottom_right" + /** * Declares a group of connections that an autorouter should keep together. * Each connection may be a trace name or a port selector. @@ -9,11 +21,28 @@ export interface BusProps { name?: string /** Trace names or port selectors for the connections in the bus. */ connections: string[] + /** Direction in which this complete bus should leave its source footprint. */ + pcbFanoutDirection?: BusPcbFanoutDirection + /** Board edge or corner toward which this complete bus should fan out. */ + pcbFanoutPreferredExit?: BusPcbFanoutPreferredExit } export const busProps = z.object({ name: z.string().optional(), connections: z.array(z.string()).min(2), + pcbFanoutDirection: z.enum(["left", "right", "up", "down"]).optional(), + pcbFanoutPreferredExit: z + .enum([ + "left", + "right", + "top", + "bottom", + "top_left", + "top_right", + "bottom_left", + "bottom_right", + ]) + .optional(), }) type InferredBusProps = z.input diff --git a/lib/components/group.ts b/lib/components/group.ts index e08d4b17..744e592e 100644 --- a/lib/components/group.ts +++ b/lib/components/group.ts @@ -353,6 +353,8 @@ export interface AutorouterConfig { | "krt" | "freerouting" | "laser_prefab" // Prefabricated PCB with laser copper ablation + | "single_layer_fanout" + | "fanout" | /** @deprecated Use "auto_jumper" */ "auto-jumper" | /** @deprecated Use "sequential_trace" */ "sequential-trace" | /** @deprecated Use "auto_local" */ "auto-local" @@ -371,6 +373,8 @@ export type AutorouterPreset = | "krt" | "freerouting" | "laser_prefab" + | "single_layer_fanout" + | "fanout" | "auto-jumper" | "sequential-trace" | "auto-local" @@ -425,6 +429,8 @@ export const autorouterConfig = z.object({ "krt", "freerouting", "laser_prefab", + "single_layer_fanout", + "fanout", "auto-jumper", "sequential-trace", "auto-local", @@ -446,6 +452,8 @@ export const autorouterPreset = z.union([ z.literal("krt"), z.literal("freerouting"), z.literal("laser_prefab"), // Prefabricated PCB with laser copper ablation + z.literal("single_layer_fanout"), + z.literal("fanout"), z.literal("auto-jumper"), z.literal("sequential-trace"), z.literal("auto-local"), diff --git a/package.json b/package.json index 9ae11697..a8db698e 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "@types/node": "^20.12.11", "@types/react": "^18.3.2", "ava": "^6.1.3", - "circuit-json": "^0.0.450", + "circuit-json": "^0.0.455", "expect-type": "^1.3.0", "glob": "^11.0.0", "madge": "^8.0.0", diff --git a/tests/autorouter.test.ts b/tests/autorouter.test.ts index a8792994..ba2dfa6e 100644 --- a/tests/autorouter.test.ts +++ b/tests/autorouter.test.ts @@ -44,6 +44,16 @@ test("supports krt preset", () => { expect(result).toBe("krt") }) +test("supports fanout presets", () => { + expect(autorouterProp.parse("single_layer_fanout")).toBe( + "single_layer_fanout", + ) + expect(autorouterProp.parse("fanout")).toBe("fanout") + expect(autorouterProp.parse({ preset: "fanout" })).toMatchObject({ + preset: "fanout", + }) +}) + test("still supports deprecated kebab-case presets", () => { const result = autorouterProp.parse("auto-cloud") expect(result).toBe("auto-cloud") diff --git a/tests/bus.test.ts b/tests/bus.test.ts index 0fee5925..811e02d9 100644 --- a/tests/bus.test.ts +++ b/tests/bus.test.ts @@ -5,6 +5,8 @@ test("busProps accepts two or more connection references", () => { const rawProps: BusProps = { name: "DATA", connections: ["D0", ".U1 > .D1"], + pcbFanoutDirection: "right", + pcbFanoutPreferredExit: "top_right", } expect(busProps.parse(rawProps)).toEqual(rawProps) From 9eefa7c66e4f5dfe7dfaafb7ead5adac0bdc33f3 Mon Sep 17 00:00:00 2001 From: seveibar Date: Mon, 27 Jul 2026 11:35:57 -0700 Subject: [PATCH 2/3] fix: scope fanout controls to routing phases --- README.md | 10 ++++--- generated/COMPONENT_TYPES.md | 35 +++++++++++++----------- generated/PROPS_OVERVIEW.md | 10 ++++--- lib/components/autoroutingphase.ts | 44 ++++++++++++++++++++++++++++++ lib/components/bus.ts | 29 -------------------- tests/autoroutingphase.test.ts | 20 ++++++++++++++ tests/bus.test.ts | 2 -- 7 files changed, 95 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index e47dc098..6217b9c2 100644 --- a/README.md +++ b/README.md @@ -342,6 +342,12 @@ export interface AutoroutingPhaseProps extends RoutingTolerances { connection?: string; connections?: string[]; reroute?: boolean; + /** Selector for the component whose pads should be escaped in this phase. */ + fanoutComponent?: string; + /** Direction in which complete buses should leave the selected component. */ + fanoutDirection?: FanoutDirection; + /** Boundary edge or corner toward which buses should leave the component. */ + fanoutPreferredExit?: FanoutPreferredExit; } ``` @@ -437,10 +443,6 @@ export interface BusProps { name?: string; /** Trace names or port selectors for the connections in the bus. */ connections: string[]; - /** Direction in which this complete bus should leave its source footprint. */ - pcbFanoutDirection?: BusPcbFanoutDirection; - /** Board edge or corner toward which this complete bus should fan out. */ - pcbFanoutPreferredExit?: BusPcbFanoutPreferredExit; } ``` diff --git a/generated/COMPONENT_TYPES.md b/generated/COMPONENT_TYPES.md index b5ce0248..6d98e034 100644 --- a/generated/COMPONENT_TYPES.md +++ b/generated/COMPONENT_TYPES.md @@ -1142,7 +1142,11 @@ export interface AutoroutingPhaseProps extends RoutingTolerances { connection?: string connections?: string[] reroute?: boolean + fanoutComponent?: string + fanoutDirection?: FanoutDirection + fanoutPreferredExit?: FanoutPreferredExit } +/** Boundary edge or corner toward which buses should leave the component. */ export const autoroutingPhaseProps = z .object({ key: z.any().optional(), @@ -1162,6 +1166,20 @@ export const autoroutingPhaseProps = z connection: z.string().optional(), connections: z.array(z.string()).optional(), reroute: z.boolean().optional(), + fanoutComponent: z.string().optional(), + fanoutDirection: z.enum(["left", "right", "up", "down"]).optional(), + fanoutPreferredExit: z + .enum([ + "left", + "right", + "top", + "bottom", + "top_left", + "top_right", + "bottom_left", + "bottom_right", + ]) + .optional(), }) ``` @@ -1285,26 +1303,11 @@ export const breakoutPointProps = pcbLayoutProps export interface BusProps { name?: string connections: string[] - pcbFanoutDirection?: BusPcbFanoutDirection - pcbFanoutPreferredExit?: BusPcbFanoutPreferredExit } -/** Board edge or corner toward which this complete bus should fan out. */ +/** Trace names or port selectors for the connections in the bus. */ export const busProps = z.object({ name: z.string().optional(), connections: z.array(z.string()).min(2), - pcbFanoutDirection: z.enum(["left", "right", "up", "down"]).optional(), - pcbFanoutPreferredExit: z - .enum([ - "left", - "right", - "top", - "bottom", - "top_left", - "top_right", - "bottom_left", - "bottom_right", - ]) - .optional(), }) ``` diff --git a/generated/PROPS_OVERVIEW.md b/generated/PROPS_OVERVIEW.md index d140f359..cef51e2e 100644 --- a/generated/PROPS_OVERVIEW.md +++ b/generated/PROPS_OVERVIEW.md @@ -204,6 +204,12 @@ export interface AutoroutingPhaseProps extends RoutingTolerances { connection?: string connections?: string[] reroute?: boolean + /** Selector for the component whose pads should be escaped in this phase. */ + fanoutComponent?: string + /** Direction in which complete buses should leave the selected component. */ + fanoutDirection?: FanoutDirection + /** Boundary edge or corner toward which buses should leave the component. */ + fanoutPreferredExit?: FanoutPreferredExit } @@ -414,10 +420,6 @@ export interface BusProps { name?: string /** Trace names or port selectors for the connections in the bus. */ connections: string[] - /** Direction in which this complete bus should leave its source footprint. */ - pcbFanoutDirection?: BusPcbFanoutDirection - /** Board edge or corner toward which this complete bus should fan out. */ - pcbFanoutPreferredExit?: BusPcbFanoutPreferredExit } diff --git a/lib/components/autoroutingphase.ts b/lib/components/autoroutingphase.ts index e662aa17..95a51487 100644 --- a/lib/components/autoroutingphase.ts +++ b/lib/components/autoroutingphase.ts @@ -7,6 +7,18 @@ import { routingTolerances, } from "./group" +export type FanoutDirection = "left" | "right" | "up" | "down" + +export type FanoutPreferredExit = + | "left" + | "right" + | "top" + | "bottom" + | "top_left" + | "top_right" + | "bottom_left" + | "bottom_right" + export interface AutoroutingPhaseProps extends RoutingTolerances { key?: any name?: string @@ -22,6 +34,12 @@ export interface AutoroutingPhaseProps extends RoutingTolerances { connection?: string connections?: string[] reroute?: boolean + /** Selector for the component whose pads should be escaped in this phase. */ + fanoutComponent?: string + /** Direction in which complete buses should leave the selected component. */ + fanoutDirection?: FanoutDirection + /** Boundary edge or corner toward which buses should leave the component. */ + fanoutPreferredExit?: FanoutPreferredExit } export const autoroutingPhaseProps = z @@ -43,6 +61,20 @@ export const autoroutingPhaseProps = z connection: z.string().optional(), connections: z.array(z.string()).optional(), reroute: z.boolean().optional(), + fanoutComponent: z.string().optional(), + fanoutDirection: z.enum(["left", "right", "up", "down"]).optional(), + fanoutPreferredExit: z + .enum([ + "left", + "right", + "top", + "bottom", + "top_left", + "top_right", + "bottom_left", + "bottom_right", + ]) + .optional(), }) .superRefine((value, ctx) => { if ( @@ -58,6 +90,18 @@ export const autoroutingPhaseProps = z path: ["region"], }) } + if ( + value.fanoutComponent === undefined && + (value.fanoutDirection !== undefined || + value.fanoutPreferredExit !== undefined) + ) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: + "fanoutComponent is required when fanoutDirection or fanoutPreferredExit is provided", + path: ["fanoutComponent"], + }) + } }) type InferredAutoroutingPhaseProps = z.input diff --git a/lib/components/bus.ts b/lib/components/bus.ts index d2c28283..0eed3577 100644 --- a/lib/components/bus.ts +++ b/lib/components/bus.ts @@ -1,18 +1,6 @@ import { expectTypesMatch } from "lib/typecheck" import { z } from "zod" -export type BusPcbFanoutDirection = "left" | "right" | "up" | "down" - -export type BusPcbFanoutPreferredExit = - | "left" - | "right" - | "top" - | "bottom" - | "top_left" - | "top_right" - | "bottom_left" - | "bottom_right" - /** * Declares a group of connections that an autorouter should keep together. * Each connection may be a trace name or a port selector. @@ -21,28 +9,11 @@ export interface BusProps { name?: string /** Trace names or port selectors for the connections in the bus. */ connections: string[] - /** Direction in which this complete bus should leave its source footprint. */ - pcbFanoutDirection?: BusPcbFanoutDirection - /** Board edge or corner toward which this complete bus should fan out. */ - pcbFanoutPreferredExit?: BusPcbFanoutPreferredExit } export const busProps = z.object({ name: z.string().optional(), connections: z.array(z.string()).min(2), - pcbFanoutDirection: z.enum(["left", "right", "up", "down"]).optional(), - pcbFanoutPreferredExit: z - .enum([ - "left", - "right", - "top", - "bottom", - "top_left", - "top_right", - "bottom_left", - "bottom_right", - ]) - .optional(), }) type InferredBusProps = z.input diff --git a/tests/autoroutingphase.test.ts b/tests/autoroutingphase.test.ts index 0761a917..cfc3cc6e 100644 --- a/tests/autoroutingphase.test.ts +++ b/tests/autoroutingphase.test.ts @@ -30,6 +30,26 @@ test("autorouting phase accepts autorouter and phase index", () => { expect(parsed.phaseIndex).toBe(1) }) +test("autorouting phase accepts component-scoped fanout controls", () => { + const raw = { + autorouter: "fanout", + fanoutComponent: ".U1", + fanoutDirection: "right", + fanoutPreferredExit: "top_right", + } satisfies AutoroutingPhaseProps + + expect(autoroutingPhaseProps.parse(raw)).toEqual(raw) +}) + +test("autorouting phase requires a component for directed fanout", () => { + expect( + autoroutingPhaseProps.safeParse({ + autorouter: "fanout", + fanoutDirection: "right", + }).success, + ).toBe(false) +}) + test("autorouting phase accepts a single connection", () => { const raw: AutoroutingPhaseProps = { phaseIndex: 2, diff --git a/tests/bus.test.ts b/tests/bus.test.ts index 811e02d9..0fee5925 100644 --- a/tests/bus.test.ts +++ b/tests/bus.test.ts @@ -5,8 +5,6 @@ test("busProps accepts two or more connection references", () => { const rawProps: BusProps = { name: "DATA", connections: ["D0", ".U1 > .D1"], - pcbFanoutDirection: "right", - pcbFanoutPreferredExit: "top_right", } expect(busProps.parse(rawProps)).toEqual(rawProps) From 1d56b5bd465f14f737f0b5fa39142947e86613b3 Mon Sep 17 00:00:00 2001 From: seveibar Date: Mon, 27 Jul 2026 12:56:53 -0700 Subject: [PATCH 3/3] refactor: configure fanout direction per bus --- README.md | 11 +++-- generated/COMPONENT_TYPES.md | 29 +++++--------- generated/PROPS_OVERVIEW.md | 11 +++-- lib/common/ninePointAnchor.ts | 2 + lib/components/autoroutingphase.ts | 64 ++++++++++-------------------- lib/components/bus.ts | 2 + tests/autoroutingphase.test.ts | 18 +++------ 7 files changed, 51 insertions(+), 86 deletions(-) diff --git a/README.md b/README.md index 6217b9c2..b8d4e60a 100644 --- a/README.md +++ b/README.md @@ -342,12 +342,11 @@ export interface AutoroutingPhaseProps extends RoutingTolerances { connection?: string; connections?: string[]; reroute?: boolean; - /** Selector for the component whose pads should be escaped in this phase. */ - fanoutComponent?: string; - /** Direction in which complete buses should leave the selected component. */ - fanoutDirection?: FanoutDirection; - /** Boundary edge or corner toward which buses should leave the component. */ - fanoutPreferredExit?: FanoutPreferredExit; + /** + * Fanout direction for each named bus in this phase. `center` leaves the + * direction unconstrained. + */ + busFanoutDirections?: Record; } ``` diff --git a/generated/COMPONENT_TYPES.md b/generated/COMPONENT_TYPES.md index 6d98e034..80e94180 100644 --- a/generated/COMPONENT_TYPES.md +++ b/generated/COMPONENT_TYPES.md @@ -1127,6 +1127,11 @@ export const analogTransientSimulationProps = z ### autoroutingphase ```typescript +export type BusFanoutDirection = + | NinePointAnchor + | { + direction: NinePointAnchor + } export interface AutoroutingPhaseProps extends RoutingTolerances { key?: any name?: string @@ -1142,11 +1147,12 @@ export interface AutoroutingPhaseProps extends RoutingTolerances { connection?: string connections?: string[] reroute?: boolean - fanoutComponent?: string - fanoutDirection?: FanoutDirection - fanoutPreferredExit?: FanoutPreferredExit + busFanoutDirections?: Record } -/** Boundary edge or corner toward which buses should leave the component. */ +/** + * Fanout direction for each named bus in this phase. `center` leaves the + * direction unconstrained. + */ export const autoroutingPhaseProps = z .object({ key: z.any().optional(), @@ -1166,20 +1172,7 @@ export const autoroutingPhaseProps = z connection: z.string().optional(), connections: z.array(z.string()).optional(), reroute: z.boolean().optional(), - fanoutComponent: z.string().optional(), - fanoutDirection: z.enum(["left", "right", "up", "down"]).optional(), - fanoutPreferredExit: z - .enum([ - "left", - "right", - "top", - "bottom", - "top_left", - "top_right", - "bottom_left", - "bottom_right", - ]) - .optional(), + busFanoutDirections: z.record(busFanoutDirection).optional(), }) ``` diff --git a/generated/PROPS_OVERVIEW.md b/generated/PROPS_OVERVIEW.md index cef51e2e..2d98edd9 100644 --- a/generated/PROPS_OVERVIEW.md +++ b/generated/PROPS_OVERVIEW.md @@ -204,12 +204,11 @@ export interface AutoroutingPhaseProps extends RoutingTolerances { connection?: string connections?: string[] reroute?: boolean - /** Selector for the component whose pads should be escaped in this phase. */ - fanoutComponent?: string - /** Direction in which complete buses should leave the selected component. */ - fanoutDirection?: FanoutDirection - /** Boundary edge or corner toward which buses should leave the component. */ - fanoutPreferredExit?: FanoutPreferredExit + /** + * Fanout direction for each named bus in this phase. `center` leaves the + * direction unconstrained. + */ + busFanoutDirections?: Record } diff --git a/lib/common/ninePointAnchor.ts b/lib/common/ninePointAnchor.ts index ff7660fd..35df06a8 100644 --- a/lib/common/ninePointAnchor.ts +++ b/lib/common/ninePointAnchor.ts @@ -11,3 +11,5 @@ export const ninePointAnchor = z.enum([ "bottom_center", "bottom_right", ]) + +export type NinePointAnchor = z.infer diff --git a/lib/components/autoroutingphase.ts b/lib/components/autoroutingphase.ts index 95a51487..968b6743 100644 --- a/lib/components/autoroutingphase.ts +++ b/lib/components/autoroutingphase.ts @@ -1,5 +1,10 @@ import { expectTypesMatch } from "lib/typecheck" import { z } from "zod" +import { + type NinePointAnchor, + ninePointAnchor, +} from "../common/ninePointAnchor" +import type { BusName } from "./bus" import { type AutorouterProp, type RoutingTolerances, @@ -7,17 +12,11 @@ import { routingTolerances, } from "./group" -export type FanoutDirection = "left" | "right" | "up" | "down" - -export type FanoutPreferredExit = - | "left" - | "right" - | "top" - | "bottom" - | "top_left" - | "top_right" - | "bottom_left" - | "bottom_right" +export type BusFanoutDirection = + | NinePointAnchor + | { + direction: NinePointAnchor + } export interface AutoroutingPhaseProps extends RoutingTolerances { key?: any @@ -34,14 +33,18 @@ export interface AutoroutingPhaseProps extends RoutingTolerances { connection?: string connections?: string[] reroute?: boolean - /** Selector for the component whose pads should be escaped in this phase. */ - fanoutComponent?: string - /** Direction in which complete buses should leave the selected component. */ - fanoutDirection?: FanoutDirection - /** Boundary edge or corner toward which buses should leave the component. */ - fanoutPreferredExit?: FanoutPreferredExit + /** + * Fanout direction for each named bus in this phase. `center` leaves the + * direction unconstrained. + */ + busFanoutDirections?: Record } +const busFanoutDirection = z.union([ + ninePointAnchor, + z.object({ direction: ninePointAnchor }), +]) + export const autoroutingPhaseProps = z .object({ key: z.any().optional(), @@ -61,20 +64,7 @@ export const autoroutingPhaseProps = z connection: z.string().optional(), connections: z.array(z.string()).optional(), reroute: z.boolean().optional(), - fanoutComponent: z.string().optional(), - fanoutDirection: z.enum(["left", "right", "up", "down"]).optional(), - fanoutPreferredExit: z - .enum([ - "left", - "right", - "top", - "bottom", - "top_left", - "top_right", - "bottom_left", - "bottom_right", - ]) - .optional(), + busFanoutDirections: z.record(busFanoutDirection).optional(), }) .superRefine((value, ctx) => { if ( @@ -90,18 +80,6 @@ export const autoroutingPhaseProps = z path: ["region"], }) } - if ( - value.fanoutComponent === undefined && - (value.fanoutDirection !== undefined || - value.fanoutPreferredExit !== undefined) - ) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - message: - "fanoutComponent is required when fanoutDirection or fanoutPreferredExit is provided", - path: ["fanoutComponent"], - }) - } }) type InferredAutoroutingPhaseProps = z.input diff --git a/lib/components/bus.ts b/lib/components/bus.ts index 0eed3577..242be75e 100644 --- a/lib/components/bus.ts +++ b/lib/components/bus.ts @@ -1,6 +1,8 @@ import { expectTypesMatch } from "lib/typecheck" import { z } from "zod" +export type BusName = string + /** * Declares a group of connections that an autorouter should keep together. * Each connection may be a trace name or a port selector. diff --git a/tests/autoroutingphase.test.ts b/tests/autoroutingphase.test.ts index cfc3cc6e..afa5b980 100644 --- a/tests/autoroutingphase.test.ts +++ b/tests/autoroutingphase.test.ts @@ -30,26 +30,18 @@ test("autorouting phase accepts autorouter and phase index", () => { expect(parsed.phaseIndex).toBe(1) }) -test("autorouting phase accepts component-scoped fanout controls", () => { +test("autorouting phase accepts per-bus fanout directions", () => { const raw = { autorouter: "fanout", - fanoutComponent: ".U1", - fanoutDirection: "right", - fanoutPreferredExit: "top_right", + busFanoutDirections: { + DATA: "top_right", + CONTROL: { direction: "center_left" }, + }, } satisfies AutoroutingPhaseProps expect(autoroutingPhaseProps.parse(raw)).toEqual(raw) }) -test("autorouting phase requires a component for directed fanout", () => { - expect( - autoroutingPhaseProps.safeParse({ - autorouter: "fanout", - fanoutDirection: "right", - }).success, - ).toBe(false) -}) - test("autorouting phase accepts a single connection", () => { const raw: AutoroutingPhaseProps = { phaseIndex: 2,