Skip to content

Commit fcabfc0

Browse files
committed
Update make-tree-html for ox-json
1 parent 0b9acb3 commit fcabfc0

1 file changed

Lines changed: 68 additions & 59 deletions

File tree

contrib/course-material-tree/make-tree-html

Lines changed: 68 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,57 @@
11
#! /usr/bin/env python3
22

3-
from __future__ import print_function
4-
from os.path import join, basename
5-
from urllib.parse import quote_plus
6-
from glob import glob
3+
from __future__ import annotations
4+
5+
from pathlib import Path
76
import re
7+
from dataclasses import dataclass
8+
from glob import glob
9+
from os.path import basename, join
10+
from typing import TYPE_CHECKING, NotRequired, TypedDict
11+
from urllib.parse import quote_plus
12+
13+
14+
if TYPE_CHECKING:
15+
from collections.abc import Mapping, Sequence
816

917

1018
section_nr = [1]
1119

1220

13-
def rewrite_org_element(args, org_el):
14-
el_type = org_el[0]
15-
org_props = org_el[1]
16-
assert org_props is None or isinstance(org_props, dict)
17-
contents = org_el[2:]
21+
class Node(TypedDict):
22+
text: str
23+
link: str
24+
icon: str
25+
section: NotRequired[str]
26+
section_nr: NotRequired[int]
27+
nodes: NotRequired[Sequence[Node]]
28+
opened: NotRequired[bool]
29+
30+
31+
# Assumes org json export from https://github.com/jlumpe/ox-json
32+
def rewrite_org_element(
33+
args, org_el
34+
) -> tuple[Node, Sequence[Node], bool]:
35+
if isinstance(org_el, str):
36+
return {}, [], False
37+
38+
el_type = org_el["$$data_type"]
39+
el_subtype = org_el.get("type")
40+
org_props = org_el["properties"]
41+
assert isinstance(org_props, dict)
42+
contents = org_el["contents"]
1843

1944
had_relate_properties = False
2045
promote_to_parent_level = False
21-
node_props = {}
22-
if el_type == "org-data":
23-
title, = [
24-
subel[1]["key"]
25-
for el in contents
26-
if el[0] == "section"
27-
for subel in el[2:]
28-
if subel[0] == "keyword"
29-
if subel[1]["key"] == "TITLE"]
46+
node_props: Node = {}
47+
if el_type == "org-document":
48+
title = org_props["title"]
3049
node_props["text"] = title
3150

32-
elif el_type == "headline":
51+
elif el_type == "org-node" and el_subtype == "headline":
3352
node_props["text"] = org_props["raw-value"]
3453

35-
prop_container = [
36-
subel[2:]
37-
for el in contents
38-
if el[0] == "section"
39-
for subel in el[2:]
40-
if subel[0] == "property-drawer"]
41-
42-
if prop_container:
43-
prop_kws = prop_container[0]
44-
else:
45-
prop_kws = []
46-
47-
properties = {
48-
ch[1]["key"]: ch[1]["value"]
49-
for ch in prop_kws
50-
if ch[0] == "node-property"
51-
}
54+
properties= org_el.get("drawer", {})
5255

5356
had_relate_properties = had_relate_properties or any(
5457
key.startswith("RELATE_") for key in properties)
@@ -74,21 +77,20 @@ def rewrite_org_element(args, org_el):
7477
and level < len(args.org_level_icon)):
7578
node_props["icon"] = args.org_level_icon[level]
7679

77-
siblings = []
78-
children = []
80+
siblings: list[Node] = []
81+
children: list[Node] = []
7982
node_props["nodes"] = children
8083

8184
for ch in contents:
82-
if isinstance(ch, list):
83-
child_props, child_siblings, promote_child_to_parent_level = \
84-
rewrite_org_element(args, ch)
85-
if "text" in child_props:
86-
if promote_child_to_parent_level:
87-
siblings.append(child_props)
88-
else:
89-
children.append(child_props)
85+
child_props, child_siblings, promote_child_to_parent_level = \
86+
rewrite_org_element(args, ch)
87+
if "text" in child_props:
88+
if promote_child_to_parent_level:
89+
siblings.append(child_props)
90+
else:
91+
children.append(child_props)
9092

91-
children.extend(child_siblings)
93+
children.extend(child_siblings)
9294

9395
if args.org_stop_level:
9496
if (level is not None
@@ -106,12 +108,11 @@ def rewrite_org_element(args, org_el):
106108
return node_props, siblings, promote_to_parent_level
107109

108110

109-
def load_org_json(args, infile_name):
111+
def load_org_json(args, infile_name: str):
110112
# https://github.com/ludios/org-to-json
111113

112114
from json import loads
113-
with open(infile_name, "rb") as inf:
114-
json = loads(inf.read())
115+
json = loads(Path(infile_name).read_bytes())
115116

116117
node_props, siblings, promote_to_parent_level = \
117118
rewrite_org_element(args, json)
@@ -156,20 +157,25 @@ def find_section_nodes(section_dict, node):
156157
find_section_nodes(section_dict, subnode)
157158

158159

160+
@dataclass(frozen=True)
159161
class RenderSettings:
160-
def __init__(self, default_icon, number_sections, tree_replacements):
161-
self.default_icon = default_icon
162-
self.number_sections = number_sections
163-
self.tree_replacements = tree_replacements
162+
default_icon: str
163+
number_sections: bool
164+
tree_replacements: Mapping[str, str]
164165

165-
def apply_replacements(self, s):
166+
def apply_replacements(self, s: str):
166167
for key, val in self.tree_replacements.items():
167168
s = s.replace(key, val)
168169

169170
return s
170171

171172

172-
def render(settings, outf, node, indent=0, skip=1):
173+
def render(
174+
settings: RenderSettings,
175+
outf: str,
176+
node: Node,
177+
indent=0,
178+
skip=1):
173179
attrs = {}
174180

175181
icon = settings.default_icon
@@ -249,7 +255,10 @@ def get_section_id_and_display_name(trunk, include_extension):
249255
return section_id, display_name
250256

251257

252-
def blacklisted_glob(basedir, pattern, blacklist_regexps):
258+
def blacklisted_glob(
259+
basedir: str,
260+
pattern: str,
261+
blacklist_regexps: Sequence[re.Pattern[str]]):
253262
return sorted(
254263
name
255264
for name in glob(join(basedir, pattern))
@@ -348,7 +357,7 @@ def main():
348357
link_html = link_ipynb.replace(".ipynb", ".html")
349358
main_link = link_html
350359

351-
sub_nodes = [{
360+
sub_nodes: list[Node] = [{
352361
"text": "View on the web",
353362
"link": link_html,
354363
"icon": "bi bi-newspaper",
@@ -392,7 +401,7 @@ def main():
392401
"icon": "bi bi-download",
393402
})
394403

395-
demo_node = {
404+
demo_node: Node = {
396405
"text": "Demo: " + display_name,
397406
"link": main_link,
398407
"icon": "bi bi-keyboard",

0 commit comments

Comments
 (0)