Classes
MenuItem
dataclass
Represents a single menu item with optional hierarchy.
Menu items form hierarchical navigation str…
MenuItem
dataclass Represents a single menu item with optional hierarchy.
Menu items form hierarchical navigation structures with parent-child relationships. Items can be marked as active based on current page URL, and support weight-based sorting for display order.
Creation:
Config file: Explicit menu definitions in bengal.toml
Page frontmatter: Pages register themselves via menu metadata
Section structure: Auto-generated from section hierarchy
Attributes
| Name | Type | Description |
|---|---|---|
name |
str |
Display name for the menu item |
url |
str |
URL path for the menu item |
weight |
int |
Sort weight (lower values appear first) |
parent |
str | None |
Parent menu identifier (for hierarchical menus) |
identifier |
str | None |
Unique identifier (auto-generated from name if not provided) |
icon |
str | None |
Icon name from frontmatter (e.g., 'book', 'folder', 'terminal') |
children |
list[MenuItem] |
Child menu items (populated during menu building) |
active |
bool |
Whether this item matches the current page URL |
active_trail |
bool |
Whether this item is in the active path (has active child) |
Relationships |
— |
|
Methods 4
add_child
Add a child menu item and sort children by weight.
Adds the child to the child…
add_child
def add_child(self, child: MenuItem) -> None
Add a child menu item and sort children by weight.
Adds the child to the children list and immediately sorts all children by weight (ascending). Lower weights appear first in the list.
Parameters 1
child |
MenuItem |
MenuItem to add as a child |
mark_active
Mark this item as active if URL matches current page.
Recursively checks this …
mark_active
def mark_active(self, current_url: str) -> bool
Mark this item as active if URL matches current page.
Recursively checks this item and all children for URL matches. Sets
activeflag if this item matches, andactive_trailflag if any
child matches. URLs are normalized (trailing slashes removed) before
comparison.
Parameters 1
current_url |
str |
Current page URL to match against (will be normalized) |
Returns
True if this item or any child is active, False otherwisebool
—
reset_active
Reset active states for this item and all children.
Recursively clears `active…
reset_active
def reset_active(self) -> None
Reset active states for this item and all children.
Recursively clearsactiveandactive_trailflags. Called before
each page render to ensure fresh state for active item detection.
to_dict
Convert menu item to dictionary for template access.
Creates a dictionary repr…
to_dict
def to_dict(self) -> dict[str, Any]
Convert menu item to dictionary for template access.
Creates a dictionary representation suitable for JSON serialization and template rendering. Recursively converts children to dictionaries.
Returns
Dictionary with name, url, icon, active, active_trail, and children fields.
Children are recursively converted to dictionaries.dict[str, Any]
—
Internal Methods 1
__post_init__
Set identifier from name if not provided.
Automatically generates a slug-like …
__post_init__
def __post_init__(self) -> None
Set identifier from name if not provided.
Automatically generates a slug-like identifier from the menu item name by lowercasing and replacing spaces/underscores with hyphens. This ensures every menu item has a unique identifier for parent-child relationships.
MenuBuilder
Builds hierarchical menu structures from various sources.
Constructs menu hierarchies from config …
MenuBuilder
Builds hierarchical menu structures from various sources.
Constructs menu hierarchies from config definitions, page frontmatter, and section structure. Handles deduplication, cycle detection, and hierarchy building with parent-child relationships.
Creation:
Direct instantiation: MenuBuilder()
- Created by MenuOrchestrator for menu building
- Fresh instance created for each menu build
Attributes
| Name | Type | Description |
|---|---|---|
items |
— | List of MenuItem objects (flat list before hierarchy building) |
_seen_identifiers |
— | Set of seen identifiers for deduplication |
_seen_urls |
— | Set of seen URLs for deduplication |
_seen_names |
— | Set of seen names for deduplication Behavior Notes: - Identifiers: Each MenuItem has an identifier (slug from name by default). Parent references use identifiers. - Cycle detection: build_hierarchy() detects circular references and raises ValueError when a cycle is found. Consumers should surface this early as a configuration error. - Deduplication: Automatically prevents duplicate items by identifier, URL, and name. |
Relationships |
— |
|
Methods 4
add_from_config
Add menu items from configuration file.
Parses menu configuration from bengal.…
add_from_config
def add_from_config(self, menu_config: list[dict[str, Any]]) -> None
Add menu items from configuration file.
Parses menu configuration from bengal.toml or config files and creates MenuItem objects. Skips duplicates automatically and logs debug messages for skipped items.
Parameters 1
menu_config |
list[dict[str, Any]] |
List of menu item dictionaries from config file. Each dict should have: name, url, weight (optional), parent (optional), identifier (optional) |
add_from_page
Add a page to menu based on frontmatter metadata.
Creates a MenuItem from page…
add_from_page
def add_from_page(self, page: Any, menu_name: str, menu_config: dict[str, Any]) -> None
Add a page to menu based on frontmatter metadata.
Creates a MenuItem from page frontmatter menu configuration. Uses page's relative_url for menu item URL (baseurl applied in templates). Skips duplicates automatically.
Parameters 3
page |
Any |
Page object with frontmatter menu configuration |
menu_name |
str |
Name of the menu (e.g., 'main', 'footer'). Currently used for logging, all menus share same builder |
menu_config |
dict[str, Any] |
Menu configuration dictionary from page frontmatter. Should have: name (optional, defaults to page.title), url (optional, defaults to page.relative_url), weight (optional), parent (optional), identifier (optional) |
build_hierarchy
Build hierarchical tree from flat list with validation.
Converts flat list of …
build_hierarchy
def build_hierarchy(self) -> list[MenuItem]
Build hierarchical tree from flat list with validation.
Converts flat list of MenuItem objects into hierarchical tree structure based on parent-child relationships. Validates parent references and detects circular dependencies.
Process:
1. Create lookup map by identifier
2. Validate parent references (warn about orphaned items)
3. Build parent-child relationships
4. Detect cycles (raises ValueError if found)
5. Return root items (items with no parent)
Returns
List of root MenuItem objects (no parent) with children populated.
Empty list if no items or all items have parents.list[MenuItem]
—
mark_active_items
Mark active items in menu tree based on current page URL.
Recursively marks me…
mark_active_items
def mark_active_items(self, current_url: str, menu_items: list[MenuItem]) -> None
Mark active items in menu tree based on current page URL.
Recursively marks menu items as active if their URL matches the current page URL. Also marks items in the active trail (items with active children). Resets all active states before marking to ensure clean state.
Parameters 2
current_url |
str |
Current page URL to match against (will be normalized) |
menu_items |
list[MenuItem] |
List of root MenuItem objects to process (hierarchical tree) |
Internal Methods 5
__init__
__init__
def __init__(self) -> None
_is_duplicate
Check if an item is a duplicate based on identifier, URL, or name.
Checks agai…
_is_duplicate
def _is_duplicate(self, item_id: str | None, item_url: str, item_name: str) -> bool
Check if an item is a duplicate based on identifier, URL, or name.
Checks against previously seen identifiers, URLs, and names to prevent duplicate menu items. An item is considered duplicate if any of these match a previously added item.
Parameters 3
item_id |
str | None |
Item identifier (if any). None is valid (not checked). |
item_url |
str |
Item URL (normalized, trailing slash removed). |
item_name |
str |
Item name (lowercased for case-insensitive comparison). |
Returns
True if duplicate found (identifier, URL, or name matches),
False otherwisebool
—
_track_item
Track an item to prevent future duplicates.
Adds the item's identifier, URL, a…
_track_item
def _track_item(self, item: MenuItem) -> None
Track an item to prevent future duplicates.
Adds the item's identifier, URL, and name to the seen sets for duplicate detection. Called automatically when items are added via add_from_config() or add_from_page().
Parameters 1
item |
MenuItem |
MenuItem to track |
_has_cycle
Detect circular references in menu tree using DFS.
Uses depth-first search to …
_has_cycle
def _has_cycle(self, item: MenuItem, visited: set[str], path: set[str]) -> bool
Detect circular references in menu tree using DFS.
Uses depth-first search to detect cycles in parent-child relationships. A cycle exists if an item appears in its own descendant chain.
Parameters 3
item |
MenuItem |
Current menu item being checked |
visited |
set[str] |
Set of all visited identifiers (for optimization) |
path |
set[str] |
Current path identifiers from root to current item (for cycle detection) |
Returns
True if cycle detected (item appears in its own descendant chain),
False otherwise Algorithm:bool
—
_get_depth
Get maximum depth of menu tree from this item.
Recursively calculates the maxi…
_get_depth
def _get_depth(self, item: MenuItem) -> int
Get maximum depth of menu tree from this item.
Recursively calculates the maximum depth of the menu tree starting from the given item. Used for logging and validation.
Parameters 1
item |
MenuItem |
Root menu item to calculate depth from |
Returns
Maximum depth as integer:int
—