Skip to content

Commit

Permalink
add applySelector to soup-util
Browse files Browse the repository at this point in the history
  • Loading branch information
seveibar committed Jul 11, 2024
1 parent 664089b commit 50866bb
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 2 deletions.
1 change: 1 addition & 0 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from "./lib/su"
export * from "./lib/transform-soup-elements"
export * from "./lib/direction-to-vec"
export * from "./lib/apply-selector"

export { default as su } from "./lib/su"
107 changes: 107 additions & 0 deletions lib/apply-selector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import * as parsel from "parsel-js"
import { convertAbbrToType } from "./convert-abbreviation-to-soup-element-type"
import type { AnySoupElement } from "@tscircuit/soup"

const filterByType = (
elements: AnySoupElement[],
type: string
): AnySoupElement[] => {
type = convertAbbrToType(type)
return elements.filter(
(elm) => ("ftype" in elm && elm.ftype === type) || elm.type === type
)
}

/**
* Filter elements to match the selector, e.g. to access the left port of a
* resistor you can do ".R1 > port.left"
*/
export const applySelector = (
elements: AnySoupElement[],
selectorRaw: string
): AnySoupElement[] => {
const selectorAST = parsel.parse(selectorRaw)
return applySelectorAST(elements, selectorAST!)
}

const doesElmMatchClassName = (elm: AnySoupElement, className: string) =>
("name" in elm && elm.name === className) ||
("port_hints" in elm && elm.port_hints?.includes(className))

export const applySelectorAST = (
elements: AnySoupElement[],
selectorAST: parsel.AST
): AnySoupElement[] => {
switch (selectorAST.type) {
case "complex": {
switch (selectorAST.combinator) {
case " ": // TODO technically should do a deep search
case ">": {
const { left, right } = selectorAST
if (left.type === "class" || left.type === "type") {
// TODO should also check if content matches any element tags
let matchElms: AnySoupElement[]
if (left.type === "class") {
matchElms = elements.filter((elm) =>
doesElmMatchClassName(elm, left.name)
)
} else if (left.type === "type") {
matchElms = filterByType(elements, left.name)
} else {
matchElms = []
}

const childrenOfMatchingElms = matchElms.flatMap((matchElm) =>
elements.filter(
(elm: any) =>
elm[`${matchElm.type}_id`] ===
(matchElm as any)[`${matchElm.type}_id`] && elm !== matchElm
)
)
return applySelectorAST(childrenOfMatchingElms, right)
} else {
throw new Error(`unsupported selector type "${left.type}" `)
}
}
default: {
throw new Error(
`Couldn't apply selector AST for complex combinator "${selectorAST.combinator}"`
)
}
}
return []
}
case "compound": {
const conditionsToMatch = selectorAST.list.map((part) => {
switch (part.type) {
case "class": {
return (elm: any) => doesElmMatchClassName(elm, part.name)
}
case "type": {
const name = convertAbbrToType(part.name)
return (elm: any) => elm.type === name
}
}
})

return elements.filter((elm) =>
conditionsToMatch.every((condFn) => condFn?.(elm))
)
}
case "type": {
return filterByType(elements, selectorAST.name) as AnySoupElement[]
}
case "class": {
return elements.filter((elm) =>
doesElmMatchClassName(elm, selectorAST.name)
)
}
default: {
throw new Error(
`Couldn't apply selector AST for type: "${
selectorAST.type
}" ${JSON.stringify(selectorAST, null, " ")}`
)
}
}
}
11 changes: 11 additions & 0 deletions lib/convert-abbreviation-to-soup-element-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const convertAbbrToType = (abbr: string): string => {
switch (abbr) {
case "port":
return "source_port"
case "net":
return "source_net"
case "power":
return "simple_power_source"
}
return abbr
}
13 changes: 11 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,8 @@
"tsup": "^8.0.2",
"typescript": "^5.4.5",
"zod": "^3.23.6"
},
"dependencies": {
"parsel-js": "^1.1.2"
}
}

0 comments on commit 50866bb

Please sign in to comment.