From 2b5c2a9959a7d59624c11f91cc42278a79729e91 Mon Sep 17 00:00:00 2001 From: seveibar Date: Sun, 5 May 2024 19:10:26 -0700 Subject: [PATCH] add select --- index.ts | 54 +++++++++++++++++++++++++++++++++++++++++++- tests/select.test.ts | 34 ++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 tests/select.test.ts diff --git a/index.ts b/index.ts index c4fe637..3c52824 100644 --- a/index.ts +++ b/index.ts @@ -1,10 +1,16 @@ -import type { AnySoupElement, AnySoupElementInput } from "@tscircuit/soup" +import type { + AnySoupElement, + AnySoupElementInput, + SourceComponentBase, + SourcePort, +} from "@tscircuit/soup" type SoupOps< K extends AnySoupElement["type"], T extends AnySoupElement | AnySoupElementInput > = { get: (id: string) => Extract | null + select: (selector: string) => Extract | null getWhere: (where: any) => Extract | null getUsing: (using: { [key: `${string}_id`]: string @@ -70,6 +76,52 @@ export const su: GetSoupUtilObject = ((soup: AnySoupElement[]) => { keys.every((key) => e[key] === where[key]) ) }, + select: (selector: string) => { + // TODO when applySelector is isolated we can use it, until then we + // do a poor man's selector implementation for two common cases + if (component_type === "source_component") { + return soup.find( + (e) => + e.type === "source_component" && + e.name === selector.replace(/\./g, "") + ) + } else if ( + component_type === "pcb_port" || + component_type === "source_port" || + component_type === "schematic_port" + ) { + const [component_name, port_selector] = selector.split(/[ \>]/) + const source_component = soup.find( + (e) => + e.type === "source_component" && e.name === component_name + ) as SourceComponentBase + if (!source_component) return null + const source_port = soup.find( + (e) => + e.type === "source_port" && + e.source_component_id === + source_component.source_component_id && + (e.name === port_selector || + (e.port_hints ?? []).includes(port_selector!)) + ) as SourcePort + if (!source_port) return null + if (component_type === "source_port") return source_port + + if (component_type === "pcb_port") { + return soup.find( + (e) => + e.type === "pcb_port" && + e.source_port_id === source_port.source_port_id + ) + } else if (component_type === "schematic_port") { + return soup.find( + (e) => + e.type === "schematic_port" && + e.source_port_id === source_port.source_port_id + ) + } + } + }, } }, } diff --git a/tests/select.test.ts b/tests/select.test.ts new file mode 100644 index 0000000..59b2c7e --- /dev/null +++ b/tests/select.test.ts @@ -0,0 +1,34 @@ +import type { AnySoupElement } from "@tscircuit/soup" +import su from "../index" +import test from "ava" + +test("select", (t) => { + const soup: AnySoupElement[] = [ + { + type: "source_component", + source_component_id: "simple_resistor_0", + name: "R1", + supplier_part_numbers: {}, + ftype: "simple_resistor", + resistance: 10_000, + }, + { + type: "source_port", + name: "left", + source_port_id: "source_port_0", + source_component_id: "simple_resistor_0", + }, + { + type: "pcb_port", + pcb_port_id: "pcb_port_0", + source_port_id: "source_port_0", + layers: ["top"], + pcb_component_id: "pcb_component_simple_resistor_0", + x: 0, + y: 0, + }, + ] + + const pp = su(soup).pcb_port.select(".R1 > .left") + t.is(pp?.pcb_port_id, "pcb_port_0") +})