bst-docs 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bst_docs/__init__.py +1 -0
- bst_docs/__main__.py +16 -0
- bst_docs/build.py +77 -0
- bst_docs/element.py +166 -0
- bst_docs/load_contents.py +54 -0
- bst_docs/render.py +87 -0
- bst_docs-0.0.1.dist-info/METADATA +71 -0
- bst_docs-0.0.1.dist-info/RECORD +12 -0
- bst_docs-0.0.1.dist-info/WHEEL +5 -0
- bst_docs-0.0.1.dist-info/entry_points.txt +2 -0
- bst_docs-0.0.1.dist-info/licenses/LICENSE +8 -0
- bst_docs-0.0.1.dist-info/top_level.txt +1 -0
bst_docs/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""API reference generator for buildstream projects."""
|
bst_docs/__main__.py
ADDED
bst_docs/build.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Build command for generating documentation."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import shutil
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
import tqdm
|
|
9
|
+
|
|
10
|
+
from bst_docs.load_contents import load_project
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@click.command()
|
|
14
|
+
@click.option(
|
|
15
|
+
"--depth",
|
|
16
|
+
default=3,
|
|
17
|
+
required=False,
|
|
18
|
+
help="Depth of network crawling to perform",
|
|
19
|
+
)
|
|
20
|
+
@click.option(
|
|
21
|
+
"--output",
|
|
22
|
+
default="./output",
|
|
23
|
+
required=False,
|
|
24
|
+
help="Destination folder for markdown files",
|
|
25
|
+
)
|
|
26
|
+
@click.option(
|
|
27
|
+
"--clean",
|
|
28
|
+
default=False,
|
|
29
|
+
required=False,
|
|
30
|
+
help="Remove all files from cache & output directories",
|
|
31
|
+
)
|
|
32
|
+
@click.option(
|
|
33
|
+
"--html-elements",
|
|
34
|
+
default=True,
|
|
35
|
+
required=False,
|
|
36
|
+
help=(
|
|
37
|
+
"If true, html elements will be embedded in markdown files"
|
|
38
|
+
"otherwise pure Commonmark markdown will be used"
|
|
39
|
+
),
|
|
40
|
+
)
|
|
41
|
+
@click.argument("path", default=".")
|
|
42
|
+
def build(
|
|
43
|
+
path: str,
|
|
44
|
+
output: str,
|
|
45
|
+
**kwargs: str,
|
|
46
|
+
) -> None:
|
|
47
|
+
"""Generate documentation for a BuildStream project."""
|
|
48
|
+
html_elements: bool = bool(kwargs.get("html_elements"))
|
|
49
|
+
|
|
50
|
+
if kwargs.get("clean"):
|
|
51
|
+
shutil.rmtree(".cache")
|
|
52
|
+
logging.warning("Nuking cache: %s", ".cache")
|
|
53
|
+
|
|
54
|
+
dst = Path(output)
|
|
55
|
+
try:
|
|
56
|
+
dst.mkdir()
|
|
57
|
+
except Exception:
|
|
58
|
+
logging.warning("Overwriting %s", dst)
|
|
59
|
+
shutil.rmtree(dst)
|
|
60
|
+
dst.mkdir()
|
|
61
|
+
files, _config = load_project(path)
|
|
62
|
+
|
|
63
|
+
for f in tqdm.tqdm(files, "Finding dependants"):
|
|
64
|
+
for kind, dependencies in f.all_dependencies().items():
|
|
65
|
+
for dep in dependencies:
|
|
66
|
+
dep = dep if isinstance(dep, str) else dep["filename"]
|
|
67
|
+
try:
|
|
68
|
+
element_dep = next(x for x in files if x.bst_name == dep)
|
|
69
|
+
element_dep.dependants[kind].append(f.bst_name)
|
|
70
|
+
except StopIteration:
|
|
71
|
+
logging.warning(str(f"Unfound dependency {dep} for {f.name}"))
|
|
72
|
+
for f in tqdm.tqdm(files, "Writing Output"):
|
|
73
|
+
f.write_file(dst, use_html=html_elements)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
if __name__ == "__main__":
|
|
77
|
+
build.main()
|
bst_docs/element.py
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"""Element data model for BuildStream project elements."""
|
|
2
|
+
|
|
3
|
+
import dataclasses
|
|
4
|
+
import logging
|
|
5
|
+
import os
|
|
6
|
+
import re
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import mdformat
|
|
10
|
+
|
|
11
|
+
from bst_docs.render import add_summary_block, render_code_section, render_value
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# TODO: replace this with builstream element
|
|
15
|
+
@dataclasses.dataclass
|
|
16
|
+
class Element:
|
|
17
|
+
"""BST Element representation."""
|
|
18
|
+
|
|
19
|
+
_conf: dict
|
|
20
|
+
raw: str
|
|
21
|
+
|
|
22
|
+
def __init__(self, _conf: dict, raw: str) -> None:
|
|
23
|
+
"""Initialize Element."""
|
|
24
|
+
self._conf = _conf
|
|
25
|
+
self.raw = raw
|
|
26
|
+
self.dependants: dict[str, list] = {
|
|
27
|
+
"depends": [],
|
|
28
|
+
"build-depends": [],
|
|
29
|
+
"runtime-depends": [],
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def name(self) -> str:
|
|
34
|
+
"""Return the element path."""
|
|
35
|
+
return str(self._conf.get("path", ""))
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def bst_name(self) -> str:
|
|
39
|
+
"""Return the element path."""
|
|
40
|
+
return re.sub(f"^{self._conf.get('element_path', '')}/", "", self.name)
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def doc_path(self) -> str:
|
|
44
|
+
"""Return the markdown file path for this element."""
|
|
45
|
+
return self.name.replace(".bst", ".md")
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def project_base(self) -> Path:
|
|
49
|
+
"""Return the project base path."""
|
|
50
|
+
return Path(self._conf.get("project_base", ""))
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def element_base(self) -> Path:
|
|
54
|
+
"""Return the element subdirectory path."""
|
|
55
|
+
return self.project_base / self._conf.get("element_path", "")
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def absolute_path(self) -> Path:
|
|
59
|
+
"""Return the absolute filesystem path to this element."""
|
|
60
|
+
return self.project_base / self._conf.get("path", "")
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def description(self) -> str:
|
|
64
|
+
"""Return the element description with a summary header."""
|
|
65
|
+
return (
|
|
66
|
+
("## Summary\n\n" + self._conf.get("description", "") + "\n")
|
|
67
|
+
if self._conf.get("description")
|
|
68
|
+
else ""
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
def _format_link_list(
|
|
72
|
+
self,
|
|
73
|
+
depend_kind: str,
|
|
74
|
+
use_html: bool,
|
|
75
|
+
depends_dict: dict,
|
|
76
|
+
) -> str:
|
|
77
|
+
"""Format a dependency list as HTML or Markdown links."""
|
|
78
|
+
depend_items = depends_dict.get(depend_kind, [])
|
|
79
|
+
if not depend_items:
|
|
80
|
+
return ""
|
|
81
|
+
|
|
82
|
+
link_list = []
|
|
83
|
+
for item in depend_items:
|
|
84
|
+
rendered = ""
|
|
85
|
+
|
|
86
|
+
match item:
|
|
87
|
+
case str():
|
|
88
|
+
rel_path = os.path.relpath(
|
|
89
|
+
(self.element_base / item),
|
|
90
|
+
self.absolute_path.parent,
|
|
91
|
+
).replace(".bst", ".md")
|
|
92
|
+
rendered = (
|
|
93
|
+
(
|
|
94
|
+
f'<a href="{rel_path}">{item}</a>'
|
|
95
|
+
if use_html
|
|
96
|
+
else f"[{item}]({rel_path})"
|
|
97
|
+
)
|
|
98
|
+
if ":" not in item
|
|
99
|
+
else render_value(item)
|
|
100
|
+
)
|
|
101
|
+
case _others:
|
|
102
|
+
rendered = render_value(item)
|
|
103
|
+
link_list.append(f"<li>{rendered}</li>" if use_html else f"- {rendered}")
|
|
104
|
+
content = (
|
|
105
|
+
f"<ul>\n{'\n'.join(link_list)}\n<ul>" # no hard tabs
|
|
106
|
+
if use_html
|
|
107
|
+
else "\n".join(link_list)
|
|
108
|
+
)
|
|
109
|
+
return add_summary_block(depend_kind.title(), content, use_html)
|
|
110
|
+
|
|
111
|
+
def all_dependencies(self) -> dict[str, list]:
|
|
112
|
+
"""All dependencies of this element."""
|
|
113
|
+
output = {}
|
|
114
|
+
for depend_kind in ["depends", "runtime-depends", "build-depends"]:
|
|
115
|
+
output[depend_kind] = self._conf.get(depend_kind, [])
|
|
116
|
+
return output
|
|
117
|
+
|
|
118
|
+
def _render_field(self, element: str, use_html: bool) -> str:
|
|
119
|
+
"""Render a named configuration field as a section."""
|
|
120
|
+
return (
|
|
121
|
+
f"## {element.title()}\n\n"
|
|
122
|
+
+ render_value(self._conf.get(element, {}), use_html)
|
|
123
|
+
if self._conf.get(element, {})
|
|
124
|
+
else ""
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
def summary_page(self, use_html: bool) -> str:
|
|
128
|
+
"""Generate the full summary page content for this element."""
|
|
129
|
+
return f"""
|
|
130
|
+
# {Path(self.name).name}
|
|
131
|
+
|
|
132
|
+
`{self._conf.get("kind", "Unknown")}`
|
|
133
|
+
{self.description or "--"}
|
|
134
|
+
|
|
135
|
+
## Dependencies
|
|
136
|
+
|
|
137
|
+
{self._format_link_list("depends", use_html, self._conf)}
|
|
138
|
+
{self._format_link_list("build-depends", use_html, self._conf)}
|
|
139
|
+
{self._format_link_list("runtime-depends", use_html, self._conf)}
|
|
140
|
+
|
|
141
|
+
## Dependants
|
|
142
|
+
{self._format_link_list("depends", use_html, self.dependants)}
|
|
143
|
+
{self._format_link_list("build-depends", use_html, self.dependants)}
|
|
144
|
+
{self._format_link_list("runtime-depends", use_html, self.dependants)}
|
|
145
|
+
|
|
146
|
+
{self._render_field("variables", use_html)}
|
|
147
|
+
{self._render_field("environment", use_html)}
|
|
148
|
+
{self._render_field("environment-nocache", use_html)}
|
|
149
|
+
{self._render_field("config", use_html)}
|
|
150
|
+
{self._render_field("public", use_html)}
|
|
151
|
+
{self._render_field("sources", use_html)}
|
|
152
|
+
|
|
153
|
+
## Raw Content
|
|
154
|
+
|
|
155
|
+
{add_summary_block("Raw Text", render_code_section(self.raw, use_html), use_html)}
|
|
156
|
+
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
def write_file(self, parent: Path, use_html: bool) -> None:
|
|
160
|
+
"""Write the rendered summary page to disk."""
|
|
161
|
+
dst = parent / self.doc_path
|
|
162
|
+
dst.parent.mkdir(parents=True, exist_ok=True)
|
|
163
|
+
text = self.summary_page(use_html)
|
|
164
|
+
text = mdformat.text(text).replace("\t", " ")
|
|
165
|
+
dst.write_text(text)
|
|
166
|
+
logging.debug("Logged element % to %", self.name, dst)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Load and parse BuildStream project configuration."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import validators
|
|
7
|
+
from git import Repo
|
|
8
|
+
from yaml import safe_load
|
|
9
|
+
|
|
10
|
+
from bst_docs.element import Element
|
|
11
|
+
|
|
12
|
+
DEFAULT_PROJECT_CONF = "project.conf"
|
|
13
|
+
CACHE_DIR = Path("./.cache")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def load_project(path: str | Path) -> tuple[list[Element], dict]:
|
|
17
|
+
"""Load a BuildStream project from a URL or local path."""
|
|
18
|
+
output = ([], {})
|
|
19
|
+
if validators.url(path):
|
|
20
|
+
git_repo_name = str(path).split("/")[-1].replace(".git", "")
|
|
21
|
+
dst_repo = CACHE_DIR / git_repo_name
|
|
22
|
+
if not dst_repo.exists():
|
|
23
|
+
Repo.clone_from(path, dst_repo)
|
|
24
|
+
else:
|
|
25
|
+
logging.info("Using cached %s", git_repo_name)
|
|
26
|
+
path = CACHE_DIR / git_repo_name
|
|
27
|
+
if Path(path).resolve().exists():
|
|
28
|
+
output = load_local_project(Path(path).resolve())
|
|
29
|
+
return output
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def load_local_project(path: Path) -> tuple[list[Element], dict]:
|
|
33
|
+
"""Load a BuildStream project from a local filesystem path."""
|
|
34
|
+
conf_path: Path = path / DEFAULT_PROJECT_CONF
|
|
35
|
+
assert (conf_path).exists(), "Project could not be loaded (no configuration file)"
|
|
36
|
+
conf = safe_load(conf_path.read_text())
|
|
37
|
+
element_path: Path = path / conf.get("element-path", "elements")
|
|
38
|
+
assert (conf_path).exists(), "Project could not be loaded (no element path)"
|
|
39
|
+
elements: list[Element] = []
|
|
40
|
+
for f in element_path.glob("**/*.bst"):
|
|
41
|
+
raw = f.read_text("utf-8")
|
|
42
|
+
yml = safe_load(raw)
|
|
43
|
+
elements.append(
|
|
44
|
+
Element(
|
|
45
|
+
yml
|
|
46
|
+
| {
|
|
47
|
+
"path": f.relative_to(path),
|
|
48
|
+
"project_base": path,
|
|
49
|
+
"element_path": element_path.relative_to(path),
|
|
50
|
+
},
|
|
51
|
+
raw,
|
|
52
|
+
),
|
|
53
|
+
)
|
|
54
|
+
return elements, conf
|
bst_docs/render.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""Rendering utilities for HTML and Markdown output."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def html_ul_from_list(list_obj: list) -> str:
|
|
7
|
+
"""Render a list as an HTML unordered list."""
|
|
8
|
+
return f"""
|
|
9
|
+
<ul>
|
|
10
|
+
{"\n".join(f"<li>{render_value(x)}</li>" for x in list_obj)}
|
|
11
|
+
</ul>
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def html_br_from_list(list_obj: list) -> str:
|
|
16
|
+
"""Render a list with HTML line breaks."""
|
|
17
|
+
return f"""
|
|
18
|
+
{"\n<br />".join(render_value(x, True) for x in list_obj)}
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def html_table_from_dict(d: dict) -> str:
|
|
23
|
+
"""Render a dictionary as an HTML table."""
|
|
24
|
+
table_elements: str = "\n".join(
|
|
25
|
+
f"<tr><td>{key}</td><td>{render_value(val)}</td></tr>" for key, val in d.items()
|
|
26
|
+
)
|
|
27
|
+
return f"""
|
|
28
|
+
<table>
|
|
29
|
+
{table_elements}
|
|
30
|
+
</table>
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def md_table_from_dict(d: dict) -> str:
|
|
35
|
+
"""Render a dictionary as a Markdown table."""
|
|
36
|
+
return f"""
|
|
37
|
+
| | |
|
|
38
|
+
|--|--|
|
|
39
|
+
{"\n".join(f"|{key}|{val!s}|" for key, val in d.items())}
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def render_value(v: Any, use_html: bool = True) -> str: # noqa: ANN401
|
|
44
|
+
"""Render a value (dict, list, or scalar) as HTML or Markdown."""
|
|
45
|
+
out = ""
|
|
46
|
+
match v:
|
|
47
|
+
case dict():
|
|
48
|
+
out = html_table_from_dict(v) if use_html else md_table_from_dict(v)
|
|
49
|
+
case list() | set():
|
|
50
|
+
out = (
|
|
51
|
+
(
|
|
52
|
+
html_ul_from_list(v)
|
|
53
|
+
if v and not isinstance(v[0], dict)
|
|
54
|
+
else html_br_from_list(v)
|
|
55
|
+
)
|
|
56
|
+
if use_html
|
|
57
|
+
else "\n- ".join(render_value(x, use_html) for x in v)
|
|
58
|
+
)
|
|
59
|
+
case _others:
|
|
60
|
+
out = (
|
|
61
|
+
f"<code>{str(v).strip().replace('\n', '</br>')}</code>"
|
|
62
|
+
if use_html
|
|
63
|
+
else f"`{str(v).strip()}`"
|
|
64
|
+
)
|
|
65
|
+
return out
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def add_summary_block(summary: str, content: str, use_html: bool) -> str:
|
|
69
|
+
"""Wrap content in an HTML details/summary block or plain text."""
|
|
70
|
+
if not use_html:
|
|
71
|
+
return summary + "\n" + content
|
|
72
|
+
return f"""
|
|
73
|
+
<details>
|
|
74
|
+
<summary>{summary}</summary>
|
|
75
|
+
{content}
|
|
76
|
+
</details>
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def render_code_section(content: str, use_html: bool) -> str:
|
|
81
|
+
"""Render a multiline code block."""
|
|
82
|
+
output = content
|
|
83
|
+
if use_html:
|
|
84
|
+
output = f"<pre><code>{content}</code></pre>"
|
|
85
|
+
else:
|
|
86
|
+
output = f"```\n{content.replace('```', r'\`\`\`')}\n```"
|
|
87
|
+
return output
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bst-docs
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: API Reference Generator for Buildstream Projects
|
|
5
|
+
Author-email: Aedan McHale <aedan.mchale@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://gitlab.com/Aedan.mchale/bst-docs
|
|
8
|
+
Classifier: Programming Language :: Python
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
16
|
+
Requires-Python: >=3.12
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: buildstream>=2.7.0
|
|
20
|
+
Requires-Dist: click>=8.4.1
|
|
21
|
+
Requires-Dist: gitpython>=3.1.50
|
|
22
|
+
Requires-Dist: mdformat>=1.0.0
|
|
23
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
24
|
+
Requires-Dist: tqdm>=4.68.2
|
|
25
|
+
Requires-Dist: ty>=0.0.43
|
|
26
|
+
Requires-Dist: validators>=0.35.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: build>=1.5.0; extra == "dev"
|
|
29
|
+
Requires-Dist: prek>=0.4.4; extra == "dev"
|
|
30
|
+
Requires-Dist: ruff>=0.15.15; extra == "dev"
|
|
31
|
+
Requires-Dist: twine>=6.2.0; extra == "dev"
|
|
32
|
+
Requires-Dist: zensical>=0.0.44; extra == "dev"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# bst-docs
|
|
36
|
+
|
|
37
|
+
This is a
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
To build a documentation folder for a given repo:
|
|
42
|
+
`uv run bst-docs build $REPO_PATH`
|
|
43
|
+
|
|
44
|
+
Or to build a documentation folder for a network repo (clones using your `.netrc`):
|
|
45
|
+
`uv run bst-docs build $REPO_URL`
|
|
46
|
+
|
|
47
|
+
These commands will produce a folder full of markdown files which can then be imported into the documentation portal of your choosing.
|
|
48
|
+
|
|
49
|
+
An example zensical.toml has been provided to view the results in `./output`, to use:
|
|
50
|
+
`uv run zensical serve`
|
|
51
|
+
|
|
52
|
+
### Configuration Options
|
|
53
|
+
|
|
54
|
+
```shell
|
|
55
|
+
Usage: bst-docs build [OPTIONS] [PATH]
|
|
56
|
+
|
|
57
|
+
Options:
|
|
58
|
+
--depth INTEGER Depth of network crawling to perform
|
|
59
|
+
--output TEXT Destination folder for markdown files
|
|
60
|
+
--clean BOOLEAN Remove all files from cache & output directories
|
|
61
|
+
--html-elements BOOLEAN If true, html elements will be embedded in markdown
|
|
62
|
+
files otherwise pure Commonmark markdown will be
|
|
63
|
+
used
|
|
64
|
+
--overwrite BOOLEAN Overwrite output directory if true, otherwise
|
|
65
|
+
errors if output files exist
|
|
66
|
+
--help Show this message and exit.
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Design Choices
|
|
70
|
+
|
|
71
|
+
- Should be possible to render everything as MD, html is for nicenesses
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
bst_docs/__init__.py,sha256=bVzVAPrxVBdHhgcGaigNV_yoNY_oPxGSXD7uLpDxxDg,56
|
|
2
|
+
bst_docs/__main__.py,sha256=g56B2qPR7PS8zZhbMptnQiIhPs1f-jftnVlb6CVwqbg,226
|
|
3
|
+
bst_docs/build.py,sha256=e2xjP5KGj8_Z-L3DwT5aqihc4j7S16TCsOqe177lcjU,2009
|
|
4
|
+
bst_docs/element.py,sha256=QoM3y85Qgg-HvbBgOAy9iBWlzjp0MG4qjZTVIAFANZk,5359
|
|
5
|
+
bst_docs/load_contents.py,sha256=O3GeeQbD2ny0-KWCpazja0WuNj3fUyy79TqW5WTQULA,1815
|
|
6
|
+
bst_docs/render.py,sha256=Z3Vn5knMo84_vQyja5tfU1Jrjk3jM1Y9MMrieYvz7cw,2328
|
|
7
|
+
bst_docs-0.0.1.dist-info/licenses/LICENSE,sha256=IMK1Cqf2Y26SwoVQqgqEeii3KR-HKi7O3Qf3Jecc5vM,1061
|
|
8
|
+
bst_docs-0.0.1.dist-info/METADATA,sha256=ZzsNrqUil3JiZkZifehQblpANhMlxss4mKIIe9Tm-cw,2469
|
|
9
|
+
bst_docs-0.0.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
10
|
+
bst_docs-0.0.1.dist-info/entry_points.txt,sha256=abhS86AQY9SzCI1mTzD8mmPd-6oRbc7xEqUvi3fy8-4,51
|
|
11
|
+
bst_docs-0.0.1.dist-info/top_level.txt,sha256=3fYXMvehhejDN7TTvOT0B_rX8MO3Ob4ZcX7H6iQR_qk,9
|
|
12
|
+
bst_docs-0.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Copyright 2026 Aedan McHale
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
8
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
bst_docs
|