diff --git a/models/workflow/workflow.go b/models/workflow/workflow.go index d83575e..57eb2a6 100644 --- a/models/workflow/workflow.go +++ b/models/workflow/workflow.go @@ -215,8 +215,30 @@ func (d *Workflow) ExtractFromPlantUML(plantUML multipart.File, request *tools.A } } + // Handle links outside the catalog loop: each link line must be processed + // exactly once (the catalog loop would otherwise call extractLink once per + // catalog entry, producing NĂ—7 duplicate links in the graph). + if strings.Contains(line, "-->") { + if err := d.extractLink(parseLine, graphVarName, "-->", false); err != nil { + fmt.Println(err) + } + continue + } + if strings.Contains(line, "<--") { + if err := d.extractLink(parseLine, graphVarName, "<--", true); err != nil { + fmt.Println(err) + } + continue + } + if strings.Contains(line, "--") { + if err := d.extractLink(parseLine, graphVarName, "--", false); err != nil { + fmt.Println(err) + } + continue + } + for n, new := range resourceCatalog { - if strings.Contains(line, n+"(") && !strings.Contains(line, "!procedure") && !strings.Contains(line, "!define") { // exclude macro declarations + if strings.Contains(line, n+"(") && !strings.Contains(line, "!procedure") && !strings.Contains(line, "!define") { newRes := new() newRes.SetID(uuid.New().String()) varName, graphItem, err := d.extractResourcePlantUML(parseLine, newRes, n, request.PeerID) @@ -226,31 +248,7 @@ func (d *Workflow) ExtractFromPlantUML(plantUML multipart.File, request *tools.A if graphItem != nil { graphVarName[varName] = *graphItem } - continue - } else if strings.Contains(line, "-->") { - err := d.extractLink(parseLine, graphVarName, "-->", false) - if err != nil { - fmt.Println(err) - continue - } - } else if strings.Contains(line, "<--") { - err := d.extractLink(parseLine, graphVarName, "<--", true) - if err != nil { - fmt.Println(err) - continue - } - } else if strings.Contains(line, "--") { - err := d.extractLink(parseLine, graphVarName, "--", false) - if err != nil { - fmt.Println(err) - continue - } - } else if strings.Contains(line, "-") { - err := d.extractLink(parseLine, graphVarName, "-", false) - if err != nil { - fmt.Println(err) - continue - } + break } } } @@ -355,14 +353,37 @@ func (d *Workflow) extractLink(line string, graphVarName map[string]graph.GraphI if len(splitted) < 2 { return errors.New("links elements not found") } + + // Source: trim surrounding whitespace. + srcVar := strings.TrimSpace(splitted[0]) + + // Destination: trim whitespace then stop at the first space or apostrophe + // (the rest may be a trailing comment produced by ToPlantUML look-ahead). + dstTokens := strings.FieldsFunc(strings.TrimSpace(splitted[1]), func(r rune) bool { + return r == ' ' || r == '\t' || r == '\'' + }) + if len(dstTokens) == 0 { + return errors.New("link destination var name not found") + } + dstVar := dstTokens[0] + + srcItem, srcOk := graphVarName[srcVar] + dstItem, dstOk := graphVarName[dstVar] + if !srcOk || srcItem.ID == "" { + return fmt.Errorf("link source %q not declared", srcVar) + } + if !dstOk || dstItem.ID == "" { + return fmt.Errorf("link destination %q not declared", dstVar) + } + link := &graph.GraphLink{ Source: graph.Position{ - ID: graphVarName[splitted[0]].ID, + ID: srcItem.ID, X: 0, Y: 0, }, Destination: graph.Position{ - ID: graphVarName[splitted[1]].ID, + ID: dstItem.ID, X: 0, Y: 0, },