bst-docs 0.0.2__tar.gz → 0.0.3__tar.gz

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.
@@ -5,4 +5,3 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
5
5
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
6
 
7
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
-
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bst-docs
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: API Reference Generator for Buildstream Projects
5
5
  Author-email: Aedan McHale <aedan.mchale@gmail.com>
6
6
  License-Expression: MIT
@@ -8,6 +8,7 @@ import click
8
8
  import tqdm
9
9
 
10
10
  from bst_docs.load_contents import load_project
11
+ from bst_docs.render import RenderConfig
11
12
 
12
13
 
13
14
  @click.command()
@@ -38,6 +39,24 @@ from bst_docs.load_contents import load_project
38
39
  " otherwise pure Commonmark markdown will be used"
39
40
  ),
40
41
  )
42
+ @click.option(
43
+ "--html-links",
44
+ default=False,
45
+ required=False,
46
+ help=(
47
+ "If true, markdown link extensions will be converted to .html"
48
+ " and html elements will be enabled"
49
+ ),
50
+ )
51
+ @click.option(
52
+ "--all-html-fixes",
53
+ default=False,
54
+ required=False,
55
+ help=(
56
+ "If true, all html level fixes will be applied"
57
+ " This is designed for when html rendering will be done after the fact"
58
+ ),
59
+ )
41
60
  @click.argument("path", default=".")
42
61
  def build(
43
62
  path: str,
@@ -45,7 +64,9 @@ def build(
45
64
  **kwargs: str,
46
65
  ) -> None:
47
66
  """Generate documentation for a BuildStream project."""
48
- html_elements: bool = bool(kwargs.get("html_elements"))
67
+ config = RenderConfig(
68
+ **kwargs,
69
+ )
49
70
 
50
71
  if kwargs.get("clean"):
51
72
  shutil.rmtree(".cache")
@@ -70,7 +91,7 @@ def build(
70
91
  except StopIteration:
71
92
  logging.warning(str(f"Unfound dependency {dep} for {f.name}"))
72
93
  for f in tqdm.tqdm(files, "Writing Output"):
73
- f.write_file(dst, use_html=html_elements)
94
+ f.write_file(dst, config=config)
74
95
 
75
96
 
76
97
  if __name__ == "__main__":
@@ -8,7 +8,12 @@ from pathlib import Path
8
8
 
9
9
  import mdformat
10
10
 
11
- from bst_docs.render import add_summary_block, render_code_section, render_value
11
+ from bst_docs.render import (
12
+ RenderConfig,
13
+ add_summary_block,
14
+ render_code_section,
15
+ render_value,
16
+ )
12
17
 
13
18
 
14
19
  # TODO: replace this with builstream element
@@ -71,7 +76,7 @@ class Element:
71
76
  def _format_link_list(
72
77
  self,
73
78
  depend_kind: str,
74
- use_html: bool,
79
+ config: RenderConfig,
75
80
  depends_dict: dict,
76
81
  ) -> str:
77
82
  """Format a dependency list as HTML or Markdown links."""
@@ -79,6 +84,8 @@ class Element:
79
84
  if not depend_items:
80
85
  return ""
81
86
 
87
+ link_ext = ".html" if config.use_html_exts else ".md"
88
+
82
89
  link_list = []
83
90
  for item in depend_items:
84
91
  rendered = ""
@@ -88,25 +95,27 @@ class Element:
88
95
  rel_path = os.path.relpath(
89
96
  (self.element_base / item),
90
97
  self.absolute_path.parent,
91
- ).replace(".bst", ".md")
98
+ ).replace(".bst", link_ext)
92
99
  rendered = (
93
100
  (
94
101
  f'<a href="{rel_path}">{item}</a>'
95
- if use_html
102
+ if config.use_html
96
103
  else f"[{item}]({rel_path})"
97
104
  )
98
105
  if ":" not in item
99
- else render_value(item)
106
+ else render_value(item, config)
100
107
  )
101
108
  case _others:
102
- rendered = render_value(item)
103
- link_list.append(f"<li>{rendered}</li>" if use_html else f"- {rendered}")
109
+ rendered = render_value(item, config)
110
+ link_list.append(
111
+ f"<li>{rendered}</li>" if config.use_html else f"- {rendered}",
112
+ )
104
113
  content = (
105
114
  f"<ul>\n{'\n'.join(link_list)}\n<ul>" # no hard tabs
106
- if use_html
115
+ if config.use_html
107
116
  else "\n".join(link_list)
108
117
  )
109
- return add_summary_block(depend_kind.title(), content, use_html)
118
+ return add_summary_block(depend_kind.title(), content, config)
110
119
 
111
120
  def all_dependencies(self) -> dict[str, list]:
112
121
  """All dependencies of this element."""
@@ -115,16 +124,16 @@ class Element:
115
124
  output[depend_kind] = self._conf.get(depend_kind, [])
116
125
  return output
117
126
 
118
- def _render_field(self, element: str, use_html: bool) -> str:
127
+ def _render_field(self, element: str, config: RenderConfig) -> str:
119
128
  """Render a named configuration field as a section."""
120
129
  return (
121
130
  f"## {element.title()}\n\n"
122
- + render_value(self._conf.get(element, {}), use_html)
131
+ + render_value(self._conf.get(element, {}), config)
123
132
  if self._conf.get(element, {})
124
133
  else ""
125
134
  )
126
135
 
127
- def summary_page(self, use_html: bool) -> str:
136
+ def summary_page(self, config: RenderConfig) -> str:
128
137
  """Generate the full summary page content for this element."""
129
138
  return f"""
130
139
  # {Path(self.name).name}
@@ -134,33 +143,33 @@ class Element:
134
143
 
135
144
  ## Dependencies
136
145
 
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)}
146
+ {self._format_link_list("depends", config, self._conf)}
147
+ {self._format_link_list("build-depends", config, self._conf)}
148
+ {self._format_link_list("runtime-depends", config, self._conf)}
140
149
 
141
150
  ## 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)}
151
+ {self._format_link_list("depends", config, self.dependants)}
152
+ {self._format_link_list("build-depends", config, self.dependants)}
153
+ {self._format_link_list("runtime-depends", config, self.dependants)}
145
154
 
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)}
155
+ {self._render_field("variables", config)}
156
+ {self._render_field("environment", config)}
157
+ {self._render_field("environment-nocache", config)}
158
+ {self._render_field("config", config)}
159
+ {self._render_field("public", config)}
160
+ {self._render_field("sources", config)}
152
161
 
153
162
  ## Raw Content
154
163
 
155
- {add_summary_block("Raw Text", render_code_section(self.raw, use_html), use_html)}
164
+ {add_summary_block("Raw Text", render_code_section(self.raw, config), config)}
156
165
 
157
166
  """
158
167
 
159
- def write_file(self, parent: Path, use_html: bool) -> None:
168
+ def write_file(self, parent: Path, config: RenderConfig) -> None:
160
169
  """Write the rendered summary page to disk."""
161
170
  dst = parent / self.doc_path
162
171
  dst.parent.mkdir(parents=True, exist_ok=True)
163
- text = self.summary_page(use_html)
172
+ text = self.summary_page(config)
164
173
  text = mdformat.text(text).replace("\t", " ")
165
174
  dst.write_text(text)
166
175
  logging.debug("Logged element % to %", self.name, dst)
@@ -0,0 +1,115 @@
1
+ """Rendering utilities for HTML and Markdown output."""
2
+
3
+ import dataclasses
4
+ from typing import Any
5
+
6
+
7
+ @dataclasses.dataclass
8
+ class RenderConfig:
9
+ """Configuration for rendering output."""
10
+
11
+ all_html_fixes: bool
12
+ use_html: bool
13
+ use_html_exts: bool
14
+
15
+ def __init__(self, **kwargs: str) -> None:
16
+ """Initialize RenderConfig."""
17
+ self.all_html_fixes = bool(kwargs.get("all-html-fixes", False))
18
+ self.use_html_exts = self.all_html_fixes or bool(
19
+ kwargs.get("use-html-exts", False),
20
+ )
21
+ self.use_html = self.all_html_fixes or bool(
22
+ kwargs.get("html-elements", False),
23
+ )
24
+
25
+
26
+ def html_ul_from_list(list_obj: list, config: RenderConfig) -> str:
27
+ """Render a list as an HTML unordered list."""
28
+ return f"""
29
+ <ul>
30
+ {"\n".join(f"<li>{render_value(x, config)}</li>" for x in list_obj)}
31
+ </ul>
32
+ """
33
+
34
+
35
+ def html_br_from_list(list_obj: list, config: RenderConfig) -> str:
36
+ """Render a list with HTML line breaks."""
37
+ return f"""
38
+ {"\n<br />".join(render_value(x, config) for x in list_obj)}
39
+ """
40
+
41
+
42
+ def html_table_from_dict(d: dict, config: RenderConfig) -> str:
43
+ """Render a dictionary as an HTML table."""
44
+ table_elements: str = "\n".join(
45
+ f"<tr><td>{key}</td><td>{render_value(val, config)}</td></tr>"
46
+ for key, val in d.items()
47
+ )
48
+ return f"""
49
+ <table>
50
+ {table_elements}
51
+ </table>
52
+ """
53
+
54
+
55
+ def md_table_from_dict(d: dict) -> str:
56
+ """Render a dictionary as a Markdown table."""
57
+ return f"""
58
+ | | |
59
+ |--|--|
60
+ {"\n".join(f"|{key}|{val!s}|" for key, val in d.items())}
61
+ """
62
+
63
+
64
+ def render_value(
65
+ v: Any, # noqa: ANN401
66
+ config: RenderConfig,
67
+ ) -> str:
68
+ """Render a value (dict, list, or scalar) as HTML or Markdown."""
69
+ out = ""
70
+ match v:
71
+ case dict():
72
+ out = (
73
+ html_table_from_dict(v, config)
74
+ if config.use_html
75
+ else md_table_from_dict(v)
76
+ )
77
+ case list() | set():
78
+ out = (
79
+ (
80
+ html_ul_from_list(v, config)
81
+ if v and not isinstance(v[0], dict)
82
+ else html_br_from_list(v, config)
83
+ )
84
+ if config.use_html
85
+ else "\n- ".join(render_value(x, config) for x in v)
86
+ )
87
+ case _others:
88
+ out = (
89
+ f"<code>{str(v).strip().replace('\n', '</br>')}</code>"
90
+ if config.use_html
91
+ else f"`{str(v).strip()}`"
92
+ )
93
+ return out
94
+
95
+
96
+ def add_summary_block(summary: str, content: str, config: RenderConfig) -> str:
97
+ """Wrap content in an HTML details/summary block or plain text."""
98
+ if not config.use_html:
99
+ return summary + "\n" + content
100
+ return f"""
101
+ <details open>
102
+ <summary>{summary}</summary>
103
+ {content}
104
+ </details>
105
+ """
106
+
107
+
108
+ def render_code_section(content: str, config: RenderConfig) -> str:
109
+ """Render a multiline code block."""
110
+ output = content
111
+ if config.use_html:
112
+ output = f"<pre><code>{content}</code></pre>"
113
+ else:
114
+ output = f"```\n{content.replace('```', r'\`\`\`')}\n```"
115
+ return output
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bst-docs
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: API Reference Generator for Buildstream Projects
5
5
  Author-email: Aedan McHale <aedan.mchale@gmail.com>
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "bst-docs"
3
- version = "0.0.2"
3
+ version = "0.0.3"
4
4
  readme = "README.md"
5
5
  authors = [{ name = "Aedan McHale", email = "aedan.mchale@gmail.com" }]
6
6
  license = "MIT"
@@ -1,87 +0,0 @@
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
File without changes
File without changes
File without changes
File without changes