From 5e6566e8eb9edd909a1d15aa81442f5486b4f5ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bence=20Kov=C3=A1cs?= <23636204+githappens@users.noreply.github.com> Date: Mon, 20 Jul 2026 12:51:12 +0200 Subject: [PATCH 1/2] feat: derive connector gender from type and direction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 Signed-off-by: Bence Kovács <23636204+githappens@users.noreply.github.com> --- src/lib/utils/port-utils.ts | 34 ++++++++++++++++++++++++++++++++ src/tests/derive-gender.test.ts | 35 +++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 src/tests/derive-gender.test.ts diff --git a/src/lib/utils/port-utils.ts b/src/lib/utils/port-utils.ts index ee9cb6ca5..4597ad170 100644 --- a/src/lib/utils/port-utils.ts +++ b/src/lib/utils/port-utils.ts @@ -106,6 +106,40 @@ export function inferDirection( return "bidirectional"; } +/** Connector gender for display. Computed only, never stored (spike #1927). */ +export type ConnectorGender = "male" | "female"; + +/** + * Derive the connector gender for a port from its type and resolved + * direction, for connectors with a strong convention (spike #1927, + * Finding 6): + * - XLR-3 follows AES14 (signal flows out of male pins) so an output port is + * male and an input port is female; XLR-5 follows the same convention. + * Without a resolved in/out direction the gender is not derivable. + * - Speakon chassis connectors are male regardless of direction (the mating + * cable end is female); a port models the chassis side. + * - dmx-xlr is deliberately not derived: DMX512 (ANSI E1.11) reverses the + * AES14 convention (transmitters are female), so the XLR rule would + * mislead here. + * Ambiguous connectors (TRS, TS, RCA, ...) return undefined. + */ +export function deriveGender( + type: string, + direction?: PortDirection, +): ConnectorGender | undefined { + switch (type) { + case "xlr-3": + case "xlr-5": + if (direction === "output") return "male"; + if (direction === "input") return "female"; + return undefined; + case "speakon": + return "male"; + default: + return undefined; + } +} + /** * Instantiate ports from a DeviceType's interface templates * Creates PlacedPort instances with stable UUIDs for each interface diff --git a/src/tests/derive-gender.test.ts b/src/tests/derive-gender.test.ts new file mode 100644 index 000000000..3ec2679d9 --- /dev/null +++ b/src/tests/derive-gender.test.ts @@ -0,0 +1,35 @@ +import { describe, expect, it } from "vitest"; +import { deriveGender } from "$lib/utils/port-utils"; + +describe("deriveGender", () => { + it("derives XLR gender per AES14 from direction", () => { + expect(deriveGender("xlr-3", "output")).toBe("male"); + expect(deriveGender("xlr-3", "input")).toBe("female"); + expect(deriveGender("xlr-5", "output")).toBe("male"); + expect(deriveGender("xlr-5", "input")).toBe("female"); + }); + + it("returns undefined for XLR without a resolved direction", () => { + expect(deriveGender("xlr-3")).toBeUndefined(); + expect(deriveGender("xlr-3", "bidirectional")).toBeUndefined(); + }); + + it("derives Speakon chassis gender regardless of direction", () => { + expect(deriveGender("speakon")).toBe("male"); + expect(deriveGender("speakon", "input")).toBe("male"); + expect(deriveGender("speakon", "output")).toBe("male"); + }); + + it("returns undefined for ambiguous or non-AV connectors", () => { + expect(deriveGender("trs-1-4")).toBeUndefined(); + expect(deriveGender("ts-1-4")).toBeUndefined(); + expect(deriveGender("rca")).toBeUndefined(); + expect(deriveGender("hdmi")).toBeUndefined(); + expect(deriveGender("1000base-t")).toBeUndefined(); + }); + + it("does not derive dmx-xlr (DMX512 reverses the AES14 convention)", () => { + expect(deriveGender("dmx-xlr", "output")).toBeUndefined(); + expect(deriveGender("dmx-xlr", "input")).toBeUndefined(); + }); +}); From 76aad2f1ba944cc444e6e773b8bd2a3631a17a02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bence=20Kov=C3=A1cs?= <23636204+githappens@users.noreply.github.com> Date: Mon, 20 Jul 2026 12:58:59 +0200 Subject: [PATCH 2/2] feat: show derived connector gender in port tooltip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 Signed-off-by: Bence Kovács <23636204+githappens@users.noreply.github.com> --- src/lib/components/PortTooltip.svelte | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/lib/components/PortTooltip.svelte b/src/lib/components/PortTooltip.svelte index 565ea230f..5bd34f6fd 100644 --- a/src/lib/components/PortTooltip.svelte +++ b/src/lib/components/PortTooltip.svelte @@ -6,7 +6,7 @@ {#if visible && port} + {@const genderLabel = getGenderLabel(port)}