findLogicalContainer function

InlineContainerNode? findLogicalContainer(
  1. FNode root,
  2. String fragmentId, {
  3. Map<String, InlineContainerNode?>? logicalContainerCache,
})

Finds the first InlineContainerNode (Paragraph/ListItem/FluentCell) that contains fragmentId as a direct text descendant. Link is transparent: its fragments belong to the parent container.

If logicalContainerCache is provided (e.g. document's internal cache), it is used for an O(1) lookup instead of a full DFS traversal.

Implementation

InlineContainerNode? findLogicalContainer(
  FNode root,
  String fragmentId, {
  Map<String, InlineContainerNode?>? logicalContainerCache,
}) {
  if (logicalContainerCache != null) {
    return logicalContainerCache[fragmentId];
  }

  InlineContainerNode? search(FNode node, InlineContainerNode? currentContainer) {
    // FluentImage atomic:
    //  - INLINE (inside Paragraph/Link, currentContainer is Paragraph):
    //    it's a fragment of the Paragraph → return the Paragraph.
    //  - BLOCK-LEVEL (parent Root/ListItem/FluentCell, currentContainer
    //    is that "block container"): it's its own logical-line → return
    //    the image itself.
    if (node is FluentImage && node.id == fragmentId) {
      if (currentContainer is Paragraph) return currentContainer;
      return node as InlineContainerNode;
    }
    if (node is HorizontalRule && node.id == fragmentId) {
      return node as InlineContainerNode;
    }
    // Link: transparent, doesn't update currentContainer
    if (node is Link) {
      for (final child in node.getChildren()) {
        final found = search(child, currentContainer);
        if (found != null) return found;
      }
      return null;
    }

    // FluentList / FluentTable: descend without container
    if (node is FluentList || node is FluentTable || node is FluentRow) {
      for (final child in childrenOf(node)) {
        final found = search(child, null);
        if (found != null) return found;
      }
      return null;
    }

    // InlineContainerNode (Paragraph, ListItem, FluentCell): new container
    if (node is InlineContainerNode) {
      final container = node as InlineContainerNode;
      for (final child in container.getChildren()) {
        if (child is FluentList) {
          // Sublists: new container scope
          final found = search(child, null);
          if (found != null) return found;
        } else {
          final found = search(child, container);
          if (found != null) return found;
        }
      }
      return null;
    }

    // Leaf Fragment: check if it's the one searched for
    if (node is Fragment && node.id == fragmentId) {
      return currentContainer;
    }

    return null;
  }

  return search(root, null);
}