Find `module Name = { ... }` blocks and their offset/line ranges. Returns dicts with name, start/end offsets, start/end lines, and parent module name (or None for top-level).
(cleaned: str, offset_to_line)
| 696 | |
| 697 | |
| 698 | def _scan_rescript_modules(cleaned: str, offset_to_line) -> list[dict]: |
| 699 | """Find `module Name = { ... }` blocks and their offset/line ranges. |
| 700 | |
| 701 | Returns dicts with name, start/end offsets, start/end lines, and parent |
| 702 | module name (or None for top-level). |
| 703 | """ |
| 704 | modules: list[dict] = [] |
| 705 | n = len(cleaned) |
| 706 | # Module aliases (`module X = Foo.Bar`) also match _RESCRIPT_MODULE_RE but |
| 707 | # have no brace body — skip them here to avoid the greedy `{`-scanner |
| 708 | # swallowing the next unrelated block (e.g. a `let` body). |
| 709 | alias_starts = { |
| 710 | m.start() for m in _RESCRIPT_MODULE_ALIAS_RE.finditer(cleaned) |
| 711 | } |
| 712 | for match in _RESCRIPT_MODULE_RE.finditer(cleaned): |
| 713 | if match.start() in alias_starts: |
| 714 | continue |
| 715 | name = match.group(1) |
| 716 | header_start = match.start() |
| 717 | # Find the first `{` after the header's `:` or `=`. To avoid grabbing |
| 718 | # a `{` from an unrelated following statement, require that the chars |
| 719 | # between `match.end()` and `brace_open` contain no definition-starting |
| 720 | # keywords (`let`, `type`, `module`, `external`). |
| 721 | brace_open = cleaned.find("{", match.end()) |
| 722 | if brace_open == -1: |
| 723 | continue |
| 724 | between = cleaned[match.end():brace_open] |
| 725 | if re.search( |
| 726 | r"(?:^|\s)(?:let|type|module|external|and)\s", |
| 727 | between, |
| 728 | ): |
| 729 | continue |
| 730 | # Walk braces to find the matching close. |
| 731 | depth = 1 |
| 732 | j = brace_open + 1 |
| 733 | while j < n and depth > 0: |
| 734 | c = cleaned[j] |
| 735 | if c == "{": |
| 736 | depth += 1 |
| 737 | elif c == "}": |
| 738 | depth -= 1 |
| 739 | j += 1 |
| 740 | brace_close = j - 1 if depth == 0 else n - 1 |
| 741 | modules.append({ |
| 742 | "name": name, |
| 743 | "start_off": header_start, |
| 744 | "end_off": brace_close, |
| 745 | "body_start_off": brace_open + 1, |
| 746 | "start_line": offset_to_line(header_start), |
| 747 | "end_line": offset_to_line(brace_close), |
| 748 | "parent": None, |
| 749 | }) |
| 750 | |
| 751 | # Parent = innermost strictly-containing module. |
| 752 | for i, m in enumerate(modules): |
| 753 | parent_name = None |
| 754 | parent_start = -1 |
| 755 | for j, other in enumerate(modules): |
no test coverage detected