Workflow yaml to mermaid converter - transitions are nodes
The snippet can be accessed without any authentication.
Authored by
Travis Bradbury
workflow-yaml-to-mermaid.php 3.06 KiB
<?php
namespace scripts;
use Symfony\Component\Yaml\Yaml;
require_once 'vendor/autoload.php';
$workflowFile = $argv[1];
echo "flowchart TB" . PHP_EOL;
foreach (WorkflowPrinter::loadFromFile($workflowFile) as $workflow) {
$workflow->print("\t");
}
final class WorkflowPrinter {
private string $id;
/**
* @var \scripts\State[]
*/
private array $states;
/**
* @var \scripts\Transition[]
*/
private array $transitions;
/**
* @var callable
*/
private $escaper;
public function __construct($id, $workflow) {
$this->id = $id;
$this->states = array_map(fn($id, $definition) => State::fromDefinition($id, $definition), array_keys($workflow['states']), $workflow['states']);
$this->transitions = array_map(fn($id, $definition) => Transition::fromDefinition($id, $definition), array_keys($workflow['transitions']), $workflow['transitions']);
$this->escaper = fn ($x) => "\"{$x}\"";
}
/**
* @return \scripts\WorkflowPrinter[]
*/
public static function loadFromFile(string $path): array {
$workflows = Yaml::parse(file_get_contents($path));
return array_map(fn ($id, $workflow) => new static($id, $workflow), array_keys($workflows), $workflows);
}
/**
* Writes a mermaid graph of the workflow.
*
* See https://mermaid.ink/
*/
public function print($prefix) {
echo $prefix . "subgraph {$this->id}" . PHP_EOL;
foreach ($this->states as $state) {
echo $prefix . "\t" . $state->format($this->escaper) . PHP_EOL;
}
foreach ($this->transitions as $transition) {
echo $prefix . "\t" . $transition->format($this->escaper) . PHP_EOL;
foreach ($transition->froms($this->escaper) as $from) {
echo $prefix . "\t" . $from . PHP_EOL;
}
echo $prefix . "\t" . $transition->to($this->escaper) . PHP_EOL;
}
echo $prefix . "end" . PHP_EOL;
}
}
final class State {
public string $id;
public string $label;
public function __construct($id, $label) {
$this->id = $id;
$this->label = $label;
}
public static function fromDefinition($id, $definition): self {
return new static($id, $definition['label']);
}
public function format(callable $escaper): string {
return "s_{$this->id}[{$escaper($this->label)}]";
}
}
final class Transition {
public string $id;
public string $label;
/**
* @var string[]
*/
public array $from;
public string $to;
public function __construct($id, $label, $from, $to) {
$this->id = $id;
$this->label = $label;
$this->from = $from;
$this->to = $to;
}
public static function fromDefinition($id, $definition): self {
return new static($id, $definition['label'], $definition['from'], $definition['to']);
}
public function format(callable $escaper): string {
return "t_{$this->id}{{$escaper($this->label)}}";
}
/**
* @return string[]
*/
public function froms(callable $escaper): array {
return array_map(fn ($from) => "s_{$from} --> t_{$this->id}", $this->from);
}
public function to(callable $escaper): string {
return "t_{$this->id} --> s_{$this->to}";
}
}
Please register or sign in to comment