-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgenerator.py
139 lines (106 loc) · 4.7 KB
/
generator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
"""Sphinx documentation generator for Vyper contracts."""
import os
from typing import List
from .parser import Contract, Function, Struct
INDEX_RST = """Vyper Smart Contracts Documentation
================================
.. toctree::
:maxdepth: 2
:caption: Contents:
"""
CONF_CONTENT = """# Configuration file for Sphinx documentation
project = 'Vyper Smart Contracts'
copyright = '2023'
author = 'Vyper Developer'
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.napoleon',
'sphinx.ext.viewcode'
]
templates_path = ['_templates']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
html_theme = 'sphinx_rtd_theme'
html_static_path = ['_static']
"""
class SphinxGenerator:
"""Generate Sphinx documentation for Vyper contracts."""
def __init__(self, output_dir: str):
self.output_dir = output_dir
self.docs_dir = os.path.join(output_dir, "docs")
os.makedirs(self.docs_dir, exist_ok=True)
def generate(self, contracts: List[Contract]) -> None:
"""Generate Sphinx documentation."""
self._generate_conf_py()
self._generate_index_rst(contracts)
self._generate_contract_docs(contracts)
def _generate_conf_py(self) -> None:
"""Generate Sphinx configuration file."""
with open(os.path.join(self.docs_dir, "conf.py"), "w", encoding="utf-8") as f:
f.write(CONF_CONTENT)
def _generate_index_rst(self, contracts: List[Contract]) -> None:
"""Generate index.rst file."""
content = INDEX_RST
for contract in contracts:
content += f" {contract.name}\n"
with open(os.path.join(self.docs_dir, "index.rst"), "w", encoding="utf-8") as f:
f.write(content)
def _generate_contract_docs(self, contracts: List[Contract]) -> None:
"""Generate documentation for each contract."""
for contract in contracts:
content = f"{contract.name}\n{'=' * len(contract.name)}\n\n"
if contract.docstring:
content += f"{contract.docstring}\n\n"
if contract.enums:
content += _insert_content_section("Enums")
for enum in contract.enums:
content += enum.generate_docs()
if contract.structs:
content += _insert_content_section("Structs")
for struct in contract.structs:
content += self._generate_struct_docs(struct)
if contract.events:
content += _insert_content_section("Events")
for event in contract.events:
content += event.generate_docs()
if contract.constants:
content += _insert_content_section("Constants")
for constant in contract.constants:
content += constant.generate_docs()
# TODO: fix this
# if contract.variables:
# content += _insert_content_section("Variables")
# for variable in contract.variables:
# content += f".. py:attribute:: {variable.name}\n\n"
# content += f" {f'public({variable.type})' if variable.visibility == 'public' else variable.type}"
if contract.external_functions:
content += _insert_content_section("External Functions")
for func in contract.external_functions:
content += self._generate_function_docs(func)
if contract.internal_functions:
content += _insert_content_section("Internal Functions")
for func in contract.internal_functions:
content += self._generate_function_docs(func)
with open(
os.path.join(self.docs_dir, f"{contract.name}.rst"),
"w",
encoding="utf-8",
) as f:
f.write(content)
@staticmethod
def _generate_function_docs(func: Function) -> str:
params = ", ".join(f"{p.name}: {p.type}" for p in func.params)
return_type = f" -> {func.return_type}" if func.return_type else ""
content = f".. py:function:: {func.name}({params}){return_type}\n\n"
if func.docstring:
content += f" {func.docstring}\n\n"
return content
@staticmethod
def _generate_struct_docs(struct: Struct) -> str:
content = f".. py:class:: {struct.name}\n\n"
for field in struct.fields:
content += f" .. py:attribute:: {struct.name}.{field.name}\n\n"
content += f" {field.type}\n\n"
return content
def _insert_content_section(name: str) -> str:
"""Insert a hyperlinked content section accessible from the docs index."""
return f"{name}\n{'-' * len(name)}\n\n"