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