diff --git a/README.md b/README.md index 6db4af4..b1480e8 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![Latest Version](https://img.shields.io/pypi/v/adr-viewer)](https://pypi.org/project/adr-viewer/) Show off your Architecture Decision Records with an easy-to-navigate web page, either as a local web-server or generated static content. +Include diagrams in [Mermaid](https://mermaid.js.org) format using code blocks/fences, e.g. [test ADR 5](test/adr/0005-has-mermaid.md). ## Examples diff --git a/adr_viewer/__init__.py b/adr_viewer/__init__.py index b160455..69edf66 100644 --- a/adr_viewer/__init__.py +++ b/adr_viewer/__init__.py @@ -21,6 +21,7 @@ def generate_content(path, template_dir_override=None, title=None) -> str: config = { "project_title": title if title else os.path.basename(os.getcwd()), "records": [], + "include_mermaid": False, } for index, adr_file in enumerate(files): @@ -29,6 +30,8 @@ def generate_content(path, template_dir_override=None, title=None) -> str: if adr_attributes: adr_attributes.index = index + if not config["include_mermaid"]: + config["include_mermaid"] = adr_attributes.includes_mermaid config["records"].append(adr_attributes) else: diff --git a/adr_viewer/parse.py b/adr_viewer/parse.py index 7f072b4..1686db7 100644 --- a/adr_viewer/parse.py +++ b/adr_viewer/parse.py @@ -11,6 +11,7 @@ class Adr: status: str body: str index: int = 0 + includes_mermaid: bool = False def extract_statuses_from_adr(page_object) -> Iterator[str]: @@ -52,7 +53,14 @@ def parse_adr(content: str) -> Optional[Adr]: header = soup.find("h1") + includes_mermaid = soup.find(name="code", attrs={"class": "language-mermaid"}) + if header: - return Adr(header.text, status, adr_as_html) + return Adr( + title=header.text, + status=status, + body=adr_as_html, + includes_mermaid=includes_mermaid, + ) else: return None diff --git a/adr_viewer/templates/index.html b/adr_viewer/templates/index.html index 6ee5e72..01490dc 100644 --- a/adr_viewer/templates/index.html +++ b/adr_viewer/templates/index.html @@ -6,6 +6,9 @@ + {% if config.include_mermaid %} + + {% endif %} ADR Viewer - {{ config.project_title }} @@ -94,7 +97,34 @@

{% endfor %} + {% if config.include_mermaid %} + + {% endif %} diff --git a/adr_viewer/test_parse.py b/adr_viewer/test_parse.py index c1e64b3..88880ef 100644 --- a/adr_viewer/test_parse.py +++ b/adr_viewer/test_parse.py @@ -62,3 +62,17 @@ def test_should_ignore_invalid_files(): adr = parse_adr(markdown) assert adr is None + + +def test_should_detect_mermaid(): + markdown = open("test/adr/0005-has-mermaid.md").read() + adr = parse_adr(markdown) + + assert adr.includes_mermaid + + +def test_should_not_detect_mermaid(): + markdown = open("test/adr/0004-proposed-status.md").read() + adr = parse_adr(markdown) + + assert not adr.includes_mermaid diff --git a/adr_viewer/test_render.py b/adr_viewer/test_render.py index 3b8071c..fdf2ad6 100644 --- a/adr_viewer/test_render.py +++ b/adr_viewer/test_render.py @@ -30,3 +30,15 @@ def test_should_render_html_with_collapsible_index(): html = render_html({"records": [adr]}) assert 'Record 123' in html + + +def test_should_render_html_with_mermaid(): + html = render_html({"include_mermaid": True}) + + assert "mermaid.min.js" in html + + +def test_should_render_html_without_mermaid(): + html = render_html({"include_mermaid": False}) + + assert "mermaid.min.js" not in html diff --git a/test/adr/0005-has-mermaid.md b/test/adr/0005-has-mermaid.md new file mode 100644 index 0000000..fe72913 --- /dev/null +++ b/test/adr/0005-has-mermaid.md @@ -0,0 +1,82 @@ +# 2. Use mermaid for diagrams + +Date: 2023-09-02 + +## Status + +Accepted + +## Context + +We need to be able to diagram things. + +## Decision + +We will use [Mermaid](https://mermaid.js.org). + +```mermaid +journey + title Using Mermaid in adr-viewer + section Writing ADR + Learn ADR: 5: Me + Write ADR: 3: Me + Render ADR: 6: Me +``` + +```mermaid +flowchart TD + A[Christmas] -->|Get money| B(Go shopping) + B --> C{Let me think} + C -->|One| D[Laptop] + C -->|Two| E[iPhone] + C -->|Three| F[Car] +``` + +```mermaid +sequenceDiagram + Alice->>+John: Hello John, how are you? + Alice->>+John: John, can you hear me? + John-->>-Alice: Hi Alice, I can hear you! + John-->>-Alice: I feel great! +``` + +```mermaid +classDiagram + Animal <|-- Duck + Animal <|-- Fish + Animal <|-- Zebra + Animal : +int age + Animal : +String gender + Animal: +isMammal() + Animal: +mate() + class Duck{ + +String beakColor + +swim() + +quack() + } + class Fish{ + -int sizeInFeet + -canEat() + } + class Zebra{ + +bool is_wild + +run() + } +``` + + +## Consequences + +We need to add a Mermaid script in the `head` tag of the template, potentially only when there is a Mermaid block in a Markdown document. + +```mermaid +gantt + title A Gantt Diagram + dateFormat YYYY-MM-DD + section Section + A task :a1, 2014-01-01, 30d + Another task :after a1 , 20d + section Another + Task in sec :2014-01-12 , 12d + another task : 24d +``` \ No newline at end of file