From db11277e9e2bcd72aac48f1c60aecb6b9c6ce001 Mon Sep 17 00:00:00 2001 From: Ashwin Sajiv <37055705+ashwinsajiv@users.noreply.github.com> Date: Fri, 3 Jul 2020 14:52:33 +1000 Subject: [PATCH] Refactor mermaid (#923) * Rename subgraph to numbers and escape the actual name * Add escape string and clean up printing of mermaid * Added epa diagram for a set of applications --- .../endpointanalysisdiagram.go | 41 ++++++++++++++++--- .../endpointanalysisdiagram_test.go | 13 ++++++ .../integrationdiagram/integrationdiagram.go | 8 +++- .../sequencediagram/sequencediagram.go | 19 ++++++--- 4 files changed, 70 insertions(+), 11 deletions(-) diff --git a/pkg/mermaid/endpointanalysisdiagram/endpointanalysisdiagram.go b/pkg/mermaid/endpointanalysisdiagram/endpointanalysisdiagram.go index 3975e8c78..2250cb919 100644 --- a/pkg/mermaid/endpointanalysisdiagram/endpointanalysisdiagram.go +++ b/pkg/mermaid/endpointanalysisdiagram/endpointanalysisdiagram.go @@ -18,6 +18,12 @@ func GenerateEndpointAnalysisDiagram(m *sysl.Module) (string, error) { return generateEndpointAnalysisDiagramHelper(m, &[]externalLink{}, true) } +//Similar to the above, but accepts a slice of application names +//and returns a diagram only including applications specified +func GenerateMultipleAppEndpointAnalysisDiagram(m *sysl.Module, appNames []string) (string, error) { + return generateMultipleAppEndpointAnalysisDiagramHelper(m, appNames, &[]externalLink{}, true) +} + //generateEndpointAnalysisDiagram is a helper which has additional arguments which need not be entered by the user func generateEndpointAnalysisDiagramHelper(m *sysl.Module, externalLinks *[]externalLink, theStart bool) (string, error) { @@ -25,16 +31,41 @@ func generateEndpointAnalysisDiagramHelper(m *sysl.Module, if theStart { result = mermaid.GeneratedHeader + "graph TD\n" } + count := 1 for appName, app := range m.Apps { - result += fmt.Sprintf(" subgraph %s\n", appName) + result += fmt.Sprintf(" subgraph %d[\"%s\"]\n", count, appName) for epName, endPoint := range app.Endpoints { statements := endPoint.Stmt result += printEndpointAnalysisStatements(m, statements, mermaid.CleanString(epName), externalLinks) } result += " end\n" + count++ + } + for _, eLink := range *externalLinks { + result += fmt.Sprintf(" %s --> %s\n", eLink.statement, eLink.endPoint) + } + return result, nil +} + +func generateMultipleAppEndpointAnalysisDiagramHelper(m *sysl.Module, appNames []string, + externalLinks *[]externalLink, theStart bool) (string, error) { + var result string + if theStart { + result = mermaid.GeneratedHeader + "graph TD\n" + } + count := 1 + for _, appName := range appNames { + result += fmt.Sprintf(" subgraph %d[\"%s\"]\n", count, appName) + endPoints := m.Apps[appName].Endpoints + for epName, endPoint := range endPoints { + statements := endPoint.Stmt + result += printEndpointAnalysisStatements(m, statements, mermaid.CleanString(epName), externalLinks) + } + result += " end\n" + count++ } for _, eLink := range *externalLinks { - result += fmt.Sprintf(" %s-->%s\n", eLink.statement, eLink.endPoint) + result += fmt.Sprintf(" %s --> %s\n", eLink.statement, eLink.endPoint) } return result, nil } @@ -47,7 +78,7 @@ func printEndpointAnalysisStatements(m *sysl.Module, statements []*sysl.Statemen switch c := statement.Stmt.(type) { case *sysl.Statement_Call: appEndPoint := fmt.Sprintf("%s-%s", mermaid.CleanString(c.Call.Target.Part[0]), mermaid.CleanString(c.Call.Endpoint)) - result += fmt.Sprintf(" %s-->%s\n", endPoint, appEndPoint) + result += fmt.Sprintf(" %s --> %s\n", endPoint, appEndPoint) pair := externalLink{appEndPoint, mermaid.CleanString(c.Call.Endpoint)} if !externalLinksContain(*externalLinks, pair) { *externalLinks = append(*externalLinks, pair) @@ -63,9 +94,9 @@ func printEndpointAnalysisStatements(m *sysl.Module, statements []*sysl.Statemen case *sysl.Statement_Foreach: result += printEndpointAnalysisStatements(m, c.Foreach.Stmt, endPoint, externalLinks) case *sysl.Statement_Action: - result += fmt.Sprintf(" %s-->%s\n", endPoint, mermaid.CleanString(c.Action.Action)) + result += fmt.Sprintf(" %s --> %s\n", endPoint, mermaid.CleanString(c.Action.Action)) case *sysl.Statement_Ret: - result += fmt.Sprintf(" %s-->%s\n", endPoint, mermaid.CleanString(c.Ret.Payload)) + result += fmt.Sprintf(" %s --> %s\n", endPoint, mermaid.CleanString(c.Ret.Payload)) default: result += "" } diff --git a/pkg/mermaid/endpointanalysisdiagram/endpointanalysisdiagram_test.go b/pkg/mermaid/endpointanalysisdiagram/endpointanalysisdiagram_test.go index bf6ca1003..c82efe394 100644 --- a/pkg/mermaid/endpointanalysisdiagram/endpointanalysisdiagram_test.go +++ b/pkg/mermaid/endpointanalysisdiagram/endpointanalysisdiagram_test.go @@ -57,3 +57,16 @@ func TestGenerateMermaidIntegrationDiagram3(t *testing.T) { assert.NotNil(t, r) assert.NoError(t, err) } + +func TestGenerateMermaidIntegrationDiagram4(t *testing.T) { + m, err := parse.NewParser().Parse("demo/simple/best-ever-sysl-example.sysl", + syslutil.NewChrootFs(afero.NewOsFs(), mermaid.ProjectDir)) + if err != nil { + t.Error(err) + } + apps := []string{"TheWorld", "DragonEater"} + r, err := GenerateMultipleAppEndpointAnalysisDiagram(m, apps) + assert.NotNil(t, m) + assert.NotNil(t, r) + assert.NoError(t, err) +} diff --git a/pkg/mermaid/integrationdiagram/integrationdiagram.go b/pkg/mermaid/integrationdiagram/integrationdiagram.go index 4a27f9f4b..506d7e0a4 100644 --- a/pkg/mermaid/integrationdiagram/integrationdiagram.go +++ b/pkg/mermaid/integrationdiagram/integrationdiagram.go @@ -3,6 +3,7 @@ package integrationdiagram import ( "errors" "fmt" + "strings" "github.com/anz-bank/sysl/pkg/mermaid" "github.com/anz-bank/sysl/pkg/sysl" @@ -88,7 +89,8 @@ func printIntegrationDiagramStatements(m *sysl.Module, statements []*sysl.Statem pair := integrationPair{appName, nextApp} if !integrationPairsContain(*integrationPairs, pair) { *integrationPairs = append(*integrationPairs, pair) - result += fmt.Sprintf(" %s --> %s\n", appName, nextApp) + result += fmt.Sprintf(" %s[\"%s\"] --> %s[\"%s\"]\n", + cleanAppName(appName), appName, cleanAppName(nextApp), nextApp) out, err := generateIntegrationDiagramHelper(m, nextApp, integrationPairs, false) if err != nil { panic("Error in generating integration diagram; check if app name is correct") @@ -133,3 +135,7 @@ func integrationPairsContain(i []integrationPair, ip integrationPair) bool { } return false } + +func cleanAppName(s string) string { + return strings.ReplaceAll(s, " ", "_") +} diff --git a/pkg/mermaid/sequencediagram/sequencediagram.go b/pkg/mermaid/sequencediagram/sequencediagram.go index fec00dcb0..0a2edf48c 100644 --- a/pkg/mermaid/sequencediagram/sequencediagram.go +++ b/pkg/mermaid/sequencediagram/sequencediagram.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "regexp" + "strings" "github.com/anz-bank/sysl/pkg/mermaid" "github.com/anz-bank/sysl/pkg/sysl" @@ -35,7 +36,7 @@ func generateSequenceDiagramHelper(m *sysl.Module, appName string, epName string if err := isValidAppNameAndEndpoint(m, appName, epName); err != nil { return "", err } - result += fmt.Sprintf(" %s->>%s: %s\n", previousApp, appName, epName) + result += fmt.Sprintf(" %s ->> %s: %s\n", previousApp, cleanAppName(appName), epName) } statements := m.Apps[appName].Endpoints[epName].GetStmt() result += printSequenceDiagramStatements(m, statements, appName, previousApp, indent, sequencePairs, theStart) @@ -125,20 +126,24 @@ func isValidAppNameAndEndpoint(m *sysl.Module, appName string, epName string) er //callStatement is a printer to print a call statement func callStatement(appName string, epName string, nextApp string, indent int) string { - return fmt.Sprintf("%s%s->>+%s: %s\n", addIndent(indent), appName, nextApp, epName) + return fmt.Sprintf("%s%s ->>+ %s: %s\n", addIndent(indent), + cleanAppName(appName), cleanAppName(nextApp), epName) } //retStatement is a printer to print a return statement func retStatement(appName string, epName string, previousApp string, indent int, theStart bool) string { if theStart { - return fmt.Sprintf("%s%s-->>%s: %s\n", addIndent(indent), appName, previousApp, epName) + return fmt.Sprintf("%s%s -->> %s: %s\n", addIndent(indent), + cleanAppName(appName), cleanAppName(previousApp), epName) } - return fmt.Sprintf("%s%s-->>-%s: %s\n", addIndent(indent), appName, previousApp, epName) + return fmt.Sprintf("%s%s -->>- %s: %s\n", addIndent(indent), + cleanAppName(appName), cleanAppName(previousApp), epName) } //actionStatement is a printer to print an action statement func actionStatement(appName string, action string, indent int) string { - return fmt.Sprintf("%s%s->>%s: %s\n", addIndent(indent), appName, appName, action) + return fmt.Sprintf("%s%s ->> %s: %s\n", addIndent(indent), + cleanAppName(appName), cleanAppName(appName), action) } //addIndent adds indents based on the input @@ -159,3 +164,7 @@ func sequencePairsContain(s []sequencePair, sp sequencePair) bool { } return false } + +func cleanAppName(s string) string { + return strings.ReplaceAll(s, "-", "_") +}