# How TextFlow Handles Different Flowchart Structures and Edge Cases

> Discover how TextFlow handles diverse flowchart structures and edge cases like cycles and duplicates. Learn about its robust rendering strategies in flowchart.py for safe processing.

- Repository: [Junyi Ye/textflow](https://github.com/junyiye/textflow)
- Tags: how-to-guide
- Published: 2026-03-05

---

**TextFlow processes varied flowchart structures through multiple rendering strategies in [`src/flowchart.py`](https://github.com/junyiye/textflow/blob/main/src/flowchart.py), safely handling cycles, duplicate nodes, and unknown shapes by falling back to defaults and defensive query methods.**

TextFlow (available at junyiye/textflow) is a Python library that bridges natural language flowcharts and Mermaid diagram syntax. At its core, the `Flowchart` class in [`src/flowchart.py`](https://github.com/junyiye/textflow/blob/main/src/flowchart.py) implements distinct rendering pipelines to support different visualization layouts while incorporating robust error handling for structural edge cases like graph cycles and missing node references.

## Rendering Strategies for Diverse Flowchart Layouts

The `Flowchart` class provides four distinct export methods in [`src/flowchart.py`](https://github.com/junyiye/textflow/blob/main/src/flowchart.py), each optimized for specific diagramming requirements and structural complexity.

### Standard Mermaid Export

The `to_mermaid()` method generates a straightforward node-and-edge representation. When encountering unknown shape types, the implementation falls back to a rectangular box to prevent malformed syntax. According to the source at lines 84-86, an `else` clause catches any undefined shape values, ensuring the diagram renders even with incomplete shape metadata.

### Link-Based Flow for Cycle Handling

Cyclic flowcharts require careful node tracking to avoid duplicate definitions. The `to_mermaid_link_based_flow()` method (lines 100-124) maintains a `defined_nodes` set to track previously emitted nodes. When traversing edges, it lazily defines target nodes only upon first encounter. This prevents redundant declarations when a node appears multiple times in a cycle or converging path.

### Node-Edge Separation for Clean Layouts

For large diagrams requiring strict separation between declarations and connections, `to_mermaid_node_edge_separation()` (lines 66-88 and 92-100) implements a two-phase export. First, all node definitions are emitted, followed by a separate block containing all edges. This guarantees a clean layout where the visual structure remains readable regardless of connection complexity.

### Sequential Connection Flow

The `to_mermaid_sequential_connection_flow()` method (lines 116-132) preserves the logical order of node creation by emitting a definition immediately before each outgoing edge. This approach ensures the visual flow mirrors the internal dictionary order, which is essential when the sequence of operations carries semantic meaning.

## Defensive Graph Query Utilities

Beyond rendering, TextFlow provides safe query methods that handle missing nodes gracefully without raising exceptions.

### Successor and Predecessor Lookups

The `get_direct_successors()` and `get_direct_predecessors()` methods perform description-based lookups, returning empty lists when a node description cannot be found. This defensive approach allows graph analysis to continue even when querying nodes that may not exist in the current flowchart instance.

### Shortest Path Calculation with BFS

For path analysis, `get_shortest_path_length()` implements a BFS algorithm that correctly handles cycles and disconnected components. When either the start or end node is missing, the method returns `-1` rather than throwing an error (lines 120-130). This implementation ensures robust path finding across complex graph topologies including cyclic structures.

## Handling Node Shapes and Conditional Edges

TextFlow manages visual semantics through strict shape validation and optional edge metadata.

### Shape Validation and Defaults

Each node carries a `shape` field supporting `ellipse`, `box`, `diamond`, and `parallelogram` values. The rendering methods check `node.shape` and select appropriate Mermaid syntax. As implemented in lines 66-86, unknown values default to a rectangular box, preventing diagram generation failures when encountering custom or undefined shape types.

### Optional Edge Conditions

The `add_edge()` method accepts an optional `condition` parameter. During rendering, edges check this field: if `condition` is `None`, a plain connection is emitted; otherwise, the syntax `|"<condition>"|` is included (lines 88-95). This guarantees consistent handling of conditional logic gates while supporting simple sequential flows.

## Working with Shuffle and Reverse Transformations

TextFlow supports diagram manipulation through wrapper methods like `to_mermaid_shuffle()` and `to_mermaid_reverse()`. These methods import helper functions (`shuffle_mermaid`, `reverse_mermaid`) at runtime. If helpers are missing, the library raises a clear exception rather than producing silent output errors, ensuring transparent failure modes during diagram transformation.

## Practical Implementation Example

The following example demonstrates building a cyclic flowchart with conditional edges and querying its properties:

```python
from flowchart import Flowchart

# Build a flowchart with a decision cycle

fc = Flowchart()
fc.add_node("A", "Start", "ellipse")
fc.add_node("B", "Process data", "box")
fc.add_node("C", "Is valid?", "diamond")
fc.add_node("D", "End", "ellipse")

# Create edges including a cycle

fc.add_edge("A", "B")
fc.add_edge("B", "C")
fc.add_edge("C", "D", condition="yes")
fc.add_edge("C", "B", condition="no")  # Cycle back to processing

# Export in different structural formats

print(fc.to_mermaid())
print(fc.to_mermaid_link_based_flow())
print(fc.to_mermaid_node_edge_separation())

# Query graph properties safely

print(fc.get_direct_successors("Process data"))
print(fc.get_shortest_path_length("Start", "End"))  # Returns 3

print(fc.get_max_indegree())  # Analyzes connection density

```

The **link-based** export avoids duplicate definitions of node "B" despite its appearance in multiple edges, while the **node-edge separation** format cleanly partitions declarations from connections. The cycle between "C" and "B" is handled gracefully by the BFS shortest-path algorithm.

## Summary

- **TextFlow** implements four distinct rendering strategies in [`src/flowchart.py`](https://github.com/junyiye/textflow/blob/main/src/flowchart.py) to accommodate different flowchart layouts and structural requirements.
- **Cycle handling** relies on the `defined_nodes` set in `to_mermaid_link_based_flow()` to prevent duplicate node definitions when traversing cyclic graphs.
- **Defensive queries** return `-1` or empty lists for missing nodes rather than raising exceptions, ensuring robust graph analysis.
- **Shape defaults** automatically fall back to rectangular boxes for unknown values, preventing syntax errors in generated Mermaid code.
- **Runtime transformation** helpers raise explicit exceptions when unavailable, avoiding silent failures during shuffle or reverse operations.

## Frequently Asked Questions

### What happens when TextFlow encounters an unsupported node shape?

When a node's shape field contains a value other than `ellipse`, `box`, `diamond`, or `parallelogram`, TextFlow defaults to a rectangular box representation. This fallback occurs in the `to_mermaid()` method at lines 84-86 of [`src/flowchart.py`](https://github.com/junyiye/textflow/blob/main/src/flowchart.py), ensuring diagrams remain valid even with incomplete shape metadata.

### How does TextFlow prevent duplicate node definitions in cyclic flowcharts?

The `to_mermaid_link_based_flow()` method tracks previously defined nodes using a `defined_nodes` set (lines 100-124). Nodes are emitted only on first encounter, preventing redundant definitions when cycles or converging paths cause a node to appear in multiple edge traversals.

### What does TextFlow return when querying a node that does not exist?

Graph query methods such as `get_direct_successors()` and `get_direct_predecessors()` return empty lists for missing nodes, while `get_shortest_path_length()` returns `-1`. This defensive design, implemented in lines 68-78 and 120-130 of [`src/flowchart.py`](https://github.com/junyiye/textflow/blob/main/src/flowchart.py), allows analysis to continue without exception handling for absent nodes.

### Can TextFlow handle flowcharts with cycles?

Yes, TextFlow handles cyclic structures through multiple mechanisms. The link-based renderer tracks defined nodes to avoid infinite loops during export, while the BFS implementation in `get_shortest_path_length()` correctly processes cycles without hanging. Cycles are preserved in the output using standard Mermaid syntax.