disposition 0.3.0

SVG diagram generator
Documentation
# Diagram Generation

Diagram generation from an `InputDiagram` into an SVG goes through the following steps:

1. Merge user `InputDiagram` over base `InputDiagram`.

    Source: `InputDiagramMerger` in `crate/input_ir_rt/src/input_diagram_merger.rs`.

2. Calculate diagram intermediate representation (`IrDiagram`) from the merged `InputDiagram`.

    Source: `InputToIrDiagramMapper` in `crate/input_ir_rt/src/input_to_ir_diagram_mapper.rs`.

3. Calculate SVG element node and text coordinates (`TaffyNodeMappings`) using `taffy`.

    Source: `IrToTaffyBuilder` in `crate/input_ir_rt/src/ir_to_taffy_builder.rs`.

    Key construction steps (per dimension, inside `build_taffy_trees_for_dimension`):

    - Diagram node taffy sub-trees are built recursively for all nodes. For each container node,
      `build_taffy_nodes_for_node_with_child_hierarchy` handles its children. When rendering at
      `DiagramLod::Normal` and a node has a description, `MdBlocksParser` parses the markdown text
      into `MdBlock` structures, and `MdNodeBuilder` replaces the single `text_node` with an
      `md_content_node` sub-tree containing per-token and per-image leaves.

    - `EdgeSpacerBuilder::build` is called at the same three trigger points to insert rank-based
      spacers for cross-rank edges (once per entity type per container, plus once per entity type
      at the top level).

    - `EdgeDescriptionBuilder::build` is called at the same three trigger points (once per entity
      type per container with `lca_node_id = Some(&container_id)`, and once per entity type at the
      top level with `lca_node_id = None`). Each call creates `edge_description_container` taffy
      nodes interleaved among the rank containers for all described edges at that LCA level. At
      `DiagramLod::Normal`, `EdgeDescriptionBuilder` also calls `MdNodeBuilder` to replace the
      single description leaf with an `md_content_node` sub-tree for markdown rendering.

    - `EdgeSpacerBuilder::build_edge_desc_container_spacers` is called immediately after each
      `EdgeDescriptionBuilder::build`, inserting spacer leaves inside each
      `edge_description_container` for any other edge whose rank span crosses that container.

    - After layout is computed, `HighlightedSpansComputer::compute` builds `entity_highlighted_spans` for
      node and edge-label text, `HighlightedSpansComputer::compute_edge_desc_containers` builds
      `edge_description_highlighted_spans` for edge description text (legacy single-leaf path),
      `MdSpansComputer::compute` processes node `md_content_node` sub-trees to merge adjacent word
      leaves into consolidated text spans and convert image leaves to image spans (stored in
      `entity_image_spans`), and `MdSpansComputer::compute_edge_descs` processes edge description
      `md_content_node` sub-trees similarly (stored in `edge_description_image_spans`).

4. Calculate SVG elements and edges including attributes (`SvgElements`) based on `IrDiagram` and `TaffyNodeMappings`.

    Source: `TaffyToSvgElementsMapper` in  `crate/input_ir_rt/src/taffy_to_svg_elements_mapper.rs`.

    In addition to node and edge SVG elements, this step now also calls
    `SvgEdgeDescriptionsBuilder::build`, which produces `SvgEdgeDescriptionInfo` values from
    `edge_description_taffy_nodes` and `edge_description_highlighted_spans`. The results are
    stored in `SvgElements::edge_description_infos`.

5. Write SVG string based on `SvgElements`.

    Source: `SvgElementsToSvgMapper` in `crate/input_ir_rt/src/svg_elements_to_svg_mapper.rs`.

    Edge descriptions are rendered as `<g id="{edge_id}__desc" class="edge-description">` elements
    with `<text>` children for each wrapped line, after edge labels and before the closing `</svg>`.