@tscircuit/core 0.0.42 → 0.0.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -134,7 +134,7 @@ import {
134
134
  translate
135
135
  } from "transformation-matrix";
136
136
 
137
- // lib/utils/selector-matching/index.ts
137
+ // lib/utils/selector-matching/is-matching-selector.ts
138
138
  function isMatchingSelector(component, selector) {
139
139
  const idMatch = selector.match(/^#(\w+)/);
140
140
  if (idMatch) {
@@ -163,6 +163,20 @@ function isMatchingSelector(component, selector) {
163
163
  });
164
164
  }
165
165
 
166
+ // lib/utils/selector-matching/is-matching-path-selector.ts
167
+ function isMatchingPathSelector(component, selector) {
168
+ const selectorParts = selector.split(/\> /g).map((part) => part.trim());
169
+ let currentComponent = component;
170
+ for (let i = selectorParts.length - 1; i >= 0; i--) {
171
+ if (!currentComponent) return false;
172
+ if (!isMatchingSelector(currentComponent, selectorParts[i])) {
173
+ return false;
174
+ }
175
+ currentComponent = currentComponent.parent;
176
+ }
177
+ return true;
178
+ }
179
+
166
180
  // lib/components/base-components/PrimitiveComponent.ts
167
181
  var PrimitiveComponent = class extends Renderable {
168
182
  parent = null;
@@ -2252,8 +2266,13 @@ searched component ${targetComponent.getString()}, which has ports: ${targetComp
2252
2266
  const hints = ports.flatMap(
2253
2267
  (port) => port.matchedComponents.filter((c) => c.componentName === "TraceHint")
2254
2268
  );
2255
- const pcbRouteHints = (this._parsedProps.pcbRouteHints ?? []).concat(
2256
- hints.flatMap((h) => h.getPcbRouteHints())
2269
+ const manualTraceHints = this.getSubcircuit().props.layout?.manual_trace_hints ?? [];
2270
+ const pcbRouteHints = (this._parsedProps.pcbRouteHints ?? []).concat(hints.flatMap((h) => h.getPcbRouteHints())).concat(
2271
+ manualTraceHints.filter(
2272
+ (hint) => ports.some(
2273
+ (port) => isMatchingPathSelector(port, hint.pcb_port_selector)
2274
+ )
2275
+ ).flatMap((hint) => hint.offsets)
2257
2276
  );
2258
2277
  if (ports.length > 2) {
2259
2278
  this.renderError(
@@ -32,6 +32,10 @@ import type { Net } from "./Net"
32
32
  import { getClosest } from "lib/utils/getClosest"
33
33
  import { z } from "zod"
34
34
  import { createNetsFromProps } from "lib/utils/components/createNetsFromProps"
35
+ import {
36
+ isMatchingPathSelector,
37
+ isMatchingSelector,
38
+ } from "lib/utils/selector-matching"
35
39
 
36
40
  type PcbRouteObjective =
37
41
  | RouteHintPoint
@@ -299,9 +303,20 @@ export class Trace extends PrimitiveComponent<typeof traceProps> {
299
303
  port.matchedComponents.filter((c) => c.componentName === "TraceHint"),
300
304
  ) as TraceHint[]
301
305
 
302
- const pcbRouteHints = (this._parsedProps.pcbRouteHints ?? []).concat(
303
- hints.flatMap((h) => h.getPcbRouteHints()),
304
- )
306
+ const manualTraceHints =
307
+ this.getSubcircuit().props.layout?.manual_trace_hints ?? []
308
+
309
+ const pcbRouteHints = (this._parsedProps.pcbRouteHints ?? [])
310
+ .concat(hints.flatMap((h) => h.getPcbRouteHints()))
311
+ .concat(
312
+ manualTraceHints
313
+ .filter((hint: { pcb_port_selector: string }) =>
314
+ ports.some((port) =>
315
+ isMatchingPathSelector(port, hint.pcb_port_selector),
316
+ ),
317
+ )
318
+ .flatMap((hint: { offsets: RouteHintPoint[] }) => hint.offsets),
319
+ )
305
320
 
306
321
  if (ports.length > 2) {
307
322
  this.renderError(
@@ -1,64 +1,2 @@
1
- import type { PrimitiveComponent } from "lib/components"
2
- import type { Primitive } from "schematic-symbols/drawing/types"
3
-
4
- /**
5
- * Determines if a component matches a given selector.
6
- *
7
- * This function supports the following selector types:
8
- * - ID selectors (#id)
9
- * - Class selectors (.className)
10
- * - Type selectors (resistor)
11
- * - Attribute selectors ([key='value'])
12
- *
13
- * It also supports combinations of these selectors.
14
- *
15
- * @param component - The component to check.
16
- * @param selector - The selector string to match against.
17
- * @returns True if the component matches the selector, false otherwise.
18
- */
19
- export function isMatchingSelector(
20
- component: PrimitiveComponent,
21
- selector: string,
22
- ): boolean {
23
- // Check for ID selector
24
- const idMatch = selector.match(/^#(\w+)/)
25
- if (idMatch) {
26
- return component.props.id === idMatch[1]
27
- }
28
-
29
- // Check for class selector
30
- const classMatch = selector.match(/^\.(\w+)/)
31
- if (classMatch) {
32
- return component.isMatchingNameOrAlias(classMatch[1])
33
- }
34
-
35
- // Split the selector into type and conditions
36
- let [type, ...conditions] = selector.split(/(?=[#.[])/)
37
-
38
- if (type === "pin") type = "port"
39
-
40
- // Check if the component type matches
41
- if (
42
- type &&
43
- type !== "*" &&
44
- component.lowercaseComponentName !== type.toLowerCase()
45
- ) {
46
- return false
47
- }
48
-
49
- // Check all conditions
50
- return conditions.every((condition) => {
51
- if (condition.startsWith("#")) {
52
- return component.props.id === condition.slice(1)
53
- }
54
- if (condition.startsWith(".")) {
55
- return component.isMatchingNameOrAlias(condition.slice(1))
56
- }
57
-
58
- // Check for attribute selector
59
- const match = condition.match(/\[(\w+)=['"]?(.+?)['"]?\]/)
60
- if (!match) return true
61
- const [, prop, value] = match
62
- return component.props[prop].toString() === value
63
- })
64
- }
1
+ export * from "./is-matching-selector"
2
+ export * from "./is-matching-path-selector"
@@ -0,0 +1,32 @@
1
+ import type { PrimitiveComponent } from "lib/components"
2
+ import type { Primitive } from "schematic-symbols/drawing/types"
3
+
4
+ import { isMatchingSelector } from "./is-matching-selector"
5
+
6
+ /**
7
+ * Determines if a component matches a path selector, meaning that the last
8
+ * selector matches the current component, and the previous selectors match
9
+ * the parent components.
10
+ */
11
+ export function isMatchingPathSelector(
12
+ component: PrimitiveComponent,
13
+ selector: string,
14
+ ): boolean {
15
+ const selectorParts = selector.split(/\> /g).map((part) => part.trim())
16
+ let currentComponent: PrimitiveComponent | null = component
17
+
18
+ // Iterate through selector parts from right to left
19
+ for (let i = selectorParts.length - 1; i >= 0; i--) {
20
+ if (!currentComponent) return false
21
+
22
+ if (!isMatchingSelector(currentComponent, selectorParts[i])) {
23
+ return false
24
+ }
25
+
26
+ // Move to the parent component for the next iteration
27
+ currentComponent = currentComponent.parent
28
+ }
29
+
30
+ // If we've matched all parts of the selector, it's a match
31
+ return true
32
+ }
@@ -0,0 +1,64 @@
1
+ import type { PrimitiveComponent } from "lib/components"
2
+ import type { Primitive } from "schematic-symbols/drawing/types"
3
+
4
+ /**
5
+ * Determines if a component matches a given selector.
6
+ *
7
+ * This function supports the following selector types:
8
+ * - ID selectors (#id)
9
+ * - Class selectors (.className)
10
+ * - Type selectors (resistor)
11
+ * - Attribute selectors ([key='value'])
12
+ *
13
+ * It also supports combinations of these selectors.
14
+ *
15
+ * @param component - The component to check.
16
+ * @param selector - The selector string to match against.
17
+ * @returns True if the component matches the selector, false otherwise.
18
+ */
19
+ export function isMatchingSelector(
20
+ component: PrimitiveComponent,
21
+ selector: string,
22
+ ): boolean {
23
+ // Check for ID selector
24
+ const idMatch = selector.match(/^#(\w+)/)
25
+ if (idMatch) {
26
+ return component.props.id === idMatch[1]
27
+ }
28
+
29
+ // Check for class selector
30
+ const classMatch = selector.match(/^\.(\w+)/)
31
+ if (classMatch) {
32
+ return component.isMatchingNameOrAlias(classMatch[1])
33
+ }
34
+
35
+ // Split the selector into type and conditions
36
+ let [type, ...conditions] = selector.split(/(?=[#.[])/)
37
+
38
+ if (type === "pin") type = "port"
39
+
40
+ // Check if the component type matches
41
+ if (
42
+ type &&
43
+ type !== "*" &&
44
+ component.lowercaseComponentName !== type.toLowerCase()
45
+ ) {
46
+ return false
47
+ }
48
+
49
+ // Check all conditions
50
+ return conditions.every((condition) => {
51
+ if (condition.startsWith("#")) {
52
+ return component.props.id === condition.slice(1)
53
+ }
54
+ if (condition.startsWith(".")) {
55
+ return component.isMatchingNameOrAlias(condition.slice(1))
56
+ }
57
+
58
+ // Check for attribute selector
59
+ const match = condition.match(/\[(\w+)=['"]?(.+?)['"]?\]/)
60
+ if (!match) return true
61
+ const [, prop, value] = match
62
+ return component.props[prop].toString() === value
63
+ })
64
+ }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@tscircuit/core",
3
3
  "module": "index.ts",
4
4
  "type": "module",
5
- "version": "0.0.42",
5
+ "version": "0.0.44",
6
6
  "types": "dist/index.d.ts",
7
7
  "main": "dist/index.js",
8
8
  "files": [
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@lume/kiwi": "^0.4.3",
37
- "@tscircuit/infgrid-ijump-astar": "^0.0.6",
37
+ "@tscircuit/infgrid-ijump-astar": "^0.0.9",
38
38
  "@tscircuit/props": "^0.0.62",
39
39
  "@tscircuit/soup": "^0.0.66",
40
40
  "@tscircuit/soup-util": "0.0.18",