• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JBZoo / Mermaid-PHP / 30072388792

23 Jul 2026 07:33PM UTC coverage: 91.755% (+1.4%) from 90.404%
30072388792

push

github

web-flow
feat: add Sequence Diagram support (#10) (#33)

## Summary

Adds first-class Mermaid `sequenceDiagram` support to the library,
following the same fluent, object-oriented style as the existing
`Graph`/`Timeline` families. Requested in #10.

A sequence diagram is modeled as an **ordered stream of statements with
nesting** (not two flat sets like `Graph`). A tiny `Statement` interface
(`render(int $shift): string`, extends `\Stringable`) is implemented by
every body element; participants/boxes form a header region; the
`SequenceDiagram` container renders header + ordered body and plugs into
the existing `Render`/`Helper` machinery.

## What's covered (full `sequenceDiagram` syntax)

- **Participants / actors** — aliases, `safeMode` (md5 ids, like
`Node`), repeatable per-participant `link()`
- **Messages** — all 10 arrow types, inline activation (`+`/`-`,
mutually exclusive) and explicit `activate`/`deactivate`
- **Notes** — `left of` / `right of` / `over` (one or two participants)
- **Lifecycle** — `create` / `destroy`; **comments** (`%%`)
- **Boxes** — participant grouping with optional color
- **Control blocks** — `loop`, `opt`, `break`, `rect` (single-section)
and `alt`/`else`, `par`/`and`, `critical`/`option` (multi-section),
arbitrarily nestable
- **Container** — title frontmatter, `autonumber`, `getParticipant()`,
`addMessageByIds()` (throws on unknown id), `renderHtml()`,
`getLiveEditorUrl()`

## Notes

- The `break` block class is named **`BreakBlock`** — `break` is a
reserved word in PHP, so `class Break` is a parse error. It still emits
the Mermaid `break` keyword.
- `Render::html()` / `Helper::getLiveEditorUrl()` union types widened to
accept `SequenceDiagram`.
- README updated with the new diagram type and a runnable example.

## Testing

- `tests/SequenceDiagramTest.php`: 23 tests, 58 assertions — every arrow
type, activation, notes, lifecycle, comments, boxes/links, all blocks +
nesting, container ordering, `addMessageByIds` errors, and an ... (continued)

153 of 158 new or added lines in 16 files covered. (96.84%)

690 of 752 relevant lines covered (91.76%)

79.63 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.44
/src/SequenceDiagram/Block/Block.php
1
<?php
2

3
/**
4
 * JBZoo Toolbox - Mermaid-PHP.
5
 *
6
 * This file is part of the JBZoo Toolbox project.
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @license    MIT
11
 * @copyright  Copyright (C) JBZoo.com, All rights reserved.
12
 * @see        https://github.com/JBZoo/Mermaid-PHP
13
 */
14

15
declare(strict_types=1);
16

17
namespace JBZoo\MermaidPHP\SequenceDiagram\Block;
18

19
use JBZoo\MermaidPHP\SequenceDiagram\Statement;
20

21
abstract class Block implements Statement
22
{
23
    protected string $keyword;
24

25
    /** @var array<int, array{divider: ?string, label: ?string, statements: Statement[]}> */
26
    protected array $sections;
27

28
    public function __construct(string $keyword, ?string $label = null)
29
    {
30
        $this->keyword  = $keyword;
30✔
31
        $this->sections = [['divider' => null, 'label' => $label, 'statements' => []]];
30✔
32
    }
33

34
    public function __toString(): string
35
    {
NEW
36
        return $this->render();
×
37
    }
38

39
    public function add(Statement $statement): static
40
    {
41
        $lastIndex                                  = \count($this->sections) - 1;
30✔
42
        $this->sections[$lastIndex]['statements'][] = $statement;
30✔
43

44
        return $this;
30✔
45
    }
46

47
    public function render(int $shift = 0): string
48
    {
49
        $spaces = \str_repeat(' ', $shift);
30✔
50
        $lines  = [];
30✔
51

52
        foreach ($this->sections as $index => $section) {
30✔
53
            $keyword = $index === 0 ? $this->keyword : (string)$section['divider'];
30✔
54
            $label   = $section['label'];
30✔
55
            $lines[] = $spaces . ($label !== null && $label !== '' ? "{$keyword} {$label}" : $keyword);
30✔
56

57
            foreach ($section['statements'] as $statement) {
30✔
58
                $lines[] = $statement->render($shift + 4);
30✔
59
            }
60
        }
61

62
        $lines[] = $spaces . 'end';
30✔
63

64
        return \implode(\PHP_EOL, $lines);
30✔
65
    }
66

67
    protected function addSection(string $divider, ?string $label): static
68
    {
69
        $this->sections[] = ['divider' => $divider, 'label' => $label, 'statements' => []];
18✔
70

71
        return $this;
18✔
72
    }
73
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc