Skip to content

Commit

Permalink
visualiser: Allow spacing in node names (#38)
Browse files Browse the repository at this point in the history
* visualiser: Allow spacing in node names

* visualiser: Allow spacing in node names

* visualiser: Allow spacing in node names
  • Loading branch information
andrewwormald authored Sep 24, 2024
1 parent efe6adb commit f7b8b22
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 18 deletions.
17 changes: 17 additions & 0 deletions internal/graph/graph.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package graph

import "slices"

func New() *Graph {
return &Graph{
graph: make(map[int][]int),
Expand Down Expand Up @@ -75,6 +77,21 @@ type Info struct {
Transitions []Transition
}

func (g *Graph) Nodes() []int {
var nodes []int
for node, ok := range g.validNodes {
if !ok {
continue
}

nodes = append(nodes, node)
}

slices.Sort(nodes)

return nodes
}

func (g *Graph) Info() Info {
var i Info
for _, node := range g.nodeOrder {
Expand Down
4 changes: 4 additions & 0 deletions internal/graph/graph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,8 @@ func TestGraph(t *testing.T) {
},
}
require.Equal(t, expected, actual)

actualNodes := g.Nodes()
expectedNodes := []int{1, 2, 3, 4, 5}
require.Equal(t, expectedNodes, actualNodes)
}
15 changes: 15 additions & 0 deletions internal/util/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package util

import "unicode"

func CamelCaseToSpacing(s string) string {
var result []rune
for i, r := range s {
if unicode.IsUpper(r) && i > 0 {
result = append(result, ' ')
}

result = append(result, r)
}
return string(result)
}
31 changes: 31 additions & 0 deletions internal/util/util_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package util_test

import (
"fmt"
"testing"

"github.com/stretchr/testify/require"

"github.com/luno/workflow/internal/util"
)

func TestCamelCaseToSpacing(t *testing.T) {
tests := []struct {
input string
expected string
}{
{"camelCase", "camel Case"},
{"thisIsATest", "this Is A Test"},
{"helloWorld", "hello World"},
{"singleWord", "single Word"},
{"Lowercase", "Lowercase"}, // No change if no camel case
{"", ""}, // Empty string case
}

for i, test := range tests {
t.Run(fmt.Sprintf("case %v: %v", i+1, test.input), func(t *testing.T) {
result := util.CamelCaseToSpacing(test.input)
require.Equal(t, test.expected, result)
})
}
}
11 changes: 8 additions & 3 deletions testdata/graph-visualisation.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ title: Diagram of example Workflow
stateDiagram-v2
direction LR
start-->middle
start-->end
middle-->end
9: Start
10: Middle
11: End
9-->10
9-->11
10-->11
```
39 changes: 24 additions & 15 deletions visualiser.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"os"
"strings"
"text/template"

"github.com/luno/workflow/internal/util"
)

// CreateDiagram creates a diagram in a md file for communicating a workflow's set of steps in an easy-to-understand
Expand Down Expand Up @@ -39,21 +41,21 @@ func mermaidDiagram[Type any, Status StatusType](a API[Type, Status], path strin

graphInfo := w.statusGraph.Info()

var starting []string
var starting []int
for _, node := range graphInfo.StartingNodes {
starting = append(starting, statusToString(Status(node)))
starting = append(starting, node)
}

var terminal []string
var terminal []int
for _, node := range graphInfo.TerminalNodes {
terminal = append(terminal, statusToString(Status(node)))
terminal = append(terminal, node)
}

var transitions []MermaidTransition
for _, transition := range graphInfo.Transitions {
transitions = append(transitions, MermaidTransition{
From: statusToString(Status(transition.From)),
To: statusToString(Status(transition.To)),
From: transition.From,
To: transition.To,
})
}

Expand All @@ -63,22 +65,25 @@ func mermaidDiagram[Type any, Status StatusType](a API[Type, Status], path strin
StartingPoints: starting,
TerminalPoints: terminal,
Transitions: transitions,
Nodes: w.statusGraph.Nodes(),
}

return template.Must(template.New("").Parse("```"+mermaidTemplate+"```")).Execute(file, mf)
return template.Must(template.New("").Funcs(map[string]any{
"Description": description[Status],
}).Parse("```"+mermaidTemplate+"```")).Execute(file, mf)
}

func statusToString[Status StatusType](s Status) string {
str := strings.ToLower(s.String())
str = strings.Replace(str, " ", "_", -1)
return str
func description[Status StatusType](val int) string {
s := Status(val).String()
return util.CamelCaseToSpacing(s)
}

type MermaidFormat struct {
WorkflowName string
Direction MermaidDirection
StartingPoints []string
TerminalPoints []string
Nodes []int
StartingPoints []int
TerminalPoints []int
Transitions []MermaidTransition
}

Expand All @@ -93,8 +98,8 @@ const (
)

type MermaidTransition struct {
From string
To string
From int
To int
}

var mermaidTemplate = `mermaid
Expand All @@ -103,6 +108,10 @@ title: Diagram of {{.WorkflowName}} Workflow
---
stateDiagram-v2
direction {{.Direction}}
{{range $key, $value := .Nodes }}
{{$value}}: {{Description $value}}
{{- end }}
{{range $key, $value := .Transitions }}
{{$value.From}}-->{{$value.To}}
{{- end }}
Expand Down

0 comments on commit f7b8b22

Please sign in to comment.