xref: /aosp_15_r20/external/fbjni/docs/build_quickref.py (revision 65c59e023c5336bbd4a23be7af78407e3d80e7e7)
1#!/usr/bin/env python3
2# Copyright (c) Facebook, Inc. and its affiliates.
3import collections
4import itertools
5import re
6import sys
7
8
9def main(argv):
10    sections = collections.defaultdict(list)
11    toc = read_toc("docs/quickref_toc.txt")
12    grab_sections("test/DocTests.java", sections)
13    grab_sections("test/jni/doc_tests.cpp", sections)
14
15    missing_code = toc.keys() - sections.keys()
16    if missing_code:
17        raise Exception(f"Missing code for sections: {' '.join(missing_code)}")
18    missing_toc = sections.keys() - toc.keys()
19    if missing_toc:
20        raise Exception(f"Missing toc for sections: {' '.join(missing_toc)}")
21
22    with open("docs/quickref.md", "w") as handle:
23        handle.write("# Quick Reference\n")
24        for section in toc:
25            name = toc[section].strip()
26            handle.write(f"- [{name}](#{anchor(name)})\n")
27        for section in toc:
28            render_section(handle, section, toc[section], sections[section])
29
30
31def anchor(title):
32    anchor = title.lower()
33    anchor = re.sub(" ", "-", anchor)
34    anchor = re.sub(r"[^-\w]", "", anchor)
35    return anchor
36
37
38def read_toc(fname):
39    with open(fname) as handle:
40        return collections.OrderedDict(line.split(" ", 1) for line in handle)
41
42
43def grab_sections(fname, sections):
44    extension = fname.split(".")[1]
45    active_block = None
46
47    with open(fname) as handle:
48        for lnum, line in enumerate(handle):
49            lnum += 1
50            if line.strip().endswith("// END"):
51                active_block = None
52                continue
53            m = re.search(r"// SECTION (\w+)$", line)
54            if m:
55                if active_block is not None:
56                    raise Exception(f"Nested section at {fname}:{lnum}")
57                active_group = m.group(1)
58                active_block = []
59                sections[active_group].append((extension, active_block))
60                continue
61            if line.strip().endswith(" MARKDOWN"):
62                if active_block is None:
63                    raise Exception(f"Orphaned markdown at {fname}:{lnum}")
64                active_block = []
65                sections[active_group].append(("md", active_block))
66                continue
67            if active_block is not None:
68                active_block.append(line)
69
70
71def render_section(out, name, title, blocks):
72    out.write(f"## {title}")
73    for syntax, lines in blocks:
74        if not lines:
75            # This happens with Markdown-first sections
76            continue
77        if syntax != "md":
78            lines = itertools.chain(
79                [f"```{syntax}\n"],
80                lines,
81                ["```\n"],
82            )
83        for line in lines:
84            out.write(line)
85    out.write("\n\n")
86
87
88if __name__ == "__main__":
89    sys.exit(main(sys.argv))
90