Skip to main content

traverse_toctree

Function traverse_toctree 

Source
pub fn traverse_toctree(
    toctree_includes: &BTreeMap<String, Vec<String>>,
    root: &str,
) -> Vec<(Option<String>, String)>
Expand description

Pre-order depth-first walk of toctree_includes from root, yielding (parent, docname) once per document — the first visit wins.

Port of _traverse_toctree (environment/__init__.py:914-939) with one deliberate difference: descent is guarded by the visited set, not just yielding. Sphinx recurses into every child unconditionally and only filters the yields, so a mutual A -> B -> A cycle recurses without bound and raises RecursionError — a real, oracle-verified sphinx 9.1.0 crash (tests/fixtures/env_differential.json records relations: null for the toctree_circular project because of it). For an acyclic graph the two are equivalent: re-descending into an already-visited document can only re-yield documents that were already yielded, and those are filtered out anyway.

The walk is iterative for the same reason it is guarded: an explicit stack cannot overflow on a deep document tree.

Sphinx logs self referenced toctree found. Ignored. (toc.circular) when a document’s toctree includes the document itself, and drops that subtree. The drop is ported; the warning is not, because the branch is unreachable in this pipeline — resolve_entries removes the current document from its own candidate set, so a self-entry never reaches toctree_includes; it is reported at parse time as toctree contains reference to nonexisting document instead (which is exactly what the oracle records for the toctree_self_ref project).