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