Parse README.md text into grouped categories. Returns a list of ParsedGroup dicts containing nested categories. Content between the Projects heading and Resources or Contributing is parsed as categories grouped by bold markers (**Group Name**).
(text: str)
| 434 | |
| 435 | |
| 436 | def parse_readme(text: str) -> list[ParsedGroup]: |
| 437 | """Parse README.md text into grouped categories. |
| 438 | |
| 439 | Returns a list of ParsedGroup dicts containing nested categories. |
| 440 | Content between the Projects heading and Resources or Contributing is parsed |
| 441 | as categories grouped by bold markers (**Group Name**). |
| 442 | """ |
| 443 | md = MarkdownIt("commonmark") |
| 444 | tokens = md.parse(text) |
| 445 | root = SyntaxTreeNode(tokens) |
| 446 | children = root.children |
| 447 | |
| 448 | # Find Projects and section boundaries in one pass. |
| 449 | projects_idx = None |
| 450 | cat_end_idx = None |
| 451 | for i, node in enumerate(children): |
| 452 | if _heading_level(node) in (1, 2): |
| 453 | text_content = _heading_text(node) |
| 454 | if projects_idx is None and text_content == "Projects": |
| 455 | projects_idx = i |
| 456 | elif cat_end_idx is None and text_content in ("Resources", "Contributing"): |
| 457 | cat_end_idx = i |
| 458 | if projects_idx is None: |
| 459 | return [] |
| 460 | |
| 461 | cat_nodes = children[projects_idx + 1 : cat_end_idx or len(children)] |
| 462 | return _parse_grouped_sections(cat_nodes) |