diff --git a/runparams.py b/runparams.py index 6b9951c..fd17feb 100644 --- a/runparams.py +++ b/runparams.py @@ -92,9 +92,9 @@ def check_input_path(p): desc_list = ["JSON dump", "MkDocs", "PlantUML", "RDF", "TeX", "Web pages"] if opts.verbose: - self.log.basicConfig(level=logging.INFO) + logging.basicConfig(level=logging.INFO) if opts.debug: - self.log.basicConfig(level=logging.DEBUG) + logging.basicConfig(level=logging.DEBUG) self.input_path = Path(opts.input_dir) check_input_path(self.input_path) diff --git a/spec_parser/mkdocs.py b/spec_parser/mkdocs.py index c7c2516..1a6174d 100644 --- a/spec_parser/mkdocs.py +++ b/spec_parser/mkdocs.py @@ -16,8 +16,12 @@ def gen_mkdocs(model, outpath, cfg): jinja.globals["class_link"] = class_link jinja.globals["property_link"] = property_link jinja.globals["ext_property_link"] = ext_property_link - jinja.globals["type_link"] = lambda x, showshort=False: type_link(x, model, showshort=showshort) + jinja.globals["type_link"] = lambda x, showshort=False: type_link( + x, model, showshort=showshort + ) jinja.globals["not_none"] = lambda x: str(x) if x is not None else "" + jinja.globals["get_subclass_tree"] = lambda x: get_subclass_tree(x, model) + jinja.globals["get_class_url"] = get_class_url p = outpath @@ -37,8 +41,23 @@ def _generate_in_dir(dirname, group, tmplfname): d.mkdir(exist_ok=True) f = d / f"{s.name}.md" + context = vars(s).copy() + + # For classes, compute direct and nested subclasses + if dirname == "Classes" and hasattr(s, "subclasses"): + # Calculate direct subclasses (they are already stored in s.subclasses) + + # Create a map of class to its direct subclasses (as Class objects, not just names) + direct_subclasses = [] + for subclass_name in s.subclasses: + subclass = model.classes.get(subclass_name) + if subclass: + direct_subclasses.append(subclass) + + context["direct_subclasses"] = direct_subclasses + template = jinja.get_template(tmplfname) - page = template.render(vars(s)) + page = template.render(context) f.write_text(page) _generate_in_dir("Classes", model.classes, "class.md.j2") @@ -52,7 +71,10 @@ def _gen_filelist(nsname, itemslist, heading): nameslist = [c.name for c in itemslist.values()] if nameslist: ret.append(f" - {heading}:") - ret.extend(f" - '{n}': model/{nsname}/{heading}/{n}.md" for n in sorted(nameslist)) + ret.extend( + f" - '{n}': model/{nsname}/{heading}/{n}.md" + for n in sorted(nameslist) + ) return ret files = dict() @@ -136,3 +158,42 @@ def type_link(name, model, *, showshort=False): return f"[{name}](../{dirname}/{name}.md)" else: return f"{name}" + + +def get_subclass_tree(class_name, model): + """Build a nested structure representing the subclass tree for a given class. + + Returns a list of dictionaries, each with 'name' and 'children' keys. + """ + result = [] + cls = model.classes.get(class_name) + + if not cls or not hasattr(cls, "subclasses") or not cls.subclasses: + return result + + for subclass_name in cls.subclasses: + subclass_info = { + "name": subclass_name, + "children": get_subclass_tree(subclass_name, model), + } + result.append(subclass_info) + + return result + + +def get_class_url(class_name): + """Generate a URL for a class based on its fully qualified name. + + Args: + class_name: Fully qualified class name like "/Namespace/ClassName" + + Returns: + URL string that works in MkDocs + """ + parts = class_name.split("/") + if len(parts) >= 3: + namespace = parts[1] + class_name = parts[2] + # Format for MkDocs + return f"../../{namespace}/Classes/{class_name}" + return "#" diff --git a/spec_parser/model.py b/spec_parser/model.py index 43436e4..0003fe3 100644 --- a/spec_parser/model.py +++ b/spec_parser/model.py @@ -130,6 +130,20 @@ def _tsort_recursive(inh, cn, visited, stack): c.inheritance_stack.append(pcn) pcn = self.classes[pcn].fqsupercname + # build subclass trees + # Initialize subclasses dict for each class + for c in self.classes.values(): + c.subclasses = [] + + # Populate subclasses + for c in self.classes.values(): + if c.fqsupercname: + self.classes[c.fqsupercname].subclasses.append(c.fqname) + + # Sort subclasses by name for consistent display + for c in self.classes.values(): + c.subclasses.sort() + # add inherited properties to classes for cn in stack: c = self.classes[cn] diff --git a/spec_parser/templates/mkdocs/class.md.j2 b/spec_parser/templates/mkdocs/class.md.j2 index f47c063..c8274a9 100644 --- a/spec_parser/templates/mkdocs/class.md.j2 +++ b/spec_parser/templates/mkdocs/class.md.j2 @@ -22,6 +22,159 @@ {% endif %} {% endfor %} +{% if subclasses %} +## Subclass tree + +{% set current_ns = fqname.split('/')[1] %} +{% set current_name = fqname.split('/')[2] %} + +