expandPortThrough method

bool expandPortThrough(
  1. String nodeId,
  2. String portId
)

Incrementally expand a port with pass-through traversal.

Like expandPort, but continues through trivial gates (buffers, inverters, slicers, concatenators) until non-trivial children or external ports of nodeId are reached.

Direction semantics:

  • WEST ports (inputs) — the signal flows inward; traversal follows hyperedge targets from the parent port to child INPUT ports, then exits through child OUTPUT ports. CONCAT children may fanout (one output → many sources in the next hyperedge).
  • EAST ports (outputs) — the signal flows outward; traversal follows hyperedge sources from the parent port to child OUTPUT ports, then exits through child INPUT ports. SLICE children may fanout (one input → many targets in the next hyperedge).

The traversal uses a BFS queue of port IDs (child-side) that still need to be matched against hyperedges. Each newly discovered trivial child enqueues its "exit" ports for further exploration.

Returns true if new children/edges were revealed.

Implementation

bool expandPortThrough(String nodeId, String portId) {
  final node = nodeMap[nodeId];
  if (node == null) {
    return false;
  }

  if (node.hiddenChildren == null || node.hiddenChildren!.isEmpty) {
    return false;
  }

  final hyperedges = node.hyperedges;
  if (hyperedges == null || hyperedges.isEmpty) {
    return false;
  }

  // Use shared collection logic to find gates and edges on this port path.
  final (collectedChildIds, collectedHyperedgeIds) =
      _collectPortThroughGatesAndEdges(node, portId);

  if (collectedChildIds.isEmpty && collectedHyperedgeIds.isEmpty) {
    return false;
  }

  // Check idempotency.
  final existingChildren = node.partialChildIds ?? {};
  final existingEdges = node.partialHyperedgeIds ?? {};
  if (existingChildren.containsAll(collectedChildIds) &&
      existingEdges.containsAll(collectedHyperedgeIds)) {
    return false;
  }

  // Additive: merge into existing partial sets.
  final mergedChildren = {...existingChildren, ...collectedChildIds};
  final mergedEdges = {...existingEdges, ...collectedHyperedgeIds};

  node
    ..partialChildIds = mergedChildren
    ..partialHyperedgeIds = mergedEdges;

  return true;
}