Source code for sphinx_needs_tree_map

"""
sphinx-needs-tree-map: StrictDoc-style tree map visualizations for sphinx-needs.

This extension provides the `needtreemap` directive to create interactive
Plotly.js treemap visualizations of sphinx-needs documentation.
"""

from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING, Any

import docutils.nodes

from sphinx_needs_tree_map.directives.needtreemap import (
    NeedTreeMapDirective,
    NeedTreeMapNode,
    process_needtreemap_nodes,
)

if TYPE_CHECKING:
    from sphinx.application import Sphinx
    from sphinx.config import Config

__version__ = "0.1.0"
__all__ = ["__version__", "setup"]

# Path to static files
STATIC_DIR = Path(__file__).parent / "static"
TEMPLATES_DIR = Path(__file__).parent / "templates"


def builder_inited(app: Sphinx) -> None:
    """Called when builder is initialized.

    Adds static files directory to Sphinx's static paths.
    """
    # Add our static directory
    if hasattr(app.config, "html_static_path"):
        app.config.html_static_path.append(str(STATIC_DIR))


def config_inited(app: Sphinx, config: Config) -> None:
    """Called when config is initialized.

    Sets up default configuration values.
    """
    # Ensure sphinx-needs is loaded first
    if "sphinx_needs" not in config.extensions:
        app.setup_extension("sphinx_needs")


[docs] def setup(app: Sphinx) -> dict[str, Any]: """Set up the sphinx-needs-tree-map extension. Args: app: The Sphinx application instance. Returns: Extension metadata dictionary. """ # Configuration values app.add_config_value( "needtreemap_plotly_cdn", "https://cdn.plot.ly/plotly-2.35.2.min.js", "html", ) app.add_config_value( "needtreemap_default_height", "600px", "html", ) app.add_config_value( "needtreemap_default_width", "100%", "html", ) app.add_config_value( "needtreemap_colors", { "req": "#E3F2FD", "spec": "#FFF3E0", "impl": "#E8F5E9", "test": "#FCE4EC", "story": "#F3E5F5", "default": "#ECEFF1", }, "html", ) app.add_config_value( "needtreemap_status_colors", { "open": "#FFCDD2", "in progress": "#FFF9C4", "implemented": "#C8E6C9", "verified": "#B2DFDB", "default": "#ECEFF1", }, "html", ) # Register the directive app.add_directive("needtreemap", NeedTreeMapDirective) # Register the custom docutils node app.add_node( NeedTreeMapNode, html=(visit_needtreemap_node, depart_needtreemap_node), latex=(skip_needtreemap_node, None), text=(skip_needtreemap_node, None), ) # Connect event handlers app.connect("config-inited", config_inited) app.connect("builder-inited", builder_inited) app.connect("doctree-resolved", process_needtreemap_nodes) # Add CSS file app.add_css_file("needtreemap.css") return { "version": __version__, "parallel_read_safe": True, "parallel_write_safe": True, }
def visit_needtreemap_node(self: Any, node: NeedTreeMapNode) -> None: """HTML visitor for NeedTreeMapNode - renders the treemap HTML.""" self.body.append(node.get("html_content", "")) def depart_needtreemap_node(self: Any, node: NeedTreeMapNode) -> None: """HTML departure handler for NeedTreeMapNode.""" pass def skip_needtreemap_node(_self: Any, _node: NeedTreeMapNode) -> None: """Skip rendering for non-HTML builders.""" raise docutils.nodes.SkipNode