diff --git a/models/workflow/plantuml.go b/models/workflow/plantuml.go index 2903313..533f9c0 100644 --- a/models/workflow/plantuml.go +++ b/models/workflow/plantuml.go @@ -15,31 +15,32 @@ import ( // PlantUML export // --------------------------------------------------------------------------- -// plantUMLProcedures defines the !procedure blocks for each resource type. -// These make the output valid, renderable PlantUML while remaining parseable -// by ExtractFromPlantUML (which already skips lines containing "!procedure"). +// plantUMLProcedures defines !procedure blocks for each resource type. +// Parameters use the $var/$name convention of PlantUML preprocessor v2. +// Calls are written WITHOUT inline comments (comment on the following line) +// to avoid the "assumed sequence diagram" syntax error. const plantUMLProcedures = `!procedure Processing($var, $name) - component "$name" as $var <> +component "$name" as $var <> !endprocedure !procedure Data($var, $name) - file "$name" as $var <> +file "$name" as $var <> !endprocedure !procedure Storage($var, $name) - database "$name" as $var <> +database "$name" as $var <> !endprocedure !procedure ComputeUnit($var, $name) - node "$name" as $var <> +node "$name" as $var <> !endprocedure !procedure WorkflowEvent($var, $name) - usecase "$name" as $var <> +usecase "$name" as $var <> !endprocedure !procedure Workflow($var, $name) - frame "$name" as $var <> +frame "$name" as $var <> !endprocedure ` @@ -72,11 +73,10 @@ func (w *Workflow) ToPlantUML() string { if src == "" || dst == "" { continue } - line := fmt.Sprintf("%s --> %s", src, dst) + sb.WriteString(fmt.Sprintf("%s --> %s\n", src, dst)) if comment := plantUMLLinkComment(link); comment != "" { - line += " ' " + comment + sb.WriteString("' " + comment + "\n") } - sb.WriteString(line + "\n") } sb.WriteString("\n@enduml\n") @@ -146,11 +146,13 @@ func plantUMLItemLine(varName string, item graph.GraphItem) string { } func plantUMLResourceLine(macro, varName string, res resources.ResourceInterface) string { - line := fmt.Sprintf("%s(%s, \"%s\")", macro, varName, res.GetName()) + decl := fmt.Sprintf("%s(%s, \"%s\")", macro, varName, res.GetName()) if comment := plantUMLResourceComment(res); comment != "" { - line += " ' " + comment + // Comment on the line AFTER the declaration. ExtractFromPlantUML uses + // look-ahead to merge it back. No inline comment = no !procedure conflict. + return decl + "\n' " + comment } - return line + return decl } // plantUMLResourceComment merges resource-level fields with the first instance diff --git a/models/workflow/workflow.go b/models/workflow/workflow.go index 83c0254..b62a909 100644 --- a/models/workflow/workflow.go +++ b/models/workflow/workflow.go @@ -149,15 +149,46 @@ func (d *Workflow) ExtractFromPlantUML(plantUML multipart.File, request *tools.A }, } graphVarName := map[string]graph.GraphItem{} - scanner := bufio.NewScanner(plantUML) + // Collect all lines first to support look-ahead (comment on the line after + // the declaration, as produced by ToPlantUML). + scanner := bufio.NewScanner(plantUML) + var lines []string for scanner.Scan() { - line := scanner.Text() + lines = append(lines, scanner.Text()) + } + if err := scanner.Err(); err != nil { + return d, err + } + + for i, line := range lines { + trimmed := strings.TrimSpace(line) + + // Skip pure comment lines and PlantUML directives — they must never be + // parsed as resource declarations or links. Without this guard, a comment + // like "' source: http://my-server.com" would match the "-" link check. + if strings.HasPrefix(trimmed, "'") || + strings.HasPrefix(trimmed, "!") || + strings.HasPrefix(trimmed, "@") || + trimmed == "" { + continue + } + + // Build the parse line: if the current line has no inline comment and the + // next line is a pure comment, append it so parsers receive one combined line. + // Also handles the legacy inline-comment format unchanged. + parseLine := line + if !strings.Contains(line, "'") && i+1 < len(lines) { + if next := strings.TrimSpace(lines[i+1]); strings.HasPrefix(next, "'") { + parseLine = line + " " + next + } + } + for n, new := range resourceCatalog { - if strings.Contains(line, n+"(") && !strings.Contains(line, "!procedure") { // should exclude declaration of type. + if strings.Contains(line, n+"(") && !strings.Contains(line, "!procedure") && !strings.Contains(line, "!define") { // exclude macro declarations newRes := new() newRes.SetID(uuid.New().String()) - varName, graphItem, err := d.extractResourcePlantUML(line, newRes, n, request.PeerID) + varName, graphItem, err := d.extractResourcePlantUML(parseLine, newRes, n, request.PeerID) fmt.Println(varName, graphItem, err) if err != nil { return d, err @@ -167,25 +198,25 @@ func (d *Workflow) ExtractFromPlantUML(plantUML multipart.File, request *tools.A } continue } else if strings.Contains(line, "-->") { - err := d.extractLink(line, graphVarName, "-->", false) + err := d.extractLink(parseLine, graphVarName, "-->", false) if err != nil { fmt.Println(err) continue } } else if strings.Contains(line, "<--") { - err := d.extractLink(line, graphVarName, "<--", true) + err := d.extractLink(parseLine, graphVarName, "<--", true) if err != nil { fmt.Println(err) continue } } else if strings.Contains(line, "--") { - err := d.extractLink(line, graphVarName, "--", false) + err := d.extractLink(parseLine, graphVarName, "--", false) if err != nil { fmt.Println(err) continue } } else if strings.Contains(line, "-") { - err := d.extractLink(line, graphVarName, "-", false) + err := d.extractLink(parseLine, graphVarName, "-", false) if err != nil { fmt.Println(err) continue @@ -193,9 +224,6 @@ func (d *Workflow) ExtractFromPlantUML(plantUML multipart.File, request *tools.A } } } - if err := scanner.Err(); err != nil { - return d, err - } d.generateResource(d.GetResources(tools.DATA_RESOURCE), request) d.generateResource(d.GetResources(tools.PROCESSING_RESOURCE), request) d.generateResource(d.GetResources(tools.STORAGE_RESOURCE), request)