import inspect import json import re import shutil from pathlib import Path from textwrap import shorten from typing import Any, Dict, List, Literal, TextIO, Union from docstring_parser import parse from openbb_terminal.core.sdk.trailmap import Trailmap, get_trailmaps from openbb_terminal.core.session.current_system import set_system_variable set_system_variable("TEST_MODE", True) set_system_variable("LOG_COLLECT", False) website_path = Path(__file__).parent.absolute() CONTENT_PATH = website_path / "content/sdk/reference" SEO_META: Dict[str, Dict[str, Union[str, List[str]]]] = json.loads( (website_path / "metadata/sdk_v3_seo_metadata.json").read_text() ) reference_import = ( 'import ReferenceCard from "@site/src/components/General/NewReferenceCard";\n\n' ) refrence_ul_element = """\n") folder_cmd_cards: List[Dict[str, str]] = reference_cards.get(path, {}) # type: ignore if folder_cmd_cards: f.writelines( [ f"\n\n### Commands\n{refrence_ul_element}\n", create_cmd_cards(folder_cmd_cards), "\n", ] ) def main() -> bool: """Generate markdown files for OpenBB SDK Documentation.""" print("Loading trailmaps...") trailmaps = get_trailmaps() kwargs = {"encoding": "utf-8", "newline": "\n"} print("Generating markdown files...") reference_cards: Dict[Path, List[Dict[str, str]]] = {} for file in CONTENT_PATH.glob("*"): if file.is_file(): file.unlink() else: shutil.rmtree(file) for trailmap in trailmaps: try: if trailmap.location_path[0] == "root": trailmap.location_path[0] = "" model_meta = ( get_function_meta(trailmap, "model") if trailmap.model else None ) view_meta = get_function_meta(trailmap, "view") if trailmap.view else None markdown = generate_markdown(model_meta, view_meta) if trailmap.class_attr == "index": trailmap.class_attr = "index_cmd" filepath = ( CONTENT_PATH / "/".join(trailmap.location_path) / f"{trailmap.class_attr}.md" ) func = trailmap.func_attrs.get( "model", trailmap.func_attrs.get("view", None) ) reference_cards.setdefault(filepath.parent, []).append( dict( title=trailmap.class_attr, description=func.short_doc, # type: ignore url="/".join(trailmap.location_path), ) ) filepath.parent.mkdir(parents=True, exist_ok=True) with open(filepath, "w", **kwargs) as f: # type: ignore f.write(markdown) except Exception as e: print( f"Error generating {trailmap.location_path} {trailmap.class_attr} - {e}" ) return False # Sort reference_cards reference_cards = dict(sorted(reference_cards.items(), key=lambda item: item[0])) with open(CONTENT_PATH / "index.mdx", "w", **kwargs) as f: # type: ignore fname = "OpenBB SDK Reference" rel_path = CONTENT_PATH.relative_to(CONTENT_PATH) write_reference_index(reference_cards, fname, CONTENT_PATH, rel_path, f) with open(CONTENT_PATH / "_category_.json", "w", **kwargs) as f: # type: ignore """Generate category json""" f.write(json.dumps({"label": "Reference", "position": 4}, indent=2)) def gen_category_json(fname: str, path: Path, position: int = 1): """Generate category json""" with open(path / "_category_.json", "w", **kwargs) as f: # type: ignore f.write( json.dumps({"label": fname.title(), "position": position}, indent=2) ) with open(path / "index.mdx", "w", **kwargs) as f: # type: ignore rel_path = path.relative_to(CONTENT_PATH) write_reference_index(reference_cards, fname, path, rel_path, f) def gen_category_recursive(nested_path: Path): """Generate category json recursively""" position = 1 for folder in nested_path.iterdir(): if folder.is_dir(): gen_category_json(folder.name, folder, position) gen_category_recursive(folder) # pylint: disable=cell-var-from-loop position += 1 gen_category_recursive(CONTENT_PATH) print("Markdown files generated, check the functions folder") return True def save_metadata() -> Dict[str, Dict[str, Union[str, List[str]]]]: """Save SEO metadata to json file.""" regex = re.compile( r"---\ntitle: (.*)\ndescription: (.*)\nkeywords:(.*)\n---\n\nimport HeadTitle", re.MULTILINE | re.DOTALL, ) metadata = {} for file in CONTENT_PATH.rglob("*/**/*.md"): context = file.read_text(encoding="utf-8") match = regex.search(context) if match: title, description, keywords = match.groups() key = file.relative_to(CONTENT_PATH).as_posix().removesuffix(".md") metadata[key.replace("/", ".")] = { "title": title, "description": description, "keywords": [ keyword.strip() for keyword in keywords.split("\n- ") if keyword ], } filepath = website_path / "metadata/sdk_v3_seo_metadata.json" with open(filepath, "w", encoding="utf-8", newline="\n") as f: json.dump(metadata, f, indent=2) return metadata if __name__ == "__main__": main()