import re
import yaml
from pathlib import Path
def parse_summary_md(summary_path: Path) -> list:
nav = []
stack = [(nav, -1)]
with open(summary_path, 'r') as f:
for line in f:
line = line.rstrip()
if not line or line.startswith('#'):
continue
match = re.match(r'^(\s*)- \[(.+?)\]\((.+?)\)', line)
if not match:
continue
indent_str, title, path = match.groups()
indent_level = len(indent_str) // 2
if path == 'intro.md':
pass
if path.endswith('/index.md'):
nav_item = {title: path}
else:
nav_item = {title: path}
while stack and stack[-1][1] >= indent_level:
stack.pop()
current_list = stack[-1][0]
if path.endswith('/index.md') or indent_level < 2:
current_list.append(nav_item)
else:
current_list.append(nav_item)
return nav
def update_mkdocs_nav(mkdocs_path: Path, nav: list):
with open(mkdocs_path, 'r') as f:
config = yaml.safe_load(f)
config['nav'] = nav
with open(mkdocs_path, 'w') as f:
yaml.dump(config, f, default_flow_style=False, sort_keys=False, allow_unicode=True)
print(f"✓ Updated {mkdocs_path} with {len(nav)} top-level navigation items")
def main():
project_root = Path(__file__).parent.parent
summary_path = project_root / 'book' / 'src' / 'SUMMARY.md'
mkdocs_path = project_root / 'mkdocs.yml'
if not summary_path.exists():
print(f"✗ Error: {summary_path} not found")
return 1
if not mkdocs_path.exists():
print(f"✗ Error: {mkdocs_path} not found")
return 1
print(f"📖 Parsing {summary_path}...")
nav = parse_summary_md(summary_path)
print(f"📝 Updating {mkdocs_path}...")
update_mkdocs_nav(mkdocs_path, nav)
print("\n✅ Navigation sync complete!")
print(f" mdbook uses: {summary_path}")
print(f" mkdocs uses: {mkdocs_path}")
print("\nBoth navigation structures now reference the same source files in book/src/")
return 0
if __name__ == '__main__':
exit(main())