Skip to content

Commit 04bbea6

Browse files
authored
Docusaurus compatible docs (#51)
1 parent 3ad5bbe commit 04bbea6

File tree

7 files changed

+229
-3
lines changed

7 files changed

+229
-3
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ instance/
7272

7373
# pdoc documentation
7474
/doc
75+
/docusaurus
7576

7677
# PyBuilder
7778
.pybuilder/

docker-compose-test.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
services:
22
fishjam:
3-
image: "ghcr.io/fishjam-cloud/fishjam:${TAG:-edge}"
3+
image: "ghcr.io/fishjam-cloud/fishjam:${TAG:-edge-88258de-1764324482}"
44
container_name: fishjam
55
restart: on-failure
66
healthcheck:

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ format_check = "scripts:run_format_check"
2929
lint = "scripts:run_linter"
3030
fix_lint = "scripts:run_linter_fix"
3131
generate_docs = "scripts:generate_docs"
32+
generate_docusaurus = "scripts:generate_docusaurus"
3233
update_client = "scripts:update_client"
3334
room_manager = "scripts:start_room_manager"
3435

scripts.py

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import re
23
import shutil
34
import subprocess
45
import sys
@@ -55,6 +56,12 @@ def run_linter_fix():
5556

5657

5758
def generate_docs():
59+
here = Path(__file__).parent
60+
input = here / "doc"
61+
62+
if input.exists():
63+
shutil.rmtree(input)
64+
5865
check_exit_code(
5966
"pdoc \
6067
--include-undocumented \
@@ -64,8 +71,6 @@ def generate_docs():
6471
-o doc \
6572
fishjam"
6673
)
67-
here = Path(__file__).parent
68-
input = here / "doc"
6974
input_images = here / "images"
7075
out = here / "docs" / "api"
7176
out_images = here / "docs" / "api" / "images"
@@ -81,6 +86,72 @@ def generate_docs():
8186
f.rename(f.with_suffix(".md"))
8287

8388

89+
def clean_mdx_content(content: str) -> str:
90+
parts = re.split(r"((?:```[\s\S]*?```|`[^`\n]+`))", content)
91+
92+
# example: convert `fishjam._openapi_client.models.peer.Peer` into `Peer`
93+
internal_path_pattern = r"fishjam\.(?:[\w.]+\.)?_[\w.]+\."
94+
95+
cleaned_parts = []
96+
for part in parts:
97+
if part.startswith("`"):
98+
text = (
99+
part.replace("&lt;", "<")
100+
.replace("&gt;", ">")
101+
.replace("&#39;", "'")
102+
.replace("builtins.", "")
103+
)
104+
105+
text = re.sub(internal_path_pattern, "", text)
106+
107+
cleaned_parts.append(text)
108+
else:
109+
text = part.replace("{", "\\{").replace("}", "\\}").replace("<", "&lt;")
110+
111+
cleaned_parts.append(text)
112+
113+
return "".join(cleaned_parts)
114+
115+
116+
def generate_docusaurus():
117+
here = Path(__file__).parent
118+
input = here / "doc"
119+
out = here / "docusaurus"
120+
121+
if input.exists():
122+
shutil.rmtree(input)
123+
if out.exists():
124+
shutil.rmtree(out)
125+
126+
check_exit_code(
127+
"pdoc \
128+
--include-undocumented \
129+
-t templates/docusaurus \
130+
-o doc \
131+
fishjam"
132+
)
133+
try:
134+
os.remove(input / "index.html")
135+
except FileNotFoundError:
136+
pass
137+
138+
out.mkdir(parents=True, exist_ok=True)
139+
140+
for f in input.glob("**/*.html"):
141+
content = f.read_text(encoding="utf-8")
142+
safe_content = clean_mdx_content(content)
143+
rel_path = f.relative_to(input)
144+
dest_path = out / rel_path.with_suffix(".md")
145+
dest_path.parent.mkdir(parents=True, exist_ok=True)
146+
147+
dest_path.write_text(safe_content, encoding="utf-8")
148+
149+
fishjam_dir = out / "fishjam"
150+
submodules_dir = out / "submodules"
151+
152+
fishjam_dir.rename(submodules_dir)
153+
154+
84155
def update_client():
85156
if len(sys.argv) < 2:
86157
raise RuntimeError("Missing fishjam openapi.yaml raw url positional argument")
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
title: {{ module.name }}
3+
sidebar_label: {{ module.name.split(".")[-1] }}
4+
custom_edit_url: null
5+
---
6+
7+
{% block content %}{% endblock %}
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
{% extends "frame.html.jinja2" %}
2+
3+
{% block content %}
4+
# {{ module.name }}
5+
6+
{% block module_info %}
7+
{% if module.docstring and ".. include::" not in module.docstring %}
8+
{{ module.docstring | safe }}
9+
{% endif %}
10+
{% endblock %}
11+
12+
{% block nav_submodules %}
13+
{% if module.submodules %}
14+
## Submodules
15+
{% for submodule in module.submodules if is_public(submodule) | trim %}
16+
- [{{ submodule.name }}](submodules/{{ submodule.name }})
17+
{% endfor %}
18+
{% endif %}
19+
{% endblock %}
20+
21+
{% block module_contents %}
22+
{% for m in module.flattened_own_members if is_public(m) | trim %}
23+
## {{ m.name }}
24+
{{ member(m) }}
25+
{% if m.kind == "class" %}
26+
{% for cm in m.own_members if cm.kind != "class" and is_public(cm) | trim %}
27+
### {{ cm.name }}
28+
{{ member(cm) }}
29+
{% endfor %}
30+
{% set inherited_members = inherited(m) | trim %}
31+
{% if inherited_members %}
32+
#### Inherited Members
33+
{{ inherited_members }}
34+
{% endif %}
35+
{% endif %}
36+
---
37+
{% endfor %}
38+
{% endblock %}
39+
{% endblock content %}
40+
41+
{#
42+
=========================================================================
43+
HELPER MACROS (Markdown Version)
44+
=========================================================================
45+
#}
46+
47+
{% defaultmacro default_value(var) -%}
48+
{% if var.default_value_str and "object object" not in var.default_value_str %}
49+
= {{ var.default_value_str | safe }}
50+
{% endif %}
51+
{% enddefaultmacro %}
52+
53+
{% defaultmacro annotation(var) %}
54+
{% if var.annotation_str %}{{ var.annotation_str }}{% endif %}
55+
{% enddefaultmacro %}
56+
57+
{% defaultmacro function(fn) -%}
58+
{% if fn.name == "__init__" %}
59+
def {{ fn.qualname.split(".")[-1] }}{{ fn.signature_without_self | string | safe }}
60+
{% else %}
61+
def {{ fn.name }}{{ fn.signature | string | safe }}
62+
{% endif %}
63+
{% enddefaultmacro %}
64+
65+
{% defaultmacro variable(var) -%}
66+
{{ var.name }}{{ annotation(var) }}{{ default_value(var) }}
67+
{% enddefaultmacro %}
68+
69+
{% defaultmacro class_bases(cls) %}
70+
{%- if cls.bases -%}
71+
(
72+
{%- for base in cls.bases -%}
73+
{%- if base is mapping or base is iterable and base is not string -%}
74+
{{ base[-1] }}
75+
{%- else -%}
76+
{{ base }}
77+
{%- endif -%}
78+
{%- if loop.nextitem %}, {% endif %}
79+
{%- endfor -%}
80+
)
81+
{%- endif -%}
82+
{% enddefaultmacro %}
83+
84+
{% defaultmacro class(cls) -%}
85+
class {{ cls.qualname }}{{ class_bases(cls) }}:
86+
{% enddefaultmacro %}
87+
88+
{% defaultmacro member(doc) %}
89+
```python
90+
{% if doc.kind == "class" %}{{ class(doc) }}{% elif doc.kind == "function" %}{{ function(doc) }}{% else %}{{ variable(doc) }}{% endif %}
91+
```
92+
{{ doc.docstring | safe }}
93+
{% enddefaultmacro %}
94+
95+
{% defaultmacro is_public(doc) %}
96+
{% if not include_undocumented and not doc.docstring %}
97+
{% elif doc.docstring and "@private" in doc.docstring %}
98+
{% elif doc.name == "__init__" and (doc.docstring or (doc.kind == "function" and doc.signature_without_self.parameters)) %}
99+
true
100+
{% elif doc.name == "__doc__" %}
101+
{% elif doc.kind == "variable" and doc.is_typevar and not doc.docstring %}
102+
{% elif doc.kind == "module" and doc.fullname not in all_modules %}
103+
{% elif (doc.qualname or doc.name) is in(module.obj.__all__ or []) %}
104+
true
105+
{% elif not doc.name.startswith("_") %}
106+
true
107+
{% endif %}
108+
{% enddefaultmacro %}
109+
110+
{% defaultmacro inherited(cls) %}
111+
{% set ignored_bases = ["str", "object", "int", "float", "bool", "list", "dict", "tuple", "set", "exception", "baseexception"] %}
112+
{% for base, members in cls.inherited_members.items() %}
113+
{% set base_name = base.name if base.name is defined else base %}
114+
{% if base_name is mapping or base_name is iterable and base_name is not string %}
115+
{% set base_name = base_name[-1] %}
116+
{% endif %}
117+
118+
{% if base_name | lower not in ignored_bases %}
119+
120+
{% set member_list %}
121+
{% for m in members if is_public(m) | trim %}
122+
* `{{ m.name }}`
123+
{% endfor %}
124+
{% endset %}
125+
126+
{% if member_list | trim %}
127+
* **{{ base_name }}**:
128+
{{ member_list }}
129+
{% endif %}
130+
131+
{% endif %}
132+
{% endfor %}
133+
{% enddefaultmacro %}
134+
135+
{# Empty macros to prevent errors from unused calls in default logic #}
136+
{% defaultmacro bases(cls) %}{% enddefaultmacro %}
137+
{% defaultmacro decorators(doc) %}{% enddefaultmacro %}
138+
{% defaultmacro submodule(mod) %}{% enddefaultmacro %}
139+
{% defaultmacro docstring(var) %}{% enddefaultmacro %}
140+
{% defaultmacro nav_members(members) %}{% enddefaultmacro %}
141+
{% defaultmacro view_source_state(doc) %}{% enddefaultmacro %}
142+
{% defaultmacro view_source_button(doc) %}{% enddefaultmacro %}
143+
{% defaultmacro view_source_code(doc) %}{% enddefaultmacro %}
144+
{% defaultmacro module_name() %}{% enddefaultmacro %}

uv.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)