diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index db9c695..e6d34b0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -101,7 +101,6 @@ jobs: projectDirectory: resources/app-mpr-v1 modelsource: resources/modelsource-v1 export: - mode: basic filter: ".*" raw: false appstore: false @@ -132,7 +131,6 @@ jobs: projectDirectory: resources/app-mpr-v2 modelsource: resources/modelsource-v2 export: - mode: basic filter: ".*" raw: false appstore: false diff --git a/README.md b/README.md index 12d2af0..a7207bb 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,6 @@ mxlint-cli export-model [flags] |------|-------|---------|-------------| | `--input` | `-i` | `.` | Path to directory or mpr file to export. If it's a directory, all mpr files will be exported | | `--output` | `-o` | `modelsource` | Path to directory to write the yaml files. If it doesn't exist, it will be created | -| `--mode` | `-m` | `basic` | Export mode. Valid options: `basic`, `advanced` | | `--filter` | `-f` | | Regex pattern to filter units by name. Only units with names matching the pattern will be exported | | `--raw` | | `false` | If set, the output yaml will include all attributes as they are in the model | | `--appstore` | | `false` | If set, appstore modules will be included in the output | @@ -107,7 +106,6 @@ lint: export: output: modelsource input: . - mode: basic filter: "*" ``` @@ -166,7 +164,6 @@ mxlint-cli serve [flags] |------|-------|---------|-------------| | `--input` | `-i` | `.` | Path to directory or mpr file to export. If it's a directory, all mpr files will be exported | | `--output` | `-o` | `modelsource` | Path to directory to write the yaml files. If it doesn't exist, it will be created | -| `--mode` | `-m` | `basic` | Export mode. Valid options: `basic`, `advanced` | | `--rules` | `-r` | `.mendix-cache/rules` | Path to directory with rules | | `--port` | `-p` | `8082` | Port to run the server on | | `--debounce` | `-d` | `500` | Debounce time in milliseconds for file change events | @@ -336,7 +333,6 @@ INFO[0000] Starting server on port 8084 INFO[0000] Watching for changes in /Users/xcheng/project INFO[0000] Output directory: modelsource INFO[0000] Rules directory: rules -INFO[0000] Mode: basic INFO[0000] Debounce time: 500 ms INFO[0000] HTTP server listening on 127.0.0.1:8084 INFO[0000] Dashboard available at http://localhost:8084 @@ -374,7 +370,7 @@ INFO[0000] PASS no_allow_2 - Lint Mendix Yaml files for common mistakes and enforces best practices - Watch for changes and automatically re-lint - Serve lint results via HTTP for integration with other tools -- Microflow transformation to more readable format (advanced mode) +- Microflow transformation to more readable format - Support for both Rego and JavaScript rules - Human readable output diff --git a/default.yaml b/default.yaml index 036798c..3981c82 100644 --- a/default.yaml +++ b/default.yaml @@ -11,7 +11,6 @@ lint: modelsource: modelsource projectDirectory: . export: - mode: basic filter: ".*" raw: false appstore: false diff --git a/lint/config.go b/lint/config.go index 9a9576e..94c1480 100644 --- a/lint/config.go +++ b/lint/config.go @@ -28,7 +28,6 @@ type ConfigRulesSpec struct { } type ConfigExportSpec struct { - Mode string `yaml:"mode"` Filter string `yaml:"filter"` Raw *bool `yaml:"raw"` Appstore *bool `yaml:"appstore"` @@ -264,9 +263,6 @@ func mergeConfig(base *Config, overlay *Config) { base.Rules.Rulesets = append([]string{}, overlay.Rules.Rulesets...) } - if strings.TrimSpace(overlay.Export.Mode) != "" { - base.Export.Mode = strings.TrimSpace(overlay.Export.Mode) - } if overlay.Export.Filter != "" { base.Export.Filter = strings.TrimSpace(overlay.Export.Filter) } diff --git a/lint/config_test.go b/lint/config_test.go index 885a7f2..fe640d4 100644 --- a/lint/config_test.go +++ b/lint/config_test.go @@ -27,7 +27,6 @@ func TestLoadMergedConfig_ProjectOverridesSystem(t *testing.T) { modelsource: modelsource-system projectDirectory: ./system export: - mode: advanced filter: system/* lint: skip: @@ -42,7 +41,6 @@ lint: modelsource: modelsource projectDirectory: . export: - mode: basic filter: "*" lint: skip: @@ -78,7 +76,7 @@ lint: if len(cfg.Rules.Rulesets) != 1 || cfg.Rules.Rulesets[0] != "file://project-rules" { t.Fatalf("expected project rules.rulesets override, got %#v", cfg.Rules.Rulesets) } - if cfg.Modelsource != "modelsource" || cfg.ProjectDirectory != "." || cfg.Export.Mode != "basic" || cfg.Export.Filter != "*" { + if cfg.Modelsource != "modelsource" || cfg.ProjectDirectory != "." || cfg.Export.Filter != "*" { t.Fatalf("expected project config override, got modelsource=%s projectDirectory=%s export=%#v", cfg.Modelsource, cfg.ProjectDirectory, cfg.Export) } @@ -126,7 +124,6 @@ func TestLoadMergedConfig_DefaultConfigBase(t *testing.T) { modelsource: default-modelsource projectDirectory: ./default-input export: - mode: advanced filter: default/* ` setDefaultConfigForTest(t, defaultConfig) @@ -139,7 +136,7 @@ export: if cfg.Rules.Path != ".mendix-cache/default-rules" { t.Fatalf("expected default rules path, got %s", cfg.Rules.Path) } - if cfg.Modelsource != "default-modelsource" || cfg.ProjectDirectory != "./default-input" || cfg.Export.Mode != "advanced" || cfg.Export.Filter != "default/*" { + if cfg.Modelsource != "default-modelsource" || cfg.ProjectDirectory != "./default-input" || cfg.Export.Filter != "default/*" { t.Fatalf("expected default values, got modelsource=%s projectDirectory=%s export=%#v", cfg.Modelsource, cfg.ProjectDirectory, cfg.Export) } } diff --git a/lint/lint_javascript.go b/lint/lint_javascript.go index 179f20f..45386cb 100644 --- a/lint/lint_javascript.go +++ b/lint/lint_javascript.go @@ -195,15 +195,29 @@ func evalTestcase_Javascript(rulePath string, inputFilePath string, ruleNumber s } res, err := ruleFunction(sobek.Undefined(), vm.ToValue(data)) + + duration := time.Since(startTime) + var failure *Failure = nil + if err != nil { - panic(err) - } + errorMessage := fmt.Sprintf("Error evaluating javascript rule %v for inputfile %v: %v", rulePath, inputFilePath, err) + log.Error(errorMessage) - rs := res.Export().(map[string]interface{}) + failure = &Failure{ + Message: errorMessage, + Type: "RuntimeError", + } - duration := time.Since(startTime) + testcase := &Testcase{ + Name: inputFilePath, + Time: float64(duration.Nanoseconds()) / 1e9, // convert to seconds + Failure: failure, + Skipped: nil, + } + return testcase, nil + } - var failure *Failure = nil + rs := res.Export().(map[string]interface{}) log.Debugf("Result: %v", rs) result := rs["allow"].(bool) diff --git a/lint/lint_test.go b/lint/lint_test.go index d86b92e..d3e8087 100644 --- a/lint/lint_test.go +++ b/lint/lint_test.go @@ -539,9 +539,26 @@ function rule(input) { t.Fatalf("Failed to write yaml file: %v", err) } - _, err = EvalAllWithResults(tempDir, tempDir, "", "", false, false) - if err == nil { - t.Error("Expected error due to failures") + rule := Rule{ + Path: jsPath, + Pattern: ".*\\.yaml", + PackageName: jsPath, + RuleNumber: "099_0099", + Language: LanguageJavascript, + } + + result, err := evalTestsuite(rule, tempDir, false, false) + if err != nil { + t.Fatalf("Expected testsuite evaluation to succeed, got: %v", err) + } + if result.Failures != 1 { + t.Fatalf("Expected 1 failure, got %d", result.Failures) + } + if len(result.Testcases) != 1 || result.Testcases[0].Failure == nil { + t.Fatalf("Expected one failing testcase, got %+v", result.Testcases) + } + if !strings.Contains(result.Testcases[0].Failure.Message, "Always fails") { + t.Fatalf("Expected failure message to contain rule error, got: %s", result.Testcases[0].Failure.Message) } }) } diff --git a/main.go b/main.go index 43a892d..2c17cbe 100644 --- a/main.go +++ b/main.go @@ -56,7 +56,6 @@ func main() { inputDirectory, outputDirectory, boolValue(config.Export.Raw, false), - config.Export.Mode, boolValue(config.Export.Appstore, false), config.Export.Filter, ) diff --git a/mpr/microflow.go b/mpr/microflow.go index 3a6c1c3..1b217e0 100644 --- a/mpr/microflow.go +++ b/mpr/microflow.go @@ -1,68 +1,91 @@ package mpr +const microflowDocumentType = "Microflows$Microflow" + +func enrichMicroflowDocument(mf MxDocument) MxDocument { + mf = addMicroflowPseudocode(mf) + mf = transformMicroflow(mf) + return mf +} + func transformMicroflow(mf MxDocument) MxDocument { - // Transform a microflow log.Infof("Transforming microflow %s", mf.Name) cleanedData := bsonToMap(mf.Attributes) + objs, flows, ok := extractMicroflowGraphData(mf.Name, cleanedData) + if !ok { + return mf + } + startEvent, ok := getMxMicroflowObjectByType(objs, "Microflows$StartEvent") + if !ok { + log.Warnf("StartEvent not found for microflow %s, skipping transformation", mf.Name) + return mf + } + + root := MxMicroflowNode{ + Type: startEvent.Type, + ID: startEvent.ID, + Attributes: startEvent.Attributes, + } + buildDAG(&root, nil, flows, objs) + mainFlow := make([]map[string]interface{}, 0) + labels := make(map[string]interface{}, 0) + extractMainFlow(&mainFlow, &root, &labels) + mf.Attributes["MainFunction"] = mainFlow + // remove ObjectCollection + delete(mf.Attributes, "ObjectCollection") + return mf +} + +func addMicroflowPseudocode(mf MxDocument) MxDocument { + cleanedData := bsonToMap(mf.Attributes) + pseudocode, err := generateMicroflowPseudocode(mf.Name, cleanedData) + if err != nil { + log.Warnf("Could not generate pseudocode for microflow %s: %v", mf.Name, err) + return mf + } + mf.Attributes["pseudocode"] = pseudocode + return mf +} - // Check if ObjectCollection exists +func extractMicroflowGraphData(name string, cleanedData map[string]interface{}) ([]MxMicroflowObject, []MxMicroflowEdge, bool) { objsCollectionRaw, ok := cleanedData["ObjectCollection"] if !ok || objsCollectionRaw == nil { - log.Warnf("ObjectCollection not found for microflow %s, skipping transformation", mf.Name) - return mf + log.Warnf("ObjectCollection not found for microflow %s, skipping transformation", name) + return nil, nil, false } objsCollection, ok := objsCollectionRaw.(map[string]interface{}) if !ok { - log.Warnf("ObjectCollection is not a map for microflow %s, skipping transformation", mf.Name) - return mf + log.Warnf("ObjectCollection is not a map for microflow %s, skipping transformation", name) + return nil, nil, false } objectsRaw, ok := objsCollection["Objects"] if !ok || objectsRaw == nil { - log.Warnf("Objects not found in ObjectCollection for microflow %s, skipping transformation", mf.Name) - return mf + log.Warnf("Objects not found in ObjectCollection for microflow %s, skipping transformation", name) + return nil, nil, false } objects, ok := objectsRaw.([]interface{}) if !ok { - log.Warnf("Objects is not a slice for microflow %s, skipping transformation", mf.Name) - return mf + log.Warnf("Objects is not a slice for microflow %s, skipping transformation", name) + return nil, nil, false } - objs := convertToMxMicroflowObjects(objects) - - // Check if Flows exists flowsRaw, ok := cleanedData["Flows"] if !ok || flowsRaw == nil { - log.Warnf("Flows not found for microflow %s, skipping transformation", mf.Name) - return mf + log.Warnf("Flows not found for microflow %s, skipping transformation", name) + return nil, nil, false } flowsSlice, ok := flowsRaw.([]interface{}) if !ok { - log.Warnf("Flows is not a slice for microflow %s, skipping transformation", mf.Name) - return mf + log.Warnf("Flows is not a slice for microflow %s, skipping transformation", name) + return nil, nil, false } - flows := convertToMxMicroflowEdges(flowsSlice) - - startEvent := getMxMicroflowObjectByType(objs, "Microflows$StartEvent") - - root := MxMicroflowNode{ - Type: startEvent.Type, - ID: startEvent.ID, - Attributes: startEvent.Attributes, - } - buildDAG(&root, nil, flows, objs) - mainFlow := make([]map[string]interface{}, 0) - labels := make(map[string]interface{}, 0) - extractMainFlow(&mainFlow, &root, &labels) - mf.Attributes["MainFunction"] = mainFlow - // remove ObjectCollection - delete(mf.Attributes, "ObjectCollection") - return mf + return convertToMxMicroflowObjects(objects), convertToMxMicroflowEdges(flowsSlice), true } func extractMainFlow(mainFlow *[]map[string]interface{}, current *MxMicroflowNode, labels *map[string]interface{}) { @@ -138,7 +161,12 @@ func buildDAG(current *MxMicroflowNode, parent *MxMicroflowNode, flows []MxMicro return } case "Microflows$SequenceFlow": - obj := getMxMicroflowObjectByID(objects, current.Attributes["DestinationPointer"].(string)) + destination, _ := current.Attributes["DestinationPointer"].(string) + obj, ok := getMxMicroflowObjectByID(objects, destination) + if !ok { + log.Warnf("Destination object %s not found for sequence flow %s", destination, current.ID) + return + } objectNode := MxMicroflowNode{ Type: obj.Type, ID: obj.ID, @@ -183,31 +211,39 @@ func getMxMicroflowEdgesByOrigin(edges []MxMicroflowEdge, originId string) []MxM return result } -func getMxMicroflowObjectByType(objs []MxMicroflowObject, objType string) MxMicroflowObject { +func getMxMicroflowObjectByType(objs []MxMicroflowObject, objType string) (MxMicroflowObject, bool) { for _, obj := range objs { if obj.Type == objType { - return obj + return obj, true } } - panic("MPR file probably corrupted") + return MxMicroflowObject{}, false } -func getMxMicroflowObjectByID(objs []MxMicroflowObject, objID string) MxMicroflowObject { +func getMxMicroflowObjectByID(objs []MxMicroflowObject, objID string) (MxMicroflowObject, bool) { for _, obj := range objs { if obj.ID == objID { - return obj + return obj, true } } - panic("MPR file probably corrupted") + return MxMicroflowObject{}, false } func convertToMxMicroflowObjects(objs []interface{}) []MxMicroflowObject { - result := make([]MxMicroflowObject, len(objs)) + result := make([]MxMicroflowObject, 0, len(objs)) for _, o := range objs { - castedObject := o.(map[string]interface{}) + castedObject, ok := o.(map[string]interface{}) + if !ok { + continue + } + objType, _ := castedObject["$Type"].(string) + id := readMicroflowID(castedObject["$ID"]) + if objType == "" || id == "" { + continue + } result = append(result, MxMicroflowObject{ - Type: castedObject["$Type"].(string), - ID: castedObject["$ID"].(string), + Type: objType, + ID: id, Attributes: castedObject, }) } @@ -215,14 +251,24 @@ func convertToMxMicroflowObjects(objs []interface{}) []MxMicroflowObject { } func convertToMxMicroflowEdges(flows []interface{}) []MxMicroflowEdge { - result := make([]MxMicroflowEdge, len(flows)) + result := make([]MxMicroflowEdge, 0, len(flows)) for _, f := range flows { - castedFlow := f.(map[string]interface{}) + castedFlow, ok := f.(map[string]interface{}) + if !ok { + continue + } + flowType, _ := castedFlow["$Type"].(string) + id := readMicroflowID(castedFlow["$ID"]) + origin := readMicroflowID(castedFlow["OriginPointer"]) + destination := readMicroflowID(castedFlow["DestinationPointer"]) + if flowType == "" || id == "" || origin == "" || destination == "" { + continue + } result = append(result, MxMicroflowEdge{ - Type: castedFlow["$Type"].(string), - ID: castedFlow["$ID"].(string), - Origin: castedFlow["OriginPointer"].(string), - Destination: castedFlow["DestinationPointer"].(string), + Type: flowType, + ID: id, + Origin: origin, + Destination: destination, Attributes: castedFlow, }) } diff --git a/mpr/microflow_pseudocode.go b/mpr/microflow_pseudocode.go new file mode 100644 index 0000000..54777a0 --- /dev/null +++ b/mpr/microflow_pseudocode.go @@ -0,0 +1,777 @@ +package mpr + +import ( + "fmt" + "slices" + "strconv" + "strings" +) + +type microflowFlow struct { + ID string + Origin string + Destination string + CaseValues []string +} + +func generateMicroflowPseudocode(microflowName string, attributes map[string]interface{}) (string, error) { + graph, err := buildMicroflowGraph(attributes) + if err != nil { + return "", err + } + + orderedNodeIDs := traverseMicroflowNodes(graph.startID, graph.outgoing) + if len(orderedNodeIDs) == 0 { + return "", fmt.Errorf("no traversable nodes in microflow %s", microflowName) + } + + labelByID, needsLabel := computeLabels(graph, orderedNodeIDs) + + var b strings.Builder + b.WriteString(fmt.Sprintf("MICROFLOW: %s\n", microflowName)) + b.WriteString(fmt.Sprintf("RETURN TYPE: %s\n", extractReturnType(attributes))) + params := extractMicroflowParameters(graph.objectsByID) + if len(params) > 0 { + b.WriteString("PARAMETERS:\n") + for _, p := range params { + b.WriteString(fmt.Sprintf(" - %s\n", p)) + } + } + b.WriteString("\nPSEUDOCODE\n----------\n") + b.WriteString("BEGIN\n") + + for idx, nodeID := range orderedNodeIDs { + node := graph.objectsByID[nodeID] + nodeType, _ := node["$Type"].(string) + out := graph.outgoing[nodeID] + nextID := "" + if idx+1 < len(orderedNodeIDs) { + nextID = orderedNodeIDs[idx+1] + } + + if needsLabel[nodeID] { + b.WriteString(fmt.Sprintf(" LABEL %s\n", labelByID[nodeID])) + } + for _, line := range renderNodeInstruction(nodeID, node, nodeType, graph) { + b.WriteString(" " + line + "\n") + } + for _, line := range renderControlFlow(nodeType, node, out, labelByID, nextID) { + b.WriteString(" " + line + "\n") + } + b.WriteString("\n") + } + + b.WriteString("END") + return b.String(), nil +} + +func renderNodeInstruction(nodeID string, node map[string]interface{}, nodeType string, graph microflowGraph) []string { + switch nodeType { + case "Microflows$ActionActivity": + actionRaw, ok := node["Action"].(map[string]interface{}) + if !ok { + return []string{"// ActionActivity (unparsed action)"} + } + actionType, _ := actionRaw["$Type"].(string) + switch actionType { + case "Microflows$LogMessageAction": + msg := extractNestedString(actionRaw, "MessageTemplate", "Text") + return []string{fmt.Sprintf("log info: %q", msg)} + case "Microflows$CreateVariableAction": + name, _ := actionRaw["VariableName"].(string) + initial, _ := actionRaw["InitialValue"].(string) + return []string{fmt.Sprintf("%s = %s", name, initial)} + case "Microflows$ChangeVariableAction": + name, _ := actionRaw["ChangeVariableName"].(string) + value, _ := actionRaw["Value"].(string) + return []string{fmt.Sprintf("%s = %s", name, value)} + case "Microflows$RetrieveAction": + result, _ := actionRaw["ResultVariableName"].(string) + entity := extractNestedString(actionRaw, "RetrieveSource", "Entity") + if result == "" { + result = "" + } + if entity == "" { + entity = "" + } + return []string{fmt.Sprintf("%s = retrieve from database %s", result, entity)} + case "Microflows$ChangeAction": + return renderChangeAction(actionRaw) + case "Microflows$MicroflowCallAction": + return []string{renderMicroflowCallAction(actionRaw)} + default: + return []string{fmt.Sprintf("// action: %s", actionType)} + } + case "Microflows$ExclusiveSplit": + return nil + case "Microflows$ExclusiveMerge": + return nil + case "Microflows$LoopedActivity": + return renderLoopedActivity(nodeID, node, graph) + case "Microflows$StartEvent": + return nil + case "Microflows$EndEvent": + return nil + default: + return []string{fmt.Sprintf("// node: %s", nodeType)} + } +} + +func renderChangeAction(actionRaw map[string]interface{}) []string { + variableName, _ := actionRaw["ChangeVariableName"].(string) + if variableName == "" { + variableName = "" + } + lines := make([]string, 0) + + for _, item := range asObjectSlice(actionRaw["Items"]) { + itemType, _ := item["$Type"].(string) + if itemType != "Microflows$ChangeActionItem" { + continue + } + attribute, _ := item["Attribute"].(string) + value, _ := item["Value"].(string) + if value == "" { + value = "" + } + fieldName := attribute + if idx := strings.LastIndex(attribute, "."); idx >= 0 && idx+1 < len(attribute) { + fieldName = attribute[idx+1:] + } + if fieldName == "" { + fieldName = "" + } + lines = append(lines, fmt.Sprintf("%s.%s = %s", variableName, fieldName, value)) + } + if commit, _ := actionRaw["Commit"].(string); strings.EqualFold(commit, "yes") { + lines = append(lines, fmt.Sprintf("commit %s", variableName)) + } + if len(lines) == 0 { + lines = append(lines, "// change object") + } + return lines +} + +func renderMicroflowCallAction(actionRaw map[string]interface{}) string { + call, ok := actionRaw["MicroflowCall"].(map[string]interface{}) + if !ok { + return "call " + } + microflowName, _ := call["Microflow"].(string) + if microflowName == "" { + microflowName = "" + } + args := make([]string, 0) + for _, mapping := range asObjectSlice(call["ParameterMappings"]) { + param, _ := mapping["Parameter"].(string) + arg, _ := mapping["Argument"].(string) + if param == "" || arg == "" { + continue + } + shortParam := param + if idx := strings.LastIndex(param, "."); idx >= 0 && idx+1 < len(param) { + shortParam = param[idx+1:] + } + args = append(args, fmt.Sprintf("%s = %s", shortParam, arg)) + } + if len(args) == 0 { + return fmt.Sprintf("call %s()", microflowName) + } + return fmt.Sprintf("call %s(%s)", microflowName, strings.Join(args, ", ")) +} + +func renderLoopedActivity(nodeID string, node map[string]interface{}, graph microflowGraph) []string { + loopSource, _ := node["LoopSource"].(map[string]interface{}) + listName, _ := loopSource["ListVariableName"].(string) + iteratorName, _ := loopSource["VariableName"].(string) + if listName == "" { + listName = "" + } + if iteratorName == "" { + iteratorName = "" + } + + innerObjects := getLoopObjectCollectionObjects(node) + if len(innerObjects) == 0 { + return []string{fmt.Sprintf("FOR EACH %s IN %s", iteratorName, listName), "END FOR"} + } + + innerByID := make(map[string]map[string]interface{}, len(innerObjects)) + for _, obj := range innerObjects { + id := readMicroflowID(obj["$ID"]) + if id == "" { + continue + } + innerByID[id] = obj + } + if len(innerByID) == 0 { + return []string{fmt.Sprintf("FOR EACH %s IN %s", iteratorName, listName), "END FOR"} + } + + splitID, splitObj := findFirstExclusiveSplit(innerByID) + if splitID != "" { + branchFlows := make([]microflowFlow, 0, 2) + for _, f := range graph.outgoing[splitID] { + if _, ok := innerByID[f.Destination]; ok { + branchFlows = append(branchFlows, f) + } + } + if len(branchFlows) == 2 { + var trueDest, falseDest string + for _, f := range branchFlows { + switch firstCaseValue(f.CaseValues) { + case "true": + trueDest = f.Destination + case "false": + falseDest = f.Destination + } + } + if trueDest != "" && falseDest != "" { + expr := extractNestedString(splitObj, "SplitCondition", "Expression") + if expr == "" { + expr = "" + } + trueLines := collectLinearBranchLines(trueDest, innerByID, graph.outgoing, graph) + falseLines := collectLinearBranchLines(falseDest, innerByID, graph.outgoing, graph) + lines := []string{fmt.Sprintf("FOR EACH %s IN %s", iteratorName, listName)} + lines = append(lines, fmt.Sprintf(" IF %s THEN", expr)) + for _, l := range trueLines { + lines = append(lines, " "+l) + } + lines = append(lines, " ELSE") + for _, l := range falseLines { + lines = append(lines, " "+l) + } + lines = append(lines, " END IF") + lines = append(lines, "END FOR") + return lines + } + } + } + + lines := []string{fmt.Sprintf("FOR EACH %s IN %s", iteratorName, listName)} + entries := getInnerEntryNodes(innerByID, graph.outgoing) + for _, entry := range entries { + for _, l := range collectLinearBranchLines(entry, innerByID, graph.outgoing, graph) { + lines = append(lines, " "+l) + } + } + lines = append(lines, "END FOR") + return lines +} + +func traverseLoopBody(entryIDs []string, outgoing map[string][]microflowFlow, scope map[string]map[string]interface{}) []string { + visited := make(map[string]bool, len(scope)) + order := make([]string, 0, len(scope)) + var visit func(string) + visit = func(id string) { + if id == "" || visited[id] { + return + } + if _, ok := scope[id]; !ok { + return + } + visited[id] = true + order = append(order, id) + for _, edge := range outgoing[id] { + if _, ok := scope[edge.Destination]; ok { + visit(edge.Destination) + } + } + } + + for _, entry := range entryIDs { + visit(entry) + } + for id := range scope { + visit(id) + } + return order +} + +func getLoopObjectCollectionObjects(node map[string]interface{}) []map[string]interface{} { + collection, ok := node["ObjectCollection"].(map[string]interface{}) + if !ok { + return nil + } + return asObjectSlice(collection["Objects"]) +} + +func asObjectSlice(raw interface{}) []map[string]interface{} { + items, ok := raw.([]interface{}) + if !ok { + return nil + } + result := make([]map[string]interface{}, 0, len(items)) + for _, item := range items { + m, ok := item.(map[string]interface{}) + if !ok { + continue + } + result = append(result, m) + } + return result +} + +func firstIDSegment(id string) string { + if id == "" { + return "X" + } + parts := strings.Split(id, "-") + if len(parts) == 0 || parts[0] == "" { + return "X" + } + raw := parts[0] + var b strings.Builder + for _, r := range raw { + if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') { + b.WriteRune(r) + } else { + b.WriteByte('_') + } + } + token := strings.Trim(b.String(), "_") + if token == "" { + return "X" + } + if len(token) > 12 { + token = token[:12] + } + return token +} + +func renderControlFlow(nodeType string, node map[string]interface{}, out []microflowFlow, labelByID map[string]string, nextID string) []string { + if nodeType == "Microflows$EndEvent" || nodeType == "Microflows$LoopedActivity" { + return nil + } + if len(out) == 0 { + return nil + } + + switch nodeType { + case "Microflows$ExclusiveSplit": + expr := extractNestedString(node, "SplitCondition", "Expression") + if expr == "" { + expr = "" + } + + // Fast path for two-way boolean split. + if len(out) == 2 { + var trueFlow *microflowFlow + var falseFlow *microflowFlow + for i := range out { + switch firstCaseValue(out[i].CaseValues) { + case "true": + trueFlow = &out[i] + case "false": + falseFlow = &out[i] + } + } + + if trueFlow != nil && falseFlow != nil { + trueLabel := labelByID[trueFlow.Destination] + falseLabel := labelByID[falseFlow.Destination] + if trueLabel == "" { + trueLabel = "" + } + if falseLabel == "" { + falseLabel = "" + } + return []string{ + fmt.Sprintf("IF %s THEN", expr), + fmt.Sprintf(" GOTO %s", trueLabel), + "ELSE", + fmt.Sprintf(" GOTO %s", falseLabel), + "END IF", + } + } + } + + // Generic split fallback, preserving all outgoing branches. + lines := []string{fmt.Sprintf("IF %s THEN", expr)} + for idx, flow := range out { + label := labelByID[flow.Destination] + if label == "" { + label = "" + } + caseLabel := strings.Join(flow.CaseValues, ", ") + if caseLabel == "" { + caseLabel = "default" + } + prefix := " GOTO" + if idx > 0 { + prefix = " // OR GOTO" + } + lines = append(lines, fmt.Sprintf("%s %s // case: %s", prefix, label, caseLabel)) + } + lines = append(lines, "END IF") + return lines + default: + dest := out[0].Destination + if dest == nextID { + return nil + } + return []string{fmt.Sprintf("GOTO %s", labelByID[dest])} + } +} + +func computeLabels(graph microflowGraph, orderedNodeIDs []string) (map[string]string, map[string]bool) { + nextByID := make(map[string]string, len(orderedNodeIDs)) + for i, id := range orderedNodeIDs { + if i+1 < len(orderedNodeIDs) { + nextByID[id] = orderedNodeIDs[i+1] + } + } + + incoming := make(map[string][]string) + for origin, outs := range graph.outgoing { + for _, edge := range outs { + incoming[edge.Destination] = append(incoming[edge.Destination], origin) + } + } + + needsLabel := make(map[string]bool, len(orderedNodeIDs)) + for _, id := range orderedNodeIDs { + preds := incoming[id] + if len(preds) == 0 { + continue + } + if len(preds) > 1 { + needsLabel[id] = true + continue + } + pred := preds[0] + predOut := graph.outgoing[pred] + if len(predOut) != 1 || nextByID[pred] != id { + needsLabel[id] = true + } + } + + labelByID := make(map[string]string) + labelCounter := 1 + for _, id := range orderedNodeIDs { + if needsLabel[id] { + labelByID[id] = fmt.Sprintf("L%03d", labelCounter) + labelCounter++ + } + } + return labelByID, needsLabel +} + +func findFirstExclusiveSplit(innerByID map[string]map[string]interface{}) (string, map[string]interface{}) { + ids := make([]string, 0, len(innerByID)) + for id := range innerByID { + ids = append(ids, id) + } + slices.Sort(ids) + for _, id := range ids { + obj := innerByID[id] + objType, _ := obj["$Type"].(string) + if objType == "Microflows$ExclusiveSplit" { + return id, obj + } + } + return "", nil +} + +func collectLinearBranchLines(startID string, scope map[string]map[string]interface{}, outgoing map[string][]microflowFlow, graph microflowGraph) []string { + lines := make([]string, 0) + visited := make(map[string]bool) + currentID := startID + for currentID != "" { + if visited[currentID] { + break + } + visited[currentID] = true + node, ok := scope[currentID] + if !ok { + break + } + nodeType, _ := node["$Type"].(string) + if nodeType == "Microflows$ExclusiveSplit" { + break + } + lines = append(lines, renderNodeInstruction(currentID, node, nodeType, graph)...) + next := "" + for _, flow := range outgoing[currentID] { + if _, ok := scope[flow.Destination]; ok { + next = flow.Destination + break + } + } + if next == "" { + break + } + currentID = next + } + if len(lines) == 0 { + lines = append(lines, "// no-op") + } + return lines +} + +func getInnerEntryNodes(scope map[string]map[string]interface{}, outgoing map[string][]microflowFlow) []string { + incoming := make(map[string]int, len(scope)) + for id := range scope { + incoming[id] = 0 + } + for origin, outs := range outgoing { + if _, ok := scope[origin]; !ok { + continue + } + for _, f := range outs { + if _, ok := scope[f.Destination]; ok { + incoming[f.Destination]++ + } + } + } + entries := make([]string, 0) + for id, count := range incoming { + if count == 0 { + entries = append(entries, id) + } + } + slices.Sort(entries) + if len(entries) == 0 { + for id := range scope { + entries = append(entries, id) + } + slices.Sort(entries) + } + return entries +} + +func firstCaseValue(values []string) string { + if len(values) == 0 { + return "" + } + return strings.ToLower(strings.TrimSpace(values[0])) +} + +func extractNestedString(m map[string]interface{}, keys ...string) string { + current := m + for i, key := range keys { + value, ok := current[key] + if !ok { + return "" + } + if i == len(keys)-1 { + s, _ := value.(string) + return s + } + next, ok := value.(map[string]interface{}) + if !ok { + return "" + } + current = next + } + return "" +} + +func extractReturnType(attributes map[string]interface{}) string { + rt, ok := attributes["MicroflowReturnType"].(map[string]interface{}) + if !ok { + return "unknown" + } + return formatDataType(rt) +} + +func extractMicroflowParameters(objectsByID map[string]map[string]interface{}) []string { + params := make([]string, 0) + for _, obj := range objectsByID { + objType, _ := obj["$Type"].(string) + if objType != "Microflows$MicroflowParameter" { + continue + } + name, _ := obj["Name"].(string) + varType, _ := obj["VariableType"].(map[string]interface{}) + required, _ := obj["IsRequired"].(bool) + requiredText := "optional" + if required { + requiredText = "required" + } + params = append(params, fmt.Sprintf("%s: %s (%s)", name, formatDataType(varType), requiredText)) + } + slices.Sort(params) + return params +} + +func formatDataType(raw map[string]interface{}) string { + typeName, _ := raw["$Type"].(string) + switch typeName { + case "DataTypes$VoidType": + return "void" + case "DataTypes$IntegerType": + return "integer" + case "DataTypes$BooleanType": + return "boolean" + case "DataTypes$StringType": + return "string" + case "DataTypes$ObjectType": + entity, _ := raw["Entity"].(string) + if entity == "" { + return "object" + } + return entity + default: + if typeName == "" { + return "unknown" + } + return typeName + } +} + +type microflowGraph struct { + objectsByID map[string]map[string]interface{} + outgoing map[string][]microflowFlow + startID string +} + +func buildMicroflowGraph(attributes map[string]interface{}) (microflowGraph, error) { + objectsByID := make(map[string]map[string]interface{}) + outgoing := make(map[string][]microflowFlow) + startID := "" + + objectCollectionRaw, ok := attributes["ObjectCollection"].(map[string]interface{}) + if !ok { + return microflowGraph{}, fmt.Errorf("ObjectCollection not found") + } + objectsRaw, ok := objectCollectionRaw["Objects"].([]interface{}) + if !ok { + return microflowGraph{}, fmt.Errorf("ObjectCollection.Objects not found") + } + + for _, item := range objectsRaw { + obj, ok := item.(map[string]interface{}) + if !ok { + continue + } + id := readMicroflowID(obj["$ID"]) + if id == "" { + continue + } + objectsByID[id] = obj + if objType, _ := obj["$Type"].(string); objType == "Microflows$StartEvent" { + startID = id + } + } + if startID == "" { + return microflowGraph{}, fmt.Errorf("start event not found") + } + + flowsRaw, ok := attributes["Flows"].([]interface{}) + if !ok { + return microflowGraph{}, fmt.Errorf("Flows not found") + } + + for _, item := range flowsRaw { + flowMap, ok := item.(map[string]interface{}) + if !ok { + continue + } + origin := readMicroflowID(flowMap["OriginPointer"]) + dest := readMicroflowID(flowMap["DestinationPointer"]) + if origin == "" || dest == "" { + continue + } + flow := microflowFlow{ + ID: readMicroflowID(flowMap["$ID"]), + Origin: origin, + Destination: dest, + CaseValues: extractCaseValues(flowMap["CaseValues"]), + } + outgoing[origin] = append(outgoing[origin], flow) + } + + return microflowGraph{ + objectsByID: objectsByID, + outgoing: outgoing, + startID: startID, + }, nil +} + +func extractCaseValues(raw interface{}) []string { + items, ok := raw.([]interface{}) + if !ok { + return nil + } + values := make([]string, 0, len(items)) + for _, item := range items { + c, ok := item.(map[string]interface{}) + if !ok { + continue + } + v, _ := c["Value"].(string) + if v != "" { + values = append(values, v) + } + } + return values +} + +func traverseMicroflowNodes(startID string, outgoing map[string][]microflowFlow) []string { + visited := make(map[string]bool) + order := make([]string, 0) + var visit func(string) + visit = func(id string) { + if id == "" || visited[id] { + return + } + visited[id] = true + order = append(order, id) + for _, edge := range outgoing[id] { + visit(edge.Destination) + } + } + visit(startID) + return order +} + +func readMicroflowID(raw interface{}) string { + switch value := raw.(type) { + case string: + return value + case map[string]interface{}: + // Raw YAML form: + // $ID: + // subtype: 0 + // data: [118, 185, ...] + dataRaw, ok := value["data"] + if !ok { + return "" + } + parts, ok := dataRaw.([]interface{}) + if !ok { + return "" + } + builder := strings.Builder{} + for idx, p := range parts { + if idx > 0 { + builder.WriteByte('-') + } + builder.WriteString(intLikeToString(p)) + } + return builder.String() + default: + return "" + } +} + +func intLikeToString(v interface{}) string { + switch n := v.(type) { + case int: + return strconv.Itoa(n) + case int32: + return strconv.Itoa(int(n)) + case int64: + return strconv.FormatInt(n, 10) + case uint64: + return strconv.FormatUint(n, 10) + case float64: + return strconv.Itoa(int(n)) + case float32: + return strconv.Itoa(int(n)) + default: + return "" + } +} diff --git a/mpr/microflow_pseudocode_test.go b/mpr/microflow_pseudocode_test.go new file mode 100644 index 0000000..1935366 --- /dev/null +++ b/mpr/microflow_pseudocode_test.go @@ -0,0 +1,178 @@ +package mpr + +import ( + "strings" + "testing" +) + +func TestGenerateMicroflowPseudocode_FromSubMicroflowExample(t *testing.T) { + attrs := subMicroflowFixture() + + pseudocode, err := generateMicroflowPseudocode("Module2.SubMicroflowExample", attrs) + if err != nil { + t.Fatalf("Failed to generate pseudocode: %v", err) + } + + if !strings.Contains(pseudocode, "IF $counter > 0 THEN") { + t.Fatalf("Expected pseudocode to include split condition") + } + if !strings.Contains(pseudocode, "counter = $counter - 1") { + t.Fatalf("Expected pseudocode to include decrement action") + } +} + +func TestGenerateMicroflowPseudocode_FromLoopMicroflowExample(t *testing.T) { + attrs := loopMicroflowFixture() + + pseudocode, err := generateMicroflowPseudocode("Module2.MicroflowLoopExample", attrs) + if err != nil { + t.Fatalf("Failed to generate pseudocode: %v", err) + } + + if !strings.Contains(pseudocode, "MICROFLOW: Module2.MicroflowLoopExample") { + t.Fatalf("Expected pseudocode header with microflow name") + } + if !strings.Contains(pseudocode, "FOR EACH IteratorUser IN UserList") { + t.Fatalf("Expected pseudocode to include structured FOR EACH loop") + } + if !strings.Contains(pseudocode, "call Module2.SubMicroflowExample(User = $IteratorUser)") { + t.Fatalf("Expected pseudocode to include microflow call in loop branch") + } +} + +func subMicroflowFixture() map[string]interface{} { + return map[string]interface{}{ + "MicroflowReturnType": map[string]interface{}{"$Type": "DataTypes$VoidType"}, + "ObjectCollection": map[string]interface{}{ + "Objects": []interface{}{ + map[string]interface{}{"$ID": "start", "$Type": "Microflows$StartEvent"}, + map[string]interface{}{ + "$ID": "create", + "$Type": "Microflows$ActionActivity", + "Action": map[string]interface{}{ + "$Type": "Microflows$CreateVariableAction", + "VariableName": "counter", + "InitialValue": "10", + "ErrorHandling": "Rollback", + }, + }, + map[string]interface{}{ + "$ID": "split", + "$Type": "Microflows$ExclusiveSplit", + "SplitCondition": map[string]interface{}{ + "Expression": "$counter > 0", + }, + }, + map[string]interface{}{ + "$ID": "decrement", + "$Type": "Microflows$ActionActivity", + "Action": map[string]interface{}{ + "$Type": "Microflows$ChangeVariableAction", + "ChangeVariableName": "counter", + "Value": "$counter - 1", + }, + }, + map[string]interface{}{"$ID": "end", "$Type": "Microflows$EndEvent"}, + }, + }, + "Flows": []interface{}{ + map[string]interface{}{"$ID": "f1", "OriginPointer": "start", "DestinationPointer": "create", "CaseValues": []interface{}{}}, + map[string]interface{}{"$ID": "f2", "OriginPointer": "create", "DestinationPointer": "split", "CaseValues": []interface{}{}}, + map[string]interface{}{"$ID": "f3", "OriginPointer": "split", "DestinationPointer": "decrement", "CaseValues": []interface{}{map[string]interface{}{"Value": "true"}}}, + map[string]interface{}{"$ID": "f4", "OriginPointer": "split", "DestinationPointer": "end", "CaseValues": []interface{}{map[string]interface{}{"Value": "false"}}}, + map[string]interface{}{"$ID": "f5", "OriginPointer": "decrement", "DestinationPointer": "split", "CaseValues": []interface{}{}}, + }, + } +} + +func loopMicroflowFixture() map[string]interface{} { + return map[string]interface{}{ + "MicroflowReturnType": map[string]interface{}{"$Type": "DataTypes$VoidType"}, + "ObjectCollection": map[string]interface{}{ + "Objects": []interface{}{ + map[string]interface{}{"$ID": "start", "$Type": "Microflows$StartEvent"}, + map[string]interface{}{ + "$ID": "retrieve", + "$Type": "Microflows$ActionActivity", + "Action": map[string]interface{}{ + "$Type": "Microflows$RetrieveAction", + "ResultVariableName": "UserList", + "RetrieveSource": map[string]interface{}{ + "Entity": "System.User", + }, + }, + }, + map[string]interface{}{ + "$ID": "loop", + "$Type": "Microflows$LoopedActivity", + "LoopSource": map[string]interface{}{ + "ListVariableName": "UserList", + "VariableName": "IteratorUser", + }, + "ObjectCollection": map[string]interface{}{ + "Objects": []interface{}{ + map[string]interface{}{ + "$ID": "loopSplit", + "$Type": "Microflows$ExclusiveSplit", + "SplitCondition": map[string]interface{}{ + "Expression": "$IteratorUser/Blocked", + }, + }, + map[string]interface{}{ + "$ID": "loopChange", + "$Type": "Microflows$ActionActivity", + "Action": map[string]interface{}{ + "$Type": "Microflows$ChangeAction", + "ChangeVariableName": "IteratorUser", + "Commit": "Yes", + "Items": []interface{}{ + map[string]interface{}{ + "$Type": "Microflows$ChangeActionItem", + "Attribute": "System.User.Blocked", + "Value": "false", + }, + }, + }, + }, + map[string]interface{}{ + "$ID": "loopCall", + "$Type": "Microflows$ActionActivity", + "Action": map[string]interface{}{ + "$Type": "Microflows$MicroflowCallAction", + "MicroflowCall": map[string]interface{}{ + "Microflow": "Module2.SubMicroflowExample", + "ParameterMappings": []interface{}{ + map[string]interface{}{ + "Parameter": "Module2.SubMicroflowExample.User", + "Argument": "$IteratorUser", + }, + }, + }, + }, + }, + map[string]interface{}{ + "$ID": "loopLog", + "$Type": "Microflows$ActionActivity", + "Action": map[string]interface{}{ + "$Type": "Microflows$LogMessageAction", + "MessageTemplate": map[string]interface{}{ + "Text": "User {1} not blocked", + }, + }, + }, + }, + }, + }, + map[string]interface{}{"$ID": "end", "$Type": "Microflows$EndEvent"}, + }, + }, + "Flows": []interface{}{ + map[string]interface{}{"$ID": "f1", "OriginPointer": "start", "DestinationPointer": "retrieve", "CaseValues": []interface{}{}}, + map[string]interface{}{"$ID": "f2", "OriginPointer": "retrieve", "DestinationPointer": "loop", "CaseValues": []interface{}{}}, + map[string]interface{}{"$ID": "f3", "OriginPointer": "loop", "DestinationPointer": "end", "CaseValues": []interface{}{}}, + map[string]interface{}{"$ID": "f4", "OriginPointer": "loopSplit", "DestinationPointer": "loopChange", "CaseValues": []interface{}{map[string]interface{}{"Value": "true"}}}, + map[string]interface{}{"$ID": "f5", "OriginPointer": "loopSplit", "DestinationPointer": "loopLog", "CaseValues": []interface{}{map[string]interface{}{"Value": "false"}}}, + map[string]interface{}{"$ID": "f6", "OriginPointer": "loopChange", "DestinationPointer": "loopCall", "CaseValues": []interface{}{}}, + }, + } +} diff --git a/mpr/microflow_test.go b/mpr/microflow_test.go index b1272f9..27e2245 100644 --- a/mpr/microflow_test.go +++ b/mpr/microflow_test.go @@ -3,6 +3,7 @@ package mpr import ( "os" + "strings" "testing" "go.mongodb.org/mongo-driver/bson" @@ -13,7 +14,7 @@ import ( func TestMPRMicroflow(t *testing.T) { t.Run("microflow-simple", func(t *testing.T) { - if _, err := exportUnits("./../resources/app-mpr-v1/App.mpr", "./../tmp", true, "advanced", ""); err != nil { + if _, err := exportUnits("./../resources/app-mpr-v1/App.mpr", "./../tmp", true, ""); err != nil { t.Errorf("Failed to export units from MPR file") } @@ -40,9 +41,43 @@ func TestMPRMicroflow(t *testing.T) { if len(sequence) != 5 { t.Errorf("Unexpected instructions length. Got: %d", len(sequence)) } + + pseudocode, ok := mfObj["pseudocode"].(string) + if !ok || pseudocode == "" { + t.Errorf("Expected pseudocode to be a non-empty string") + } + if ok && pseudocode != "" { + if !containsText(pseudocode, "BEGIN") || !containsText(pseudocode, "END") { + t.Errorf("Expected pseudocode to contain BEGIN/END structure") + } + } + }) + t.Run("microflow-simple-has-pseudocode", func(t *testing.T) { + if _, err := exportUnits("./../resources/app-mpr-v1/App.mpr", "./../tmp", true, "MicroflowSimple"); err != nil { + t.Errorf("Failed to export units from MPR file") + } + + mfFile, err := os.ReadFile("./../tmp/MyFirstModule/Folder/MicroflowSimple.Microflows$Microflow.yaml") + if err != nil { + t.Errorf("Failed to read file: %v", err) + } + + var mfObj bson.M + var node yaml.Node + if err := yaml.Unmarshal(mfFile, &node); err != nil { + t.Errorf("Failed to unmarshal microflow file: %v", err) + } + if err := node.Decode(&mfObj); err != nil { + t.Errorf("Failed to decode microflow file: %v", err) + } + + pseudocode, ok := mfObj["pseudocode"].(string) + if !ok || pseudocode == "" { + t.Errorf("Expected pseudocode to be present in export") + } }) t.Run("microflow-with-split", func(t *testing.T) { - if _, err := exportUnits("./../resources/app-mpr-v1/App.mpr", "./../tmp", true, "advanced", ""); err != nil { + if _, err := exportUnits("./../resources/app-mpr-v1/App.mpr", "./../tmp", true, ""); err != nil { t.Errorf("Failed to export units from MPR file") } @@ -71,7 +106,7 @@ func TestMPRMicroflow(t *testing.T) { } }) t.Run("microflow-split-then-merge", func(t *testing.T) { - if _, err := exportUnits("./../resources/app-mpr-v1/App.mpr", "./../tmp", true, "advanced", ""); err != nil { + if _, err := exportUnits("./../resources/app-mpr-v1/App.mpr", "./../tmp", true, ""); err != nil { t.Errorf("Failed to export units from MPR file") } @@ -133,3 +168,7 @@ func TestMPRMicroflow(t *testing.T) { } }) } + +func containsText(s string, needle string) bool { + return strings.Contains(strings.ToUpper(s), strings.ToUpper(needle)) +} diff --git a/mpr/mpr.go b/mpr/mpr.go index 93792d1..c95b83a 100644 --- a/mpr/mpr.go +++ b/mpr/mpr.go @@ -12,6 +12,7 @@ import ( "strings" "gopkg.in/yaml.v3" + "go.mongodb.org/mongo-driver/bson" _ "github.com/glebarez/go-sqlite" ) @@ -31,7 +32,7 @@ const ( MaxComponentLength = 50 ) -func ExportModel(inputDirectory string, outputDirectory string, raw bool, mode string, appstore bool, filter string) error { +func ExportModel(inputDirectory string, outputDirectory string, raw bool, appstore bool, filter string) error { // create tmp directory in user tmp directory tmpDir := filepath.Join(os.TempDir(), "mxlint") @@ -67,7 +68,7 @@ func ExportModel(inputDirectory string, outputDirectory string, raw bool, mode s exportedCount := 0 if filter != "^Metadata$" { var err error - exportedCount, err = exportUnits(inputDirectory, tmpDir, raw, mode, filter) + exportedCount, err = exportUnits(inputDirectory, tmpDir, raw, filter) if err != nil { return fmt.Errorf("error exporting units: %v", err) } @@ -456,7 +457,7 @@ func validatePathLength(basePath string, relativePath string, filename string) ( return newRelativePath, filename, nil } -func getMxDocuments(units []MxUnit, folders []MxFolder, mode string) ([]MxDocument, error) { +func getMxDocuments(units []MxUnit, folders []MxFolder) ([]MxDocument, error) { var documents []MxDocument documentTypes := []string{"ProjectDocuments", "DomainModel", "ModuleSettings", "ModuleSecurity", "Documents"} @@ -475,8 +476,8 @@ func getMxDocuments(units []MxUnit, folders []MxFolder, mode string) ([]MxDocume Attributes: unit.Contents, } - if mode == "advanced" && unit.Contents["$Type"] == "Microflows$Microflow" { - myDocument = transformMicroflow(myDocument) + if unit.Contents["$Type"] == microflowDocumentType { + myDocument = enrichMicroflowDocument(myDocument) } documents = append(documents, myDocument) } @@ -485,7 +486,7 @@ func getMxDocuments(units []MxUnit, folders []MxFolder, mode string) ([]MxDocume return documents, nil } -func exportUnits(inputDirectory string, outputDirectory string, raw bool, mode string, filter string) (int, error) { +func exportUnits(inputDirectory string, outputDirectory string, raw bool, filter string) (int, error) { log.Debugf("Exporting units from %s to %s", inputDirectory, outputDirectory) units, err := getMxUnits(inputDirectory) @@ -497,7 +498,7 @@ func exportUnits(inputDirectory string, outputDirectory string, raw bool, mode s if err != nil { return 0, fmt.Errorf("error getting folders: %v", err) } - documents, err := getMxDocuments(units, folders, mode) + documents, err := getMxDocuments(units, folders) if err != nil { return 0, fmt.Errorf("error getting documents: %v", err) } @@ -574,7 +575,8 @@ func exportUnits(inputDirectory string, outputDirectory string, raw bool, mode s func writeFile(filepath string, contents map[string]interface{}) error { log.Debugf("Writing file %s", filepath) - yamlstring, err := yaml.Marshal(contents) + normalizedContents := normalizeMultilineValues(contents) + yamlstring, err := yaml.Marshal(normalizedContents) if err != nil { return fmt.Errorf("error marshaling: %v", err) } @@ -585,6 +587,137 @@ func writeFile(filepath string, contents map[string]interface{}) error { return nil } +type doubleQuotedMultilineString string + +func (s doubleQuotedMultilineString) MarshalYAML() (interface{}, error) { + return &yaml.Node{ + Kind: yaml.ScalarNode, + Tag: "!!str", + Value: string(s), + Style: yaml.DoubleQuotedStyle, + }, nil +} + +type literalBlockMultilineString string + +func (s literalBlockMultilineString) MarshalYAML() (interface{}, error) { + return &yaml.Node{ + Kind: yaml.ScalarNode, + Tag: "!!str", + Value: string(s), + Style: yaml.LiteralStyle, + }, nil +} + +// normalizeMultilineValues normalizes indentation in multiline string values recursively +// and forces multiline strings to be encoded as double-quoted scalars. +func normalizeMultilineValues(v interface{}) interface{} { + switch value := v.(type) { + case bson.M: + result := make(bson.M, len(value)) + for k, item := range value { + result[k] = normalizeMultilineValues(item) + } + return result + case map[string]interface{}: + result := make(map[string]interface{}, len(value)) + for k, item := range value { + result[k] = normalizeMultilineValues(item) + } + return result + case []bson.M: + result := make([]bson.M, len(value)) + for i, item := range value { + normalized := normalizeMultilineValues(item) + if itemMap, ok := normalized.(bson.M); ok { + result[i] = itemMap + } else { + result[i] = item + } + } + return result + case []map[string]interface{}: + result := make([]map[string]interface{}, len(value)) + for i, item := range value { + normalized := normalizeMultilineValues(item) + if itemMap, ok := normalized.(map[string]interface{}); ok { + result[i] = itemMap + } else { + result[i] = item + } + } + return result + case []interface{}: + result := make([]interface{}, len(value)) + for i, item := range value { + result[i] = normalizeMultilineValues(item) + } + return result + case string: + normalized := normalizeMultilineString(value) + if strings.Contains(normalized, "\n") { + if startsWithWhitespace(normalized) { + return doubleQuotedMultilineString(normalized) + } + return literalBlockMultilineString(normalized) + } + return normalized + default: + return v + } +} + +func startsWithWhitespace(value string) bool { + if value == "" { + return false + } + first := value[0] + return first == ' ' || first == '\t' +} + +func normalizeMultilineString(value string) string { + if !strings.Contains(value, "\n") { + return value + } + + lines := strings.Split(value, "\n") + minIndent := -1 + for _, line := range lines { + if strings.TrimSpace(line) == "" { + continue + } + indent := countLeadingWhitespace(line) + if minIndent == -1 || indent < minIndent { + minIndent = indent + } + } + + if minIndent <= 0 { + return value + } + + for i, line := range lines { + if strings.TrimSpace(line) == "" { + continue + } + lines[i] = line[minIndent:] + } + + return strings.Join(lines, "\n") +} + +func countLeadingWhitespace(line string) int { + count := 0 + for _, r := range line { + if r == ' ' || r == '\t' { + count++ + continue + } + break + } + return count +} + func getMxUnits(inputDirectory string) ([]MxUnit, error) { mprPath, err := getMprPath(inputDirectory) if err != nil { diff --git a/mpr/mpr_test.go b/mpr/mpr_test.go index bca9930..083ab5e 100644 --- a/mpr/mpr_test.go +++ b/mpr/mpr_test.go @@ -7,6 +7,7 @@ import ( "testing" "gopkg.in/yaml.v3" + "go.mongodb.org/mongo-driver/bson" ) func TestGetMprVersion(t *testing.T) { @@ -506,6 +507,35 @@ func TestWriteFile(t *testing.T) { }, expectError: true, }, + { + name: "write multiline value with inconsistent indentation", + filepath: filepath.Join(tmpDir, "multiline.yaml"), + contents: map[string]interface{}{ + "Name": "TestDocument", + "Value": " if $x = 1 then empty\nelse if $x = 2 then true\n else false", + }, + expectError: false, + }, + { + name: "write multiline value without leading whitespace", + filepath: filepath.Join(tmpDir, "multiline_literal.yaml"), + contents: map[string]interface{}{ + "Name": "TestDocument", + "Value": "if $x = 1 then true\nelse false", + }, + expectError: false, + }, + { + name: "write nested bson multiline value with inconsistent indentation", + filepath: filepath.Join(tmpDir, "multiline_nested_bson.yaml"), + contents: map[string]interface{}{ + "Name": "TestDocument", + "Nested": bson.M{ + "Value": " if $x = 1 then empty\nelse if $x = 2 then true\n else false", + }, + }, + expectError: false, + }, } for _, tt := range tests { @@ -530,6 +560,12 @@ func TestWriteFile(t *testing.T) { if data["Name"] != tt.contents["Name"] { t.Errorf("Written file content mismatch") } + if (tt.name == "write multiline value with inconsistent indentation" || tt.name == "write nested bson multiline value with inconsistent indentation") && strings.Contains(string(content), "|") { + t.Errorf("Expected multiline value to be double-quoted, but found block scalar style in: %s", string(content)) + } + if tt.name == "write multiline value without leading whitespace" && !strings.Contains(string(content), "|\n") && !strings.Contains(string(content), "|-\n") { + t.Errorf("Expected multiline value to use literal block scalar style, got: %s", string(content)) + } } } }) @@ -698,28 +734,19 @@ func TestGetMxDocuments(t *testing.T) { name string units []MxUnit folders []MxFolder - mode string expectedDocs int }{ { - name: "basic mode", - units: units, - folders: folders, - mode: "basic", - expectedDocs: 2, - }, - { - name: "advanced mode", + name: "documents extracted", units: units, folders: folders, - mode: "advanced", expectedDocs: 2, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - documents, err := getMxDocuments(tt.units, tt.folders, tt.mode) + documents, err := getMxDocuments(tt.units, tt.folders) if err != nil { t.Errorf("getMxDocuments() unexpected error: %v", err) } diff --git a/mpr/mpr_v1_test.go b/mpr/mpr_v1_test.go index dbf5d72..77522ba 100644 --- a/mpr/mpr_v1_test.go +++ b/mpr/mpr_v1_test.go @@ -42,7 +42,7 @@ func TestMPRMetadata(t *testing.T) { func TestMPRUnits(t *testing.T) { t.Run("single-mpr", func(t *testing.T) { - if _, err := exportUnits("./../resources/app-mpr-v1", "./../tmp", false, "basic", ""); err != nil { + if _, err := exportUnits("./../resources/app-mpr-v1", "./../tmp", false, ""); err != nil { t.Errorf("Failed to export units from MPR file") } }) @@ -51,7 +51,7 @@ func TestMPRUnits(t *testing.T) { func TestIDAttributesExclusion(t *testing.T) { t.Run("verify-id-attributes-excluded", func(t *testing.T) { // Export units with ID attributes excluded - if _, err := exportUnits("./../resources/app-mpr-v1", "./../tmp", false, "basic", ""); err != nil { + if _, err := exportUnits("./../resources/app-mpr-v1", "./../tmp", false, ""); err != nil { t.Errorf("Failed to export units from MPR file: %v", err) return } @@ -108,7 +108,7 @@ func TestFilterMetadataOnly(t *testing.T) { // Export with filter ^Metadata$ // According to the code, when filter is "^Metadata$", only metadata is exported, no units - if err := ExportModel("./../resources/app-mpr-v1", testDir, false, "basic", false, "^Metadata$"); err != nil { + if err := ExportModel("./../resources/app-mpr-v1", testDir, false, false, "^Metadata$"); err != nil { t.Errorf("Failed to export with Metadata filter: %v", err) return } @@ -148,7 +148,7 @@ func TestFilterConstantPattern(t *testing.T) { // Export with filter ^Constant.* // This pattern won't match any documents in the test data, so we should get only metadata - if err := ExportModel("./../resources/app-mpr-v1", testDir, false, "basic", false, "^Constant.*"); err != nil { + if err := ExportModel("./../resources/app-mpr-v1", testDir, false, false, "^Constant.*"); err != nil { t.Errorf("Failed to export with Constant filter: %v", err) return } diff --git a/mpr/mpr_v2_test.go b/mpr/mpr_v2_test.go index 9df1694..8330b44 100644 --- a/mpr/mpr_v2_test.go +++ b/mpr/mpr_v2_test.go @@ -30,7 +30,7 @@ func TestMPRV2Metadata(t *testing.T) { t.Errorf("Failed to decode metadata file: %v", err) } // check metadata - expectedProductVersion := "10.18.3.58900" + expectedProductVersion := "10.24.9.81004" if metadataObj.ProductVersion != expectedProductVersion { t.Errorf("ProductVersion is incorrect. Expected: %s, Got: %s", expectedProductVersion, metadataObj.ProductVersion) } @@ -39,7 +39,7 @@ func TestMPRV2Metadata(t *testing.T) { func TestMPRV2Units(t *testing.T) { t.Run("single-mpr", func(t *testing.T) { - if _, err := exportUnits("./../resources/app-mpr-v2", "./../tmp", false, "basic", ""); err != nil { + if _, err := exportUnits("./../resources/app-mpr-v2", "./../tmp", false, ""); err != nil { t.Errorf("Failed to export units from MPR file") } }) diff --git a/resources/app-mpr-v2/App.mpr b/resources/app-mpr-v2/App.mpr index f8b3fbf..3e8e695 100644 Binary files a/resources/app-mpr-v2/App.mpr and b/resources/app-mpr-v2/App.mpr differ diff --git a/resources/app-mpr-v2/mprcontents/00/e5/00e50513-3a40-4bd1-b2cf-3c1563722e9d.mxunit b/resources/app-mpr-v2/mprcontents/00/e5/00e50513-3a40-4bd1-b2cf-3c1563722e9d.mxunit index 7c4637a..07ea99f 100644 Binary files a/resources/app-mpr-v2/mprcontents/00/e5/00e50513-3a40-4bd1-b2cf-3c1563722e9d.mxunit and b/resources/app-mpr-v2/mprcontents/00/e5/00e50513-3a40-4bd1-b2cf-3c1563722e9d.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/06/f0/06f03012-be22-47ba-81f5-0fc44294d7a0.mxunit b/resources/app-mpr-v2/mprcontents/06/f0/06f03012-be22-47ba-81f5-0fc44294d7a0.mxunit index 73a70cb..c59e101 100644 Binary files a/resources/app-mpr-v2/mprcontents/06/f0/06f03012-be22-47ba-81f5-0fc44294d7a0.mxunit and b/resources/app-mpr-v2/mprcontents/06/f0/06f03012-be22-47ba-81f5-0fc44294d7a0.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/09/43/0943827a-0b44-45a8-9645-a670b9551756.mxunit b/resources/app-mpr-v2/mprcontents/09/43/0943827a-0b44-45a8-9645-a670b9551756.mxunit new file mode 100644 index 0000000..7790c4e Binary files /dev/null and b/resources/app-mpr-v2/mprcontents/09/43/0943827a-0b44-45a8-9645-a670b9551756.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/0a/37/0a3770fe-0cc5-417c-92fe-cf90587f1b38.mxunit b/resources/app-mpr-v2/mprcontents/0a/37/0a3770fe-0cc5-417c-92fe-cf90587f1b38.mxunit index df92b29..143291c 100644 Binary files a/resources/app-mpr-v2/mprcontents/0a/37/0a3770fe-0cc5-417c-92fe-cf90587f1b38.mxunit and b/resources/app-mpr-v2/mprcontents/0a/37/0a3770fe-0cc5-417c-92fe-cf90587f1b38.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/0a/91/0a91b0c1-3df9-4399-aca1-12f1adb5e963.mxunit b/resources/app-mpr-v2/mprcontents/0a/91/0a91b0c1-3df9-4399-aca1-12f1adb5e963.mxunit index 3c8a6a9..3e90109 100644 Binary files a/resources/app-mpr-v2/mprcontents/0a/91/0a91b0c1-3df9-4399-aca1-12f1adb5e963.mxunit and b/resources/app-mpr-v2/mprcontents/0a/91/0a91b0c1-3df9-4399-aca1-12f1adb5e963.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/0a/ee/0aee4fa4-51c1-47f3-b195-ba6151fbb73d.mxunit b/resources/app-mpr-v2/mprcontents/0a/ee/0aee4fa4-51c1-47f3-b195-ba6151fbb73d.mxunit index d3c22fe..c41db99 100644 Binary files a/resources/app-mpr-v2/mprcontents/0a/ee/0aee4fa4-51c1-47f3-b195-ba6151fbb73d.mxunit and b/resources/app-mpr-v2/mprcontents/0a/ee/0aee4fa4-51c1-47f3-b195-ba6151fbb73d.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/0b/a6/0ba6f231-adce-4443-8fd4-b431d22f647c.mxunit b/resources/app-mpr-v2/mprcontents/0b/a6/0ba6f231-adce-4443-8fd4-b431d22f647c.mxunit index c0bd432..452c818 100644 Binary files a/resources/app-mpr-v2/mprcontents/0b/a6/0ba6f231-adce-4443-8fd4-b431d22f647c.mxunit and b/resources/app-mpr-v2/mprcontents/0b/a6/0ba6f231-adce-4443-8fd4-b431d22f647c.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/0e/99/0e995f2a-a400-4ab0-bc1f-167731a10a61.mxunit b/resources/app-mpr-v2/mprcontents/0e/99/0e995f2a-a400-4ab0-bc1f-167731a10a61.mxunit index b9e5107..ac5d625 100644 Binary files a/resources/app-mpr-v2/mprcontents/0e/99/0e995f2a-a400-4ab0-bc1f-167731a10a61.mxunit and b/resources/app-mpr-v2/mprcontents/0e/99/0e995f2a-a400-4ab0-bc1f-167731a10a61.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/0f/32/0f32c00a-952c-4a44-81cf-505b9d436375.mxunit b/resources/app-mpr-v2/mprcontents/0f/32/0f32c00a-952c-4a44-81cf-505b9d436375.mxunit index 3bb7669..8de9866 100644 Binary files a/resources/app-mpr-v2/mprcontents/0f/32/0f32c00a-952c-4a44-81cf-505b9d436375.mxunit and b/resources/app-mpr-v2/mprcontents/0f/32/0f32c00a-952c-4a44-81cf-505b9d436375.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/15/41/15410ae4-f250-4aea-a636-62936e994a10.mxunit b/resources/app-mpr-v2/mprcontents/15/41/15410ae4-f250-4aea-a636-62936e994a10.mxunit index e0365b1..f9aa5fb 100644 Binary files a/resources/app-mpr-v2/mprcontents/15/41/15410ae4-f250-4aea-a636-62936e994a10.mxunit and b/resources/app-mpr-v2/mprcontents/15/41/15410ae4-f250-4aea-a636-62936e994a10.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/1b/5d/1b5d4ff9-647a-485f-abdc-7359ebbec551.mxunit b/resources/app-mpr-v2/mprcontents/1b/5d/1b5d4ff9-647a-485f-abdc-7359ebbec551.mxunit index 3439664..a7212a7 100644 Binary files a/resources/app-mpr-v2/mprcontents/1b/5d/1b5d4ff9-647a-485f-abdc-7359ebbec551.mxunit and b/resources/app-mpr-v2/mprcontents/1b/5d/1b5d4ff9-647a-485f-abdc-7359ebbec551.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/1f/cc/1fcc2823-c303-5a27-b6c7-78b04c96c88f.mxunit b/resources/app-mpr-v2/mprcontents/1f/cc/1fcc2823-c303-5a27-b6c7-78b04c96c88f.mxunit index 576b166..5828260 100644 Binary files a/resources/app-mpr-v2/mprcontents/1f/cc/1fcc2823-c303-5a27-b6c7-78b04c96c88f.mxunit and b/resources/app-mpr-v2/mprcontents/1f/cc/1fcc2823-c303-5a27-b6c7-78b04c96c88f.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/20/a0/20a09e3c-3a8c-413e-93c9-60206eff3f01.mxunit b/resources/app-mpr-v2/mprcontents/20/a0/20a09e3c-3a8c-413e-93c9-60206eff3f01.mxunit index 0c215b4..72ba43a 100644 Binary files a/resources/app-mpr-v2/mprcontents/20/a0/20a09e3c-3a8c-413e-93c9-60206eff3f01.mxunit and b/resources/app-mpr-v2/mprcontents/20/a0/20a09e3c-3a8c-413e-93c9-60206eff3f01.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/26/ef/26ef1b19-2fb9-4278-9919-0e398f186933.mxunit b/resources/app-mpr-v2/mprcontents/26/ef/26ef1b19-2fb9-4278-9919-0e398f186933.mxunit index d7c3070..2384975 100644 Binary files a/resources/app-mpr-v2/mprcontents/26/ef/26ef1b19-2fb9-4278-9919-0e398f186933.mxunit and b/resources/app-mpr-v2/mprcontents/26/ef/26ef1b19-2fb9-4278-9919-0e398f186933.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/2d/9e/2d9e3587-482e-4769-8deb-3ff53b764e85.mxunit b/resources/app-mpr-v2/mprcontents/2d/9e/2d9e3587-482e-4769-8deb-3ff53b764e85.mxunit index 029ecec..6b18105 100644 Binary files a/resources/app-mpr-v2/mprcontents/2d/9e/2d9e3587-482e-4769-8deb-3ff53b764e85.mxunit and b/resources/app-mpr-v2/mprcontents/2d/9e/2d9e3587-482e-4769-8deb-3ff53b764e85.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/3e/e3/3ee3cfb5-98d0-4398-bb0a-3592ce5f16ae.mxunit b/resources/app-mpr-v2/mprcontents/3e/e3/3ee3cfb5-98d0-4398-bb0a-3592ce5f16ae.mxunit index 46ee7a4..53a3923 100644 Binary files a/resources/app-mpr-v2/mprcontents/3e/e3/3ee3cfb5-98d0-4398-bb0a-3592ce5f16ae.mxunit and b/resources/app-mpr-v2/mprcontents/3e/e3/3ee3cfb5-98d0-4398-bb0a-3592ce5f16ae.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/3f/64/3f64baa2-b85c-4999-9a3c-3cc38382eb54.mxunit b/resources/app-mpr-v2/mprcontents/3f/64/3f64baa2-b85c-4999-9a3c-3cc38382eb54.mxunit index 2cd01e6..7901692 100644 Binary files a/resources/app-mpr-v2/mprcontents/3f/64/3f64baa2-b85c-4999-9a3c-3cc38382eb54.mxunit and b/resources/app-mpr-v2/mprcontents/3f/64/3f64baa2-b85c-4999-9a3c-3cc38382eb54.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/40/7e/407eef73-fda4-42f0-b68c-58dbfa9fc1b3.mxunit b/resources/app-mpr-v2/mprcontents/40/7e/407eef73-fda4-42f0-b68c-58dbfa9fc1b3.mxunit index 03b2750..e8e6e76 100644 Binary files a/resources/app-mpr-v2/mprcontents/40/7e/407eef73-fda4-42f0-b68c-58dbfa9fc1b3.mxunit and b/resources/app-mpr-v2/mprcontents/40/7e/407eef73-fda4-42f0-b68c-58dbfa9fc1b3.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/42/38/423862f6-8095-469c-baf9-a0200128add3.mxunit b/resources/app-mpr-v2/mprcontents/42/38/423862f6-8095-469c-baf9-a0200128add3.mxunit index 230c17a..fbaf9dd 100644 Binary files a/resources/app-mpr-v2/mprcontents/42/38/423862f6-8095-469c-baf9-a0200128add3.mxunit and b/resources/app-mpr-v2/mprcontents/42/38/423862f6-8095-469c-baf9-a0200128add3.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/44/bd/44bd5553-6fbf-4773-8497-2f46d522ac88.mxunit b/resources/app-mpr-v2/mprcontents/44/bd/44bd5553-6fbf-4773-8497-2f46d522ac88.mxunit index 76ad094..ed5786f 100644 Binary files a/resources/app-mpr-v2/mprcontents/44/bd/44bd5553-6fbf-4773-8497-2f46d522ac88.mxunit and b/resources/app-mpr-v2/mprcontents/44/bd/44bd5553-6fbf-4773-8497-2f46d522ac88.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/49/c9/49c990a0-36b5-4ea6-a3ef-37b615c601b2.mxunit b/resources/app-mpr-v2/mprcontents/49/c9/49c990a0-36b5-4ea6-a3ef-37b615c601b2.mxunit index 761a1de..199e0db 100644 Binary files a/resources/app-mpr-v2/mprcontents/49/c9/49c990a0-36b5-4ea6-a3ef-37b615c601b2.mxunit and b/resources/app-mpr-v2/mprcontents/49/c9/49c990a0-36b5-4ea6-a3ef-37b615c601b2.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/4e/70/4e70063d-53e1-477a-ab92-6b763330c293.mxunit b/resources/app-mpr-v2/mprcontents/4e/70/4e70063d-53e1-477a-ab92-6b763330c293.mxunit index 2431804..0014b24 100644 Binary files a/resources/app-mpr-v2/mprcontents/4e/70/4e70063d-53e1-477a-ab92-6b763330c293.mxunit and b/resources/app-mpr-v2/mprcontents/4e/70/4e70063d-53e1-477a-ab92-6b763330c293.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/4f/b9/4fb9fc5d-7c51-4ee5-aef1-a98088851edf.mxunit b/resources/app-mpr-v2/mprcontents/4f/b9/4fb9fc5d-7c51-4ee5-aef1-a98088851edf.mxunit index 33e0a4a..d006774 100644 Binary files a/resources/app-mpr-v2/mprcontents/4f/b9/4fb9fc5d-7c51-4ee5-aef1-a98088851edf.mxunit and b/resources/app-mpr-v2/mprcontents/4f/b9/4fb9fc5d-7c51-4ee5-aef1-a98088851edf.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/52/c9/52c9db65-0531-4243-ac03-519a85dd9b01.mxunit b/resources/app-mpr-v2/mprcontents/52/c9/52c9db65-0531-4243-ac03-519a85dd9b01.mxunit index 43765f9..78170d1 100644 Binary files a/resources/app-mpr-v2/mprcontents/52/c9/52c9db65-0531-4243-ac03-519a85dd9b01.mxunit and b/resources/app-mpr-v2/mprcontents/52/c9/52c9db65-0531-4243-ac03-519a85dd9b01.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/56/06/56064c85-dd6c-4e4d-814d-a23b82347404.mxunit b/resources/app-mpr-v2/mprcontents/56/06/56064c85-dd6c-4e4d-814d-a23b82347404.mxunit index fa8d69d..6402904 100644 Binary files a/resources/app-mpr-v2/mprcontents/56/06/56064c85-dd6c-4e4d-814d-a23b82347404.mxunit and b/resources/app-mpr-v2/mprcontents/56/06/56064c85-dd6c-4e4d-814d-a23b82347404.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/56/b0/56b0a1fa-758b-4f22-8a47-6cce47ca15f7.mxunit b/resources/app-mpr-v2/mprcontents/56/b0/56b0a1fa-758b-4f22-8a47-6cce47ca15f7.mxunit index 84402aa..4f20988 100644 Binary files a/resources/app-mpr-v2/mprcontents/56/b0/56b0a1fa-758b-4f22-8a47-6cce47ca15f7.mxunit and b/resources/app-mpr-v2/mprcontents/56/b0/56b0a1fa-758b-4f22-8a47-6cce47ca15f7.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/57/d2/57d2ecb5-6c2f-4ffa-a0b3-a37a40da3adf.mxunit b/resources/app-mpr-v2/mprcontents/57/d2/57d2ecb5-6c2f-4ffa-a0b3-a37a40da3adf.mxunit index c6460f6..fc5ebe8 100644 Binary files a/resources/app-mpr-v2/mprcontents/57/d2/57d2ecb5-6c2f-4ffa-a0b3-a37a40da3adf.mxunit and b/resources/app-mpr-v2/mprcontents/57/d2/57d2ecb5-6c2f-4ffa-a0b3-a37a40da3adf.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/5a/55/5a55ffd3-b3b8-4472-83db-fa8e19bd6338.mxunit b/resources/app-mpr-v2/mprcontents/5a/55/5a55ffd3-b3b8-4472-83db-fa8e19bd6338.mxunit index 68924b0..e23e8f3 100644 Binary files a/resources/app-mpr-v2/mprcontents/5a/55/5a55ffd3-b3b8-4472-83db-fa8e19bd6338.mxunit and b/resources/app-mpr-v2/mprcontents/5a/55/5a55ffd3-b3b8-4472-83db-fa8e19bd6338.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/5d/87/5d877940-5c86-4f48-bfce-5787e60765da.mxunit b/resources/app-mpr-v2/mprcontents/5d/87/5d877940-5c86-4f48-bfce-5787e60765da.mxunit index 659b535..87dedee 100644 Binary files a/resources/app-mpr-v2/mprcontents/5d/87/5d877940-5c86-4f48-bfce-5787e60765da.mxunit and b/resources/app-mpr-v2/mprcontents/5d/87/5d877940-5c86-4f48-bfce-5787e60765da.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/62/19/621936b8-f6cd-4d71-b848-057cfef3b523.mxunit b/resources/app-mpr-v2/mprcontents/62/19/621936b8-f6cd-4d71-b848-057cfef3b523.mxunit index cf55230..7feaa5b 100644 Binary files a/resources/app-mpr-v2/mprcontents/62/19/621936b8-f6cd-4d71-b848-057cfef3b523.mxunit and b/resources/app-mpr-v2/mprcontents/62/19/621936b8-f6cd-4d71-b848-057cfef3b523.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/67/c5/67c57ef8-f92f-41ef-94f0-b66247ae1940.mxunit b/resources/app-mpr-v2/mprcontents/67/c5/67c57ef8-f92f-41ef-94f0-b66247ae1940.mxunit index f2b2ff2..5415ff6 100644 Binary files a/resources/app-mpr-v2/mprcontents/67/c5/67c57ef8-f92f-41ef-94f0-b66247ae1940.mxunit and b/resources/app-mpr-v2/mprcontents/67/c5/67c57ef8-f92f-41ef-94f0-b66247ae1940.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/69/59/6959cb97-4144-490f-b1e8-b842cb549e3c.mxunit b/resources/app-mpr-v2/mprcontents/69/59/6959cb97-4144-490f-b1e8-b842cb549e3c.mxunit index 70ae2b6..520451e 100644 Binary files a/resources/app-mpr-v2/mprcontents/69/59/6959cb97-4144-490f-b1e8-b842cb549e3c.mxunit and b/resources/app-mpr-v2/mprcontents/69/59/6959cb97-4144-490f-b1e8-b842cb549e3c.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/6e/cb/6ecbc452-2e68-4960-bc33-6101c4b7e664.mxunit b/resources/app-mpr-v2/mprcontents/6e/cb/6ecbc452-2e68-4960-bc33-6101c4b7e664.mxunit index 085ef8d..fca7d77 100644 Binary files a/resources/app-mpr-v2/mprcontents/6e/cb/6ecbc452-2e68-4960-bc33-6101c4b7e664.mxunit and b/resources/app-mpr-v2/mprcontents/6e/cb/6ecbc452-2e68-4960-bc33-6101c4b7e664.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/70/7b/707be533-3777-4eef-aac8-5444e930622c.mxunit b/resources/app-mpr-v2/mprcontents/70/7b/707be533-3777-4eef-aac8-5444e930622c.mxunit index 1f3cf9e..f7bf944 100644 Binary files a/resources/app-mpr-v2/mprcontents/70/7b/707be533-3777-4eef-aac8-5444e930622c.mxunit and b/resources/app-mpr-v2/mprcontents/70/7b/707be533-3777-4eef-aac8-5444e930622c.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/71/8f/718ffa1f-9f55-47b2-83d8-8ce903088969.mxunit b/resources/app-mpr-v2/mprcontents/71/8f/718ffa1f-9f55-47b2-83d8-8ce903088969.mxunit index 2aee108..e713bfc 100644 Binary files a/resources/app-mpr-v2/mprcontents/71/8f/718ffa1f-9f55-47b2-83d8-8ce903088969.mxunit and b/resources/app-mpr-v2/mprcontents/71/8f/718ffa1f-9f55-47b2-83d8-8ce903088969.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/74/0e/740ed2ec-6238-4622-8c62-3b4e8f39cb44.mxunit b/resources/app-mpr-v2/mprcontents/74/0e/740ed2ec-6238-4622-8c62-3b4e8f39cb44.mxunit index dffc57e..9edd66f 100644 Binary files a/resources/app-mpr-v2/mprcontents/74/0e/740ed2ec-6238-4622-8c62-3b4e8f39cb44.mxunit and b/resources/app-mpr-v2/mprcontents/74/0e/740ed2ec-6238-4622-8c62-3b4e8f39cb44.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/74/fb/74fbe7c0-6261-42bb-952a-ba0dd5e060d7.mxunit b/resources/app-mpr-v2/mprcontents/74/fb/74fbe7c0-6261-42bb-952a-ba0dd5e060d7.mxunit index 35d8735..1e6c08b 100644 Binary files a/resources/app-mpr-v2/mprcontents/74/fb/74fbe7c0-6261-42bb-952a-ba0dd5e060d7.mxunit and b/resources/app-mpr-v2/mprcontents/74/fb/74fbe7c0-6261-42bb-952a-ba0dd5e060d7.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/75/50/7550b3da-ccfd-4b2c-94f1-26a0ee0574a5.mxunit b/resources/app-mpr-v2/mprcontents/75/50/7550b3da-ccfd-4b2c-94f1-26a0ee0574a5.mxunit index 074a869..ff2b6f3 100644 Binary files a/resources/app-mpr-v2/mprcontents/75/50/7550b3da-ccfd-4b2c-94f1-26a0ee0574a5.mxunit and b/resources/app-mpr-v2/mprcontents/75/50/7550b3da-ccfd-4b2c-94f1-26a0ee0574a5.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/78/5d/785df806-095e-4020-b852-0d6b3b7d3ee8.mxunit b/resources/app-mpr-v2/mprcontents/78/5d/785df806-095e-4020-b852-0d6b3b7d3ee8.mxunit index e4c483f..c8bb5f6 100644 Binary files a/resources/app-mpr-v2/mprcontents/78/5d/785df806-095e-4020-b852-0d6b3b7d3ee8.mxunit and b/resources/app-mpr-v2/mprcontents/78/5d/785df806-095e-4020-b852-0d6b3b7d3ee8.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/79/77/797729f2-7448-4c95-be09-5a2e10d53b0a.mxunit b/resources/app-mpr-v2/mprcontents/79/77/797729f2-7448-4c95-be09-5a2e10d53b0a.mxunit index 1ec767b..1d82058 100644 Binary files a/resources/app-mpr-v2/mprcontents/79/77/797729f2-7448-4c95-be09-5a2e10d53b0a.mxunit and b/resources/app-mpr-v2/mprcontents/79/77/797729f2-7448-4c95-be09-5a2e10d53b0a.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/7c/94/7c94af18-6bf7-41a0-9368-87502f51e84a.mxunit b/resources/app-mpr-v2/mprcontents/7c/94/7c94af18-6bf7-41a0-9368-87502f51e84a.mxunit index 170271a..81bf2b6 100644 Binary files a/resources/app-mpr-v2/mprcontents/7c/94/7c94af18-6bf7-41a0-9368-87502f51e84a.mxunit and b/resources/app-mpr-v2/mprcontents/7c/94/7c94af18-6bf7-41a0-9368-87502f51e84a.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/7d/bd/7dbd1fb0-1736-48b7-b687-e4ba95514873.mxunit b/resources/app-mpr-v2/mprcontents/7d/bd/7dbd1fb0-1736-48b7-b687-e4ba95514873.mxunit index 37dc09a..18d540a 100644 Binary files a/resources/app-mpr-v2/mprcontents/7d/bd/7dbd1fb0-1736-48b7-b687-e4ba95514873.mxunit and b/resources/app-mpr-v2/mprcontents/7d/bd/7dbd1fb0-1736-48b7-b687-e4ba95514873.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/80/2f/802f155d-b936-4a24-a3e8-a92c01d4de55.mxunit b/resources/app-mpr-v2/mprcontents/80/2f/802f155d-b936-4a24-a3e8-a92c01d4de55.mxunit index a28e9ed..e2c30ce 100644 Binary files a/resources/app-mpr-v2/mprcontents/80/2f/802f155d-b936-4a24-a3e8-a92c01d4de55.mxunit and b/resources/app-mpr-v2/mprcontents/80/2f/802f155d-b936-4a24-a3e8-a92c01d4de55.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/82/d3/82d3944d-781d-454f-b408-15318fdc23b8.mxunit b/resources/app-mpr-v2/mprcontents/82/d3/82d3944d-781d-454f-b408-15318fdc23b8.mxunit index 10864f8..ac635b5 100644 Binary files a/resources/app-mpr-v2/mprcontents/82/d3/82d3944d-781d-454f-b408-15318fdc23b8.mxunit and b/resources/app-mpr-v2/mprcontents/82/d3/82d3944d-781d-454f-b408-15318fdc23b8.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/83/52/83528a06-83f9-45a3-8413-a1a245079dbf.mxunit b/resources/app-mpr-v2/mprcontents/83/52/83528a06-83f9-45a3-8413-a1a245079dbf.mxunit index 039a2d9..5879e70 100644 Binary files a/resources/app-mpr-v2/mprcontents/83/52/83528a06-83f9-45a3-8413-a1a245079dbf.mxunit and b/resources/app-mpr-v2/mprcontents/83/52/83528a06-83f9-45a3-8413-a1a245079dbf.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/8a/34/8a349320-91c5-41f4-bc69-ff7644a67ada.mxunit b/resources/app-mpr-v2/mprcontents/8a/34/8a349320-91c5-41f4-bc69-ff7644a67ada.mxunit index 6b29532..abed251 100644 Binary files a/resources/app-mpr-v2/mprcontents/8a/34/8a349320-91c5-41f4-bc69-ff7644a67ada.mxunit and b/resources/app-mpr-v2/mprcontents/8a/34/8a349320-91c5-41f4-bc69-ff7644a67ada.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/8d/cd/8dcdb976-7319-422c-b7a2-bddc16a0d47c.mxunit b/resources/app-mpr-v2/mprcontents/8d/cd/8dcdb976-7319-422c-b7a2-bddc16a0d47c.mxunit new file mode 100644 index 0000000..1372377 Binary files /dev/null and b/resources/app-mpr-v2/mprcontents/8d/cd/8dcdb976-7319-422c-b7a2-bddc16a0d47c.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/8f/36/8f36ec3f-bf7b-4e7d-9791-c29d663466a6.mxunit b/resources/app-mpr-v2/mprcontents/8f/36/8f36ec3f-bf7b-4e7d-9791-c29d663466a6.mxunit index 1cbe6d1..5f1f0e8 100644 Binary files a/resources/app-mpr-v2/mprcontents/8f/36/8f36ec3f-bf7b-4e7d-9791-c29d663466a6.mxunit and b/resources/app-mpr-v2/mprcontents/8f/36/8f36ec3f-bf7b-4e7d-9791-c29d663466a6.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/91/e9/91e94323-c85d-424e-b2c5-57a0bdeaa276.mxunit b/resources/app-mpr-v2/mprcontents/91/e9/91e94323-c85d-424e-b2c5-57a0bdeaa276.mxunit index ef53ee3..14df339 100644 Binary files a/resources/app-mpr-v2/mprcontents/91/e9/91e94323-c85d-424e-b2c5-57a0bdeaa276.mxunit and b/resources/app-mpr-v2/mprcontents/91/e9/91e94323-c85d-424e-b2c5-57a0bdeaa276.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/96/02/9602cbda-536d-4359-9ba5-1bec20752879.mxunit b/resources/app-mpr-v2/mprcontents/96/02/9602cbda-536d-4359-9ba5-1bec20752879.mxunit index dc83610..7049c9d 100644 Binary files a/resources/app-mpr-v2/mprcontents/96/02/9602cbda-536d-4359-9ba5-1bec20752879.mxunit and b/resources/app-mpr-v2/mprcontents/96/02/9602cbda-536d-4359-9ba5-1bec20752879.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/96/49/96496df7-a00c-4336-853e-6640ac097b3c.mxunit b/resources/app-mpr-v2/mprcontents/96/49/96496df7-a00c-4336-853e-6640ac097b3c.mxunit index be34109..082f0e4 100644 Binary files a/resources/app-mpr-v2/mprcontents/96/49/96496df7-a00c-4336-853e-6640ac097b3c.mxunit and b/resources/app-mpr-v2/mprcontents/96/49/96496df7-a00c-4336-853e-6640ac097b3c.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/99/85/9985993b-d286-4a00-811f-0faf257e9c45.mxunit b/resources/app-mpr-v2/mprcontents/99/85/9985993b-d286-4a00-811f-0faf257e9c45.mxunit index 50376cd..0d2e043 100644 Binary files a/resources/app-mpr-v2/mprcontents/99/85/9985993b-d286-4a00-811f-0faf257e9c45.mxunit and b/resources/app-mpr-v2/mprcontents/99/85/9985993b-d286-4a00-811f-0faf257e9c45.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/9e/2b/9e2b120b-e11a-4989-b9c9-350483a6c0b7.mxunit b/resources/app-mpr-v2/mprcontents/9e/2b/9e2b120b-e11a-4989-b9c9-350483a6c0b7.mxunit index 4e0ffed..51804cd 100644 Binary files a/resources/app-mpr-v2/mprcontents/9e/2b/9e2b120b-e11a-4989-b9c9-350483a6c0b7.mxunit and b/resources/app-mpr-v2/mprcontents/9e/2b/9e2b120b-e11a-4989-b9c9-350483a6c0b7.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/a1/bf/a1bfc5c3-1e6f-4ed2-b1aa-7856483bfa48.mxunit b/resources/app-mpr-v2/mprcontents/a1/bf/a1bfc5c3-1e6f-4ed2-b1aa-7856483bfa48.mxunit index 8f7183e..d262c79 100644 Binary files a/resources/app-mpr-v2/mprcontents/a1/bf/a1bfc5c3-1e6f-4ed2-b1aa-7856483bfa48.mxunit and b/resources/app-mpr-v2/mprcontents/a1/bf/a1bfc5c3-1e6f-4ed2-b1aa-7856483bfa48.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/ac/7d/ac7d8508-1a6d-4b11-8f77-a10f5ec22974.mxunit b/resources/app-mpr-v2/mprcontents/ac/7d/ac7d8508-1a6d-4b11-8f77-a10f5ec22974.mxunit index b80e246..fe11e90 100644 Binary files a/resources/app-mpr-v2/mprcontents/ac/7d/ac7d8508-1a6d-4b11-8f77-a10f5ec22974.mxunit and b/resources/app-mpr-v2/mprcontents/ac/7d/ac7d8508-1a6d-4b11-8f77-a10f5ec22974.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/be/e7/bee78074-838f-404e-8a05-7fb1bb567043.mxunit b/resources/app-mpr-v2/mprcontents/be/e7/bee78074-838f-404e-8a05-7fb1bb567043.mxunit index 2ffc621..7294686 100644 Binary files a/resources/app-mpr-v2/mprcontents/be/e7/bee78074-838f-404e-8a05-7fb1bb567043.mxunit and b/resources/app-mpr-v2/mprcontents/be/e7/bee78074-838f-404e-8a05-7fb1bb567043.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/c0/4b/c04b930f-8070-48e6-9ba0-f97a061adb5f.mxunit b/resources/app-mpr-v2/mprcontents/c0/4b/c04b930f-8070-48e6-9ba0-f97a061adb5f.mxunit index cf839d1..0de7037 100644 Binary files a/resources/app-mpr-v2/mprcontents/c0/4b/c04b930f-8070-48e6-9ba0-f97a061adb5f.mxunit and b/resources/app-mpr-v2/mprcontents/c0/4b/c04b930f-8070-48e6-9ba0-f97a061adb5f.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/c4/27/c427746c-b094-4717-a245-77a4cf36aaff.mxunit b/resources/app-mpr-v2/mprcontents/c4/27/c427746c-b094-4717-a245-77a4cf36aaff.mxunit index a4327fe..732ba57 100644 Binary files a/resources/app-mpr-v2/mprcontents/c4/27/c427746c-b094-4717-a245-77a4cf36aaff.mxunit and b/resources/app-mpr-v2/mprcontents/c4/27/c427746c-b094-4717-a245-77a4cf36aaff.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/c4/8c/c48cbe23-57ee-477c-a76b-6489592fff08.mxunit b/resources/app-mpr-v2/mprcontents/c4/8c/c48cbe23-57ee-477c-a76b-6489592fff08.mxunit index d6e0846..ab9b7fe 100644 Binary files a/resources/app-mpr-v2/mprcontents/c4/8c/c48cbe23-57ee-477c-a76b-6489592fff08.mxunit and b/resources/app-mpr-v2/mprcontents/c4/8c/c48cbe23-57ee-477c-a76b-6489592fff08.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/d5/81/d5811947-50ab-4731-95cd-a7b561b7366a.mxunit b/resources/app-mpr-v2/mprcontents/d5/81/d5811947-50ab-4731-95cd-a7b561b7366a.mxunit index dda1d7e..d59d961 100644 Binary files a/resources/app-mpr-v2/mprcontents/d5/81/d5811947-50ab-4731-95cd-a7b561b7366a.mxunit and b/resources/app-mpr-v2/mprcontents/d5/81/d5811947-50ab-4731-95cd-a7b561b7366a.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/da/69/da693f46-8dfa-4d03-a63d-c571fe430b64.mxunit b/resources/app-mpr-v2/mprcontents/da/69/da693f46-8dfa-4d03-a63d-c571fe430b64.mxunit index 021713a..879221e 100644 Binary files a/resources/app-mpr-v2/mprcontents/da/69/da693f46-8dfa-4d03-a63d-c571fe430b64.mxunit and b/resources/app-mpr-v2/mprcontents/da/69/da693f46-8dfa-4d03-a63d-c571fe430b64.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/dd/58/dd582b70-5521-4242-aebd-48acb34c97d1.mxunit b/resources/app-mpr-v2/mprcontents/dd/58/dd582b70-5521-4242-aebd-48acb34c97d1.mxunit index 9dfdb65..e88c907 100644 Binary files a/resources/app-mpr-v2/mprcontents/dd/58/dd582b70-5521-4242-aebd-48acb34c97d1.mxunit and b/resources/app-mpr-v2/mprcontents/dd/58/dd582b70-5521-4242-aebd-48acb34c97d1.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/dd/cf/ddcf6ef4-e4c4-4194-a0dd-b1d97f0cdc66.mxunit b/resources/app-mpr-v2/mprcontents/dd/cf/ddcf6ef4-e4c4-4194-a0dd-b1d97f0cdc66.mxunit index 5d5f902..4e04092 100644 Binary files a/resources/app-mpr-v2/mprcontents/dd/cf/ddcf6ef4-e4c4-4194-a0dd-b1d97f0cdc66.mxunit and b/resources/app-mpr-v2/mprcontents/dd/cf/ddcf6ef4-e4c4-4194-a0dd-b1d97f0cdc66.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/e0/f5/e0f5873c-1902-499c-a3cf-91146ed71fc0.mxunit b/resources/app-mpr-v2/mprcontents/e0/f5/e0f5873c-1902-499c-a3cf-91146ed71fc0.mxunit index 313ffd4..29bcc5e 100644 Binary files a/resources/app-mpr-v2/mprcontents/e0/f5/e0f5873c-1902-499c-a3cf-91146ed71fc0.mxunit and b/resources/app-mpr-v2/mprcontents/e0/f5/e0f5873c-1902-499c-a3cf-91146ed71fc0.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/e3/6a/e36a5b77-2753-4daa-81a0-00589548079a.mxunit b/resources/app-mpr-v2/mprcontents/e3/6a/e36a5b77-2753-4daa-81a0-00589548079a.mxunit index c932b01..d684718 100644 Binary files a/resources/app-mpr-v2/mprcontents/e3/6a/e36a5b77-2753-4daa-81a0-00589548079a.mxunit and b/resources/app-mpr-v2/mprcontents/e3/6a/e36a5b77-2753-4daa-81a0-00589548079a.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/eb/ab/ebab5919-b396-45af-8486-3f8a3b049112.mxunit b/resources/app-mpr-v2/mprcontents/eb/ab/ebab5919-b396-45af-8486-3f8a3b049112.mxunit index f62fab7..284892a 100644 Binary files a/resources/app-mpr-v2/mprcontents/eb/ab/ebab5919-b396-45af-8486-3f8a3b049112.mxunit and b/resources/app-mpr-v2/mprcontents/eb/ab/ebab5919-b396-45af-8486-3f8a3b049112.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/ed/53/ed53106a-931b-45ff-8c09-c4a61e2d5dc0.mxunit b/resources/app-mpr-v2/mprcontents/ed/53/ed53106a-931b-45ff-8c09-c4a61e2d5dc0.mxunit index 52956fb..aa4ab53 100644 Binary files a/resources/app-mpr-v2/mprcontents/ed/53/ed53106a-931b-45ff-8c09-c4a61e2d5dc0.mxunit and b/resources/app-mpr-v2/mprcontents/ed/53/ed53106a-931b-45ff-8c09-c4a61e2d5dc0.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/ee/aa/eeaa96dd-bcb5-4985-9fde-6b65754360ef.mxunit b/resources/app-mpr-v2/mprcontents/ee/aa/eeaa96dd-bcb5-4985-9fde-6b65754360ef.mxunit index 872a811..712c149 100644 Binary files a/resources/app-mpr-v2/mprcontents/ee/aa/eeaa96dd-bcb5-4985-9fde-6b65754360ef.mxunit and b/resources/app-mpr-v2/mprcontents/ee/aa/eeaa96dd-bcb5-4985-9fde-6b65754360ef.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/ee/c3/eec3d6d7-3fc5-42aa-a93c-30cadfd7fcff.mxunit b/resources/app-mpr-v2/mprcontents/ee/c3/eec3d6d7-3fc5-42aa-a93c-30cadfd7fcff.mxunit index 5bc7a50..77a0832 100644 Binary files a/resources/app-mpr-v2/mprcontents/ee/c3/eec3d6d7-3fc5-42aa-a93c-30cadfd7fcff.mxunit and b/resources/app-mpr-v2/mprcontents/ee/c3/eec3d6d7-3fc5-42aa-a93c-30cadfd7fcff.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/ef/0f/ef0f9ac1-707b-4f12-a161-601aa16f5a4a.mxunit b/resources/app-mpr-v2/mprcontents/ef/0f/ef0f9ac1-707b-4f12-a161-601aa16f5a4a.mxunit index f48454d..cc8241f 100644 Binary files a/resources/app-mpr-v2/mprcontents/ef/0f/ef0f9ac1-707b-4f12-a161-601aa16f5a4a.mxunit and b/resources/app-mpr-v2/mprcontents/ef/0f/ef0f9ac1-707b-4f12-a161-601aa16f5a4a.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/f0/06/f0064893-3d06-4a11-8afd-7c3ad2b6e37f.mxunit b/resources/app-mpr-v2/mprcontents/f0/06/f0064893-3d06-4a11-8afd-7c3ad2b6e37f.mxunit index 3c43d18..f78a715 100644 Binary files a/resources/app-mpr-v2/mprcontents/f0/06/f0064893-3d06-4a11-8afd-7c3ad2b6e37f.mxunit and b/resources/app-mpr-v2/mprcontents/f0/06/f0064893-3d06-4a11-8afd-7c3ad2b6e37f.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/f0/eb/f0eb8aaa-c979-42c4-9cb0-c0c7b4970765.mxunit b/resources/app-mpr-v2/mprcontents/f0/eb/f0eb8aaa-c979-42c4-9cb0-c0c7b4970765.mxunit index 458d60f..b39e818 100644 Binary files a/resources/app-mpr-v2/mprcontents/f0/eb/f0eb8aaa-c979-42c4-9cb0-c0c7b4970765.mxunit and b/resources/app-mpr-v2/mprcontents/f0/eb/f0eb8aaa-c979-42c4-9cb0-c0c7b4970765.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/f1/97/f197f259-a90d-436d-88fa-a805ca29db36.mxunit b/resources/app-mpr-v2/mprcontents/f1/97/f197f259-a90d-436d-88fa-a805ca29db36.mxunit index d156d44..67d9f2a 100644 Binary files a/resources/app-mpr-v2/mprcontents/f1/97/f197f259-a90d-436d-88fa-a805ca29db36.mxunit and b/resources/app-mpr-v2/mprcontents/f1/97/f197f259-a90d-436d-88fa-a805ca29db36.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/f6/a4/f6a40cf5-f574-4775-87b6-f623dd60e4ff.mxunit b/resources/app-mpr-v2/mprcontents/f6/a4/f6a40cf5-f574-4775-87b6-f623dd60e4ff.mxunit index c01e04f..f4dd142 100644 Binary files a/resources/app-mpr-v2/mprcontents/f6/a4/f6a40cf5-f574-4775-87b6-f623dd60e4ff.mxunit and b/resources/app-mpr-v2/mprcontents/f6/a4/f6a40cf5-f574-4775-87b6-f623dd60e4ff.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/fe/49/fe494e4a-98c1-4e3d-915e-e998b6982e56.mxunit b/resources/app-mpr-v2/mprcontents/fe/49/fe494e4a-98c1-4e3d-915e-e998b6982e56.mxunit index fb8e337..ac580d9 100644 Binary files a/resources/app-mpr-v2/mprcontents/fe/49/fe494e4a-98c1-4e3d-915e-e998b6982e56.mxunit and b/resources/app-mpr-v2/mprcontents/fe/49/fe494e4a-98c1-4e3d-915e-e998b6982e56.mxunit differ diff --git a/resources/app-mpr-v2/mprcontents/ff/c1/ffc1a4c2-a2e3-4c62-835c-34ec7c29cdfb.mxunit b/resources/app-mpr-v2/mprcontents/ff/c1/ffc1a4c2-a2e3-4c62-835c-34ec7c29cdfb.mxunit new file mode 100644 index 0000000..c6eb0b7 Binary files /dev/null and b/resources/app-mpr-v2/mprcontents/ff/c1/ffc1a4c2-a2e3-4c62-835c-34ec7c29cdfb.mxunit differ diff --git a/resources/modelsource-v1/MyFirstModule/Folder/MicroflowComplexSplit.Microflows$Microflow.yaml b/resources/modelsource-v1/MyFirstModule/Folder/MicroflowComplexSplit.Microflows$Microflow.yaml index b6065f9..ab8f000 100644 --- a/resources/modelsource-v1/MyFirstModule/Folder/MicroflowComplexSplit.Microflows$Microflow.yaml +++ b/resources/modelsource-v1/MyFirstModule/Folder/MicroflowComplexSplit.Microflows$Microflow.yaml @@ -9,20 +9,22 @@ ConcurrenyErrorMessage: Documentation: "" Excluded: false ExportLevel: Hidden -MarkAsUsed: false -MicroflowActionInfo: null -MicroflowReturnType: - $Type: DataTypes$VoidType -Name: MicroflowComplexSplit -ObjectCollection: - $Type: Microflows$MicroflowObjectCollection - Objects: - - $Type: Microflows$StartEvent - - $Type: Microflows$EndEvent - Documentation: "" - ReturnValue: "" - - $Type: Microflows$ActionActivity - Action: +MainFunction: + - Attributes: + $Type: Microflows$StartEvent + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: ByoAvHEnAECoob0TcBsoCQ== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -30;0 + OriginControlVector: 0;0 + - Attributes: + $Type: Microflows$ActionActivity + Action: $Type: Microflows$CreateVariableAction ErrorHandlingType: Rollback InitialValue: MyFirstModule.EnumerationStatus._New @@ -30,43 +32,176 @@ ObjectCollection: VariableType: $Type: DataTypes$EnumerationType Enumeration: MyFirstModule.EnumerationStatus - AutoGenerateCaption: true - BackgroundColor: Default - Caption: Activity - Disabled: false - Documentation: "" - - $Type: Microflows$ExclusiveSplit - Caption: Decision - Documentation: "" - ErrorHandlingType: Rollback - SplitCondition: + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: WRDtQdo6JUyYuOoGOduyKg== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 30;0 + - Attributes: + $Type: Microflows$ExclusiveSplit + Caption: Decision + Documentation: "" + ErrorHandlingType: Rollback + SplitCondition: $Type: Microflows$ExpressionSplitCondition Expression: $status - - $Type: Microflows$EndEvent - Documentation: "" - ReturnValue: "" - - $Type: Microflows$EndEvent - Documentation: "" - ReturnValue: "" - - $Type: Microflows$ExclusiveMerge - - $Type: Microflows$EndEvent - Documentation: "" - ReturnValue: "" - - $Type: Microflows$ActionActivity - Action: - $Type: Microflows$CreateChangeAction - Commit: "No" - Entity: MyFirstModule.Bike - ErrorHandlingType: Rollback - Items: [] - RefreshInClient: false - VariableName: NewBike - AutoGenerateCaption: true - BackgroundColor: Default - Caption: Activity - Disabled: false - Documentation: "" + Splits: + - - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: GtQF96dtV0G8gOv2X9ulQw== + $Type: Microflows$EnumerationCase + Value: Done + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 15;0 + - Attributes: + $Type: Microflows$ExclusiveMerge + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: 4lsobhDlDEmu00iffEjksA== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 15;0 + - Attributes: + $Type: Microflows$EndEvent + Documentation: "" + ReturnValue: "" + - - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: mTqnRBztSU+tw1feVZstJw== + $Type: Microflows$EnumerationCase + Value: InProgress + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: 0;-15 + OriginControlVector: -2;14 + - Attributes: + $Type: Microflows$EndEvent + Documentation: "" + ReturnValue: "" + - - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: ofqfAAZ6W0Oi4BaPJNdYfg== + $Type: Microflows$EnumerationCase + Value: (empty) + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: 0;-30 + OriginControlVector: 0;15 + - Attributes: + $Type: Microflows$ActionActivity + Action: + $Type: Microflows$CreateChangeAction + Commit: "No" + Entity: MyFirstModule.Bike + ErrorHandlingType: Rollback + Items: [] + RefreshInClient: false + VariableName: NewBike + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: zcwSb1ri20aIsWKv+U6d9Q== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: 0;-15 + OriginControlVector: 0;30 + - Attributes: + $Type: Microflows$EndEvent + Documentation: "" + ReturnValue: "" + - - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: eafhO9mN/ka+Uu6v154wUw== + $Type: Microflows$EnumerationCase + Value: Cancelled + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: 0;15 + OriginControlVector: 0;15 + - Attributes: + $Type: Microflows$ExclusiveMerge + - - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: nbqcFg2i+Eu2YAO95CVRwQ== + $Type: Microflows$EnumerationCase + Value: _New + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: 15;0 + OriginControlVector: 0;15 + - Attributes: + $Type: Microflows$EndEvent + Documentation: "" + ReturnValue: "" +MarkAsUsed: false +MicroflowActionInfo: null +MicroflowReturnType: + $Type: DataTypes$VoidType +Name: MicroflowComplexSplit ReturnVariableName: "" Url: "" UrlSearchParameters: [] WorkflowActionInfo: null +pseudocode: |- + MICROFLOW: MicroflowComplexSplit + RETURN TYPE: void + + PSEUDOCODE + ---------- + BEGIN + + status = MyFirstModule.EnumerationStatus._New + + IF $status THEN + GOTO L001 // case: Done + // OR GOTO L002 // case: InProgress + // OR GOTO L003 // case: (empty) + // OR GOTO L001 // case: Cancelled + // OR GOTO L004 // case: _New + END IF + + LABEL L001 + + + LABEL L002 + + LABEL L003 + // action: Microflows$CreateChangeAction + + + LABEL L004 + + END diff --git a/resources/modelsource-v1/MyFirstModule/Folder/MicroflowForLoop.Microflows$Microflow.yaml b/resources/modelsource-v1/MyFirstModule/Folder/MicroflowForLoop.Microflows$Microflow.yaml index 476794d..d0511bb 100644 --- a/resources/modelsource-v1/MyFirstModule/Folder/MicroflowForLoop.Microflows$Microflow.yaml +++ b/resources/modelsource-v1/MyFirstModule/Folder/MicroflowForLoop.Microflows$Microflow.yaml @@ -9,20 +9,22 @@ ConcurrenyErrorMessage: Documentation: "" Excluded: false ExportLevel: Hidden -MarkAsUsed: false -MicroflowActionInfo: null -MicroflowReturnType: - $Type: DataTypes$VoidType -Name: MicroflowForLoop -ObjectCollection: - $Type: Microflows$MicroflowObjectCollection - Objects: - - $Type: Microflows$StartEvent - - $Type: Microflows$EndEvent - Documentation: "" - ReturnValue: "" - - $Type: Microflows$ActionActivity - Action: +MainFunction: + - Attributes: + $Type: Microflows$StartEvent + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: mNbOo7XmhE22WCcjlxz4Zw== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -30;0 + OriginControlVector: 0;0 + - Attributes: + $Type: Microflows$ActionActivity + Action: $Type: Microflows$RetrieveAction ErrorHandlingType: Rollback ResultVariableName: BikeList @@ -36,31 +38,46 @@ ObjectCollection: $Type: Microflows$ConstantRange SingleObject: false XpathConstraint: "" - AutoGenerateCaption: true - BackgroundColor: Default - Caption: Activity - Disabled: false - Documentation: "" - - $Type: Microflows$LoopedActivity - Documentation: "" - ErrorHandlingType: Rollback - LoopSource: + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: oSElvrlmJkGpoeUrbtZjKw== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -30;0 + OriginControlVector: 30;0 + - Attributes: + $Type: Microflows$LoopedActivity + Documentation: "" + ErrorHandlingType: Rollback + LoopSource: $Type: Microflows$IterableList ListVariableName: BikeList VariableName: IteratorBike - ObjectCollection: + ObjectCollection: $Type: Microflows$MicroflowObjectCollection Objects: - - $Type: Microflows$ActionActivity + - $ID: REoQzbooxUqlJfxtM61uuw== + $Type: Microflows$ActionActivity Action: + $ID: ePBJZv2ockmxBjt1gRJInw== $Type: Microflows$ChangeAction ChangeVariableName: IteratorBike Commit: "No" ErrorHandlingType: Rollback Items: - - $Type: Microflows$ChangeActionItem + - $ID: vlZ2qLGLHkaufP+Kexafqg== + $Type: Microflows$ChangeActionItem Association: "" Attribute: MyFirstModule.Bike.Name + Type: Set Value: '''abc''' RefreshInClient: false AutoGenerateCaption: true @@ -68,19 +85,69 @@ ObjectCollection: Caption: Activity Disabled: false Documentation: "" - - $Type: Microflows$ActionActivity - Action: + RelativeMiddlePoint: 184;120 + Size: 120;60 + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: fn8Jgb25I0yZH/iZubEH3w== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -30;0 + OriginControlVector: 30;0 + - Attributes: + $Type: Microflows$ActionActivity + Action: $Type: Microflows$CommitAction CommitVariableName: BikeList ErrorHandlingType: Rollback RefreshInClient: false WithEvents: true - AutoGenerateCaption: true - BackgroundColor: Default - Caption: Activity - Disabled: false - Documentation: "" + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: 5k1lHmjvtUWTjcbw91JXYQ== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 30;0 + - Attributes: + $Type: Microflows$EndEvent + Documentation: "" + ReturnValue: "" +MarkAsUsed: false +MicroflowActionInfo: null +MicroflowReturnType: + $Type: DataTypes$VoidType +Name: MicroflowForLoop ReturnVariableName: "" Url: "" UrlSearchParameters: [] WorkflowActionInfo: null +pseudocode: |- + MICROFLOW: MicroflowForLoop + RETURN TYPE: void + + PSEUDOCODE + ---------- + BEGIN + + BikeList = retrieve from database MyFirstModule.Bike + + FOR EACH IteratorBike IN BikeList + IteratorBike.Name = 'abc' + END FOR + + // action: Microflows$CommitAction + + + END diff --git a/resources/modelsource-v1/MyFirstModule/Folder/MicroflowLoop.Microflows$Microflow.yaml b/resources/modelsource-v1/MyFirstModule/Folder/MicroflowLoop.Microflows$Microflow.yaml index 4cc1f9c..e083e06 100644 --- a/resources/modelsource-v1/MyFirstModule/Folder/MicroflowLoop.Microflows$Microflow.yaml +++ b/resources/modelsource-v1/MyFirstModule/Folder/MicroflowLoop.Microflows$Microflow.yaml @@ -9,55 +9,145 @@ ConcurrenyErrorMessage: Documentation: "" Excluded: false ExportLevel: Hidden -MarkAsUsed: false -MicroflowActionInfo: null -MicroflowReturnType: - $Type: DataTypes$VoidType -Name: MicroflowLoop -ObjectCollection: - $Type: Microflows$MicroflowObjectCollection - Objects: - - $Type: Microflows$StartEvent - - $Type: Microflows$EndEvent - Documentation: "" - ReturnValue: "" - - $Type: Microflows$ActionActivity - Action: +MainFunction: + - Attributes: + $Type: Microflows$StartEvent + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: GiH0TK39nUWNx49qCaO+7Q== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -30;0 + OriginControlVector: 15;0 + - Attributes: + $Type: Microflows$ActionActivity + Action: $Type: Microflows$CreateVariableAction ErrorHandlingType: Rollback InitialValue: "10" VariableName: counter VariableType: $Type: DataTypes$IntegerType - AutoGenerateCaption: true - BackgroundColor: Default - Caption: Activity - Disabled: false - Documentation: "" - - $Type: Microflows$ExclusiveSplit - Caption: Enough? - Documentation: "" - ErrorHandlingType: Rollback - SplitCondition: + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: ssykl6pqyUqJCuOggJOUtQ== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 30;0 + - Attributes: + $Type: Microflows$ExclusiveMerge + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: NwmcF32mSUug4t2CDPQghQ== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 15;0 + - Attributes: + $Type: Microflows$ExclusiveSplit + Caption: Enough? + Documentation: "" + ErrorHandlingType: Rollback + SplitCondition: $Type: Microflows$ExpressionSplitCondition Expression: $counter > 0 - - $Type: Microflows$ActionActivity - Action: - $Type: Microflows$ChangeVariableAction - ChangeVariableName: counter - ErrorHandlingType: Rollback - Value: $counter-1 - AutoGenerateCaption: true - BackgroundColor: Default - Caption: Activity - Disabled: false - Documentation: "" - - $Type: Microflows$ExclusiveMerge - - $Type: Microflows$Annotation - Caption: 'label: label1' - - $Type: Microflows$Annotation - Caption: 'goto: label1' + Splits: + - - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: X8BX7EbNHEKxzAzXbV9PVw== + $Type: Microflows$EnumerationCase + Value: "true" + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 15;0 + - Attributes: + $Type: Microflows$EndEvent + Documentation: "" + ReturnValue: "" + - - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: ujmRZNU150qvnlAUoqPLJA== + $Type: Microflows$EnumerationCase + Value: "false" + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: 0;30 + OriginControlVector: 0;-15 + - Attributes: + $Type: Microflows$ActionActivity + Action: + $Type: Microflows$ChangeVariableAction + ChangeVariableName: counter + ErrorHandlingType: Rollback + Value: $counter-1 + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: n6vcUe3E4EWUB7u+Zoe2/Q== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: 0;-15 + OriginControlVector: -30;0 + - Attributes: + $Type: Microflows$ExclusiveMerge +MarkAsUsed: false +MicroflowActionInfo: null +MicroflowReturnType: + $Type: DataTypes$VoidType +Name: MicroflowLoop ReturnVariableName: "" Url: "" UrlSearchParameters: [] WorkflowActionInfo: null +pseudocode: |- + MICROFLOW: MicroflowLoop + RETURN TYPE: void + + PSEUDOCODE + ---------- + BEGIN + + counter = 10 + + LABEL L001 + + IF $counter > 0 THEN + GOTO L002 + ELSE + GOTO L003 + END IF + + LABEL L002 + + LABEL L003 + counter = $counter-1 + GOTO L001 + + END diff --git a/resources/modelsource-v1/MyFirstModule/Folder/MicroflowLoopNested.Microflows$Microflow.yaml b/resources/modelsource-v1/MyFirstModule/Folder/MicroflowLoopNested.Microflows$Microflow.yaml index 926032f..a7bd63b 100644 --- a/resources/modelsource-v1/MyFirstModule/Folder/MicroflowLoopNested.Microflows$Microflow.yaml +++ b/resources/modelsource-v1/MyFirstModule/Folder/MicroflowLoopNested.Microflows$Microflow.yaml @@ -9,83 +9,251 @@ ConcurrenyErrorMessage: Documentation: "" Excluded: false ExportLevel: Hidden -MarkAsUsed: false -MicroflowActionInfo: null -MicroflowReturnType: - $Type: DataTypes$VoidType -Name: MicroflowLoopNested -ObjectCollection: - $Type: Microflows$MicroflowObjectCollection - Objects: - - $Type: Microflows$StartEvent - - $Type: Microflows$EndEvent - Documentation: "" - ReturnValue: "" - - $Type: Microflows$ActionActivity - Action: +MainFunction: + - Attributes: + $Type: Microflows$StartEvent + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: pns0UIqrRUWOihSp3xfF0g== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -30;0 + OriginControlVector: 15;0 + - Attributes: + $Type: Microflows$ActionActivity + Action: $Type: Microflows$CreateVariableAction ErrorHandlingType: Rollback InitialValue: "10" VariableName: counter VariableType: $Type: DataTypes$IntegerType - AutoGenerateCaption: true - BackgroundColor: Default - Caption: Activity - Disabled: false - Documentation: "" - - $Type: Microflows$ExclusiveSplit - Caption: Enough? - Documentation: "" - ErrorHandlingType: Rollback - SplitCondition: + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: UKaIBh0q5EG61Fd5Hb1V1w== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 30;0 + - Attributes: + $Type: Microflows$ExclusiveMerge + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: 5D4FtjfHaU2hqHvOhHuW/g== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 15;0 + - Attributes: + $Type: Microflows$ExclusiveSplit + Caption: Enough? + Documentation: "" + ErrorHandlingType: Rollback + SplitCondition: $Type: Microflows$ExpressionSplitCondition Expression: $counter > 0 - - $Type: Microflows$ActionActivity - Action: - $Type: Microflows$ChangeVariableAction - ChangeVariableName: counter - ErrorHandlingType: Rollback - Value: $counter-1 - AutoGenerateCaption: true - BackgroundColor: Default - Caption: Activity - Disabled: false - Documentation: "" - - $Type: Microflows$ExclusiveMerge - - $Type: Microflows$ExclusiveSplit - Caption: more? - Documentation: "" - ErrorHandlingType: Rollback - SplitCondition: - $Type: Microflows$ExpressionSplitCondition - Expression: $counter2 > 0 - - $Type: Microflows$ActionActivity - Action: - $Type: Microflows$CreateVariableAction - ErrorHandlingType: Rollback - InitialValue: "20" - VariableName: counter2 - VariableType: - $Type: DataTypes$IntegerType - AutoGenerateCaption: true - BackgroundColor: Default - Caption: Activity - Disabled: false - Documentation: "" - - $Type: Microflows$ActionActivity - Action: - $Type: Microflows$ChangeVariableAction - ChangeVariableName: counter2 - ErrorHandlingType: Rollback - Value: $counter2-1 - AutoGenerateCaption: true - BackgroundColor: Default - Caption: Activity - Disabled: false - Documentation: "" - - $Type: Microflows$ExclusiveMerge + Splits: + - - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: +iET+CRW00Gp3hNjUtwu5g== + $Type: Microflows$EnumerationCase + Value: "true" + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 15;0 + - Attributes: + $Type: Microflows$EndEvent + Documentation: "" + ReturnValue: "" + - - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: QEeT4yPDzk6a3czfYVVGrg== + $Type: Microflows$EnumerationCase + Value: "false" + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: 0;30 + OriginControlVector: 0;-15 + - Attributes: + $Type: Microflows$ActionActivity + Action: + $Type: Microflows$CreateVariableAction + ErrorHandlingType: Rollback + InitialValue: "20" + VariableName: counter2 + VariableType: + $Type: DataTypes$IntegerType + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: nD1AKthUmEq3h50QOXyQZQ== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: 0;15 + OriginControlVector: 0;-30 + - Attributes: + $Type: Microflows$ExclusiveMerge + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: Cwi0Y+E+cEKMwOh2n+/ehA== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: 0;15 + OriginControlVector: 0;-15 + - Attributes: + $Type: Microflows$ExclusiveSplit + Caption: more? + Documentation: "" + ErrorHandlingType: Rollback + SplitCondition: + $Type: Microflows$ExpressionSplitCondition + Expression: $counter2 > 0 + Splits: + - - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: 57Dpwr4rtECju/dbpm0UcA== + $Type: Microflows$EnumerationCase + Value: "false" + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: 30;0 + OriginControlVector: -15;0 + - Attributes: + $Type: Microflows$ActionActivity + Action: + $Type: Microflows$ChangeVariableAction + ChangeVariableName: counter + ErrorHandlingType: Rollback + Value: $counter-1 + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: kOOW1HJnm06lCraExHD1AQ== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: 0;-15 + OriginControlVector: 0;30 + - Attributes: + $Type: Microflows$ExclusiveMerge + - - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: GJUIOCVuFkyxppsqr8/Lbw== + $Type: Microflows$EnumerationCase + Value: "true" + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: 0;-30 + OriginControlVector: 15;0 + - Attributes: + $Type: Microflows$ActionActivity + Action: + $Type: Microflows$ChangeVariableAction + ChangeVariableName: counter2 + ErrorHandlingType: Rollback + Value: $counter2-1 + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: dc3qO8PZ1EKIClotmzP5Tg== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: 15;0 + OriginControlVector: 0;30 + - Attributes: + $Type: Microflows$ExclusiveMerge +MarkAsUsed: false +MicroflowActionInfo: null +MicroflowReturnType: + $Type: DataTypes$VoidType +Name: MicroflowLoopNested ReturnVariableName: "" Url: "" UrlSearchParameters: [] WorkflowActionInfo: null +pseudocode: |- + MICROFLOW: MicroflowLoopNested + RETURN TYPE: void + + PSEUDOCODE + ---------- + BEGIN + + counter = 10 + + LABEL L001 + + IF $counter > 0 THEN + GOTO L002 + ELSE + GOTO L003 + END IF + + LABEL L002 + + LABEL L003 + counter2 = 20 + + LABEL L004 + + IF $counter2 > 0 THEN + GOTO L006 + ELSE + GOTO L005 + END IF + + LABEL L005 + counter = $counter-1 + GOTO L001 + + LABEL L006 + counter2 = $counter2-1 + GOTO L004 + + END diff --git a/resources/modelsource-v1/MyFirstModule/Folder/MicroflowSimple.Microflows$Microflow.yaml b/resources/modelsource-v1/MyFirstModule/Folder/MicroflowSimple.Microflows$Microflow.yaml index b7cdc79..b46d017 100644 --- a/resources/modelsource-v1/MyFirstModule/Folder/MicroflowSimple.Microflows$Microflow.yaml +++ b/resources/modelsource-v1/MyFirstModule/Folder/MicroflowSimple.Microflows$Microflow.yaml @@ -9,32 +9,65 @@ ConcurrenyErrorMessage: Documentation: "" Excluded: false ExportLevel: Hidden -MarkAsUsed: false -MicroflowActionInfo: null -MicroflowReturnType: - $Type: DataTypes$VoidType -Name: MicroflowSimple -ObjectCollection: - $Type: Microflows$MicroflowObjectCollection - Objects: - - $Type: Microflows$StartEvent - - $Type: Microflows$EndEvent - Documentation: "" - ReturnValue: "" - - $Type: Microflows$ActionActivity - Action: +MainFunction: + - Attributes: + $Type: Microflows$StartEvent + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: 3aYgrUdk2kes8OgRwAn/2w== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -30;0 + OriginControlVector: 15;0 + - Attributes: + $Type: Microflows$ActionActivity + Action: $Type: Microflows$CreateVariableAction ErrorHandlingType: Rollback InitialValue: "false" VariableName: Variable VariableType: $Type: DataTypes$BooleanType - AutoGenerateCaption: true - BackgroundColor: Default - Caption: Activity - Disabled: false - Documentation: "" + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: qTDWISziZ025rDj2XnQbSA== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 30;0 + - Attributes: + $Type: Microflows$EndEvent + Documentation: "" + ReturnValue: "" +MarkAsUsed: false +MicroflowActionInfo: null +MicroflowReturnType: + $Type: DataTypes$VoidType +Name: MicroflowSimple ReturnVariableName: "" Url: "" UrlSearchParameters: [] WorkflowActionInfo: null +pseudocode: |- + MICROFLOW: MicroflowSimple + RETURN TYPE: void + + PSEUDOCODE + ---------- + BEGIN + + Variable = false + + + END diff --git a/resources/modelsource-v1/MyFirstModule/Folder/MicroflowSplit.Microflows$Microflow.yaml b/resources/modelsource-v1/MyFirstModule/Folder/MicroflowSplit.Microflows$Microflow.yaml index 4a0f122..af3824c 100644 --- a/resources/modelsource-v1/MyFirstModule/Folder/MicroflowSplit.Microflows$Microflow.yaml +++ b/resources/modelsource-v1/MyFirstModule/Folder/MicroflowSplit.Microflows$Microflow.yaml @@ -9,58 +9,116 @@ ConcurrenyErrorMessage: Documentation: "" Excluded: false ExportLevel: Hidden -MarkAsUsed: false -MicroflowActionInfo: null -MicroflowReturnType: - $Type: DataTypes$VoidType -Name: MicroflowSplit -ObjectCollection: - $Type: Microflows$MicroflowObjectCollection - Objects: - - $Type: Microflows$StartEvent - - $Type: Microflows$EndEvent - Documentation: "" - ReturnValue: "" - - $Type: Microflows$ActionActivity - Action: +MainFunction: + - Attributes: + $Type: Microflows$StartEvent + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: gus6TaZ+7EqtgIf2bAnl2g== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -30;0 + OriginControlVector: 0;0 + - Attributes: + $Type: Microflows$ActionActivity + Action: $Type: Microflows$CreateVariableAction ErrorHandlingType: Rollback InitialValue: '''test'' ' VariableName: Variable VariableType: $Type: DataTypes$StringType - AutoGenerateCaption: true - BackgroundColor: Default - Caption: Activity - Disabled: false - Documentation: "" - - $Type: Microflows$ExclusiveSplit - Caption: empty? - Documentation: "" - ErrorHandlingType: Rollback - SplitCondition: + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: ZNXIj10BZUmfZB6SrZGZaA== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 30;0 + - Attributes: + $Type: Microflows$ExclusiveSplit + Caption: empty? + Documentation: "" + ErrorHandlingType: Rollback + SplitCondition: $Type: Microflows$ExpressionSplitCondition Expression: $Variable != empty and $Variable != '' - - $Type: Microflows$EndEvent - Documentation: "" - ReturnValue: "" - - $Type: Microflows$ActionActivity - Action: - $Type: Microflows$LogMessageAction - ErrorHandlingType: Rollback - IncludeLatestStackTrace: false - Level: Info - MessageTemplate: - $Type: Microflows$StringTemplate - Parameters: [] - Text: test - Node: '''XXX''' - AutoGenerateCaption: true - BackgroundColor: Default - Caption: Activity - Disabled: false - Documentation: "" + Splits: + - - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: 5pQc0Ffffk6oRS0KWA0uWg== + $Type: Microflows$EnumerationCase + Value: "false" + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 15;0 + - Attributes: + $Type: Microflows$EndEvent + Documentation: "" + ReturnValue: "" + - - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: fxaQkhvbpUq3X9IcxtTEow== + $Type: Microflows$EnumerationCase + Value: "true" + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: 0;-30 + OriginControlVector: 0;15 + - Attributes: + $Type: Microflows$ActionActivity + Action: + $Type: Microflows$LogMessageAction + ErrorHandlingType: Rollback + IncludeLatestStackTrace: false + Level: Info + MessageTemplate: + $Type: Microflows$StringTemplate + Parameters: [] + Text: test + Node: '''XXX''' + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: dpl6eUL5SUaChpbo+ZkS1g== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: 0;-15 + OriginControlVector: 0;30 + - Attributes: + $Type: Microflows$EndEvent + Documentation: "" + ReturnValue: "" +MarkAsUsed: false +MicroflowActionInfo: null +MicroflowReturnType: + $Type: DataTypes$VoidType +Name: MicroflowSplit ReturnVariableName: "" Url: "" UrlSearchParameters: [] WorkflowActionInfo: null +pseudocode: "MICROFLOW: MicroflowSplit\nRETURN TYPE: void\n\nPSEUDOCODE\n----------\nBEGIN\n\n Variable = 'test' \n\n IF $Variable != empty and $Variable != '' THEN\n GOTO L002\n ELSE\n GOTO L001\n END IF\n\n LABEL L001\n\n LABEL L002\n log info: \"test\"\n\n\nEND" diff --git a/resources/modelsource-v1/MyFirstModule/Folder/MicroflowSplitThenMerge.Microflows$Microflow.yaml b/resources/modelsource-v1/MyFirstModule/Folder/MicroflowSplitThenMerge.Microflows$Microflow.yaml index 82dd309..eb2f088 100644 --- a/resources/modelsource-v1/MyFirstModule/Folder/MicroflowSplitThenMerge.Microflows$Microflow.yaml +++ b/resources/modelsource-v1/MyFirstModule/Folder/MicroflowSplitThenMerge.Microflows$Microflow.yaml @@ -9,56 +9,149 @@ ConcurrenyErrorMessage: Documentation: "" Excluded: false ExportLevel: Hidden -MarkAsUsed: false -MicroflowActionInfo: null -MicroflowReturnType: - $Type: DataTypes$VoidType -Name: MicroflowSplitThenMerge -ObjectCollection: - $Type: Microflows$MicroflowObjectCollection - Objects: - - $Type: Microflows$StartEvent - - $Type: Microflows$EndEvent - Documentation: "" - ReturnValue: "" - - $Type: Microflows$ActionActivity - Action: +MainFunction: + - Attributes: + $Type: Microflows$StartEvent + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: svSfk27rQUOrFsOuNKD7DA== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -30;0 + OriginControlVector: 0;0 + - Attributes: + $Type: Microflows$ActionActivity + Action: $Type: Microflows$CreateVariableAction ErrorHandlingType: Rollback InitialValue: "false" VariableName: Variable VariableType: $Type: DataTypes$BooleanType - AutoGenerateCaption: true - BackgroundColor: Default - Caption: Activity - Disabled: false - Documentation: "" - - $Type: Microflows$ExclusiveSplit - Caption: left or right? - Documentation: "" - ErrorHandlingType: Rollback - SplitCondition: + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: vA0rbX3mvEezhz7u1QUK6g== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 30;0 + - Attributes: + $Type: Microflows$ExclusiveSplit + Caption: left or right? + Documentation: "" + ErrorHandlingType: Rollback + SplitCondition: $Type: Microflows$ExpressionSplitCondition Expression: $Variable - - $Type: Microflows$ActionActivity - Action: - $Type: Microflows$LogMessageAction - ErrorHandlingType: Rollback - IncludeLatestStackTrace: false - Level: Info - MessageTemplate: - $Type: Microflows$StringTemplate - Parameters: [] - Text: test - Node: '''XXX''' - AutoGenerateCaption: true - BackgroundColor: Default - Caption: Activity - Disabled: false - Documentation: "" - - $Type: Microflows$ExclusiveMerge + Splits: + - - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: aN4Nm1Ztw0e8gDQvOw2mTQ== + $Type: Microflows$EnumerationCase + Value: "false" + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 15;0 + - Attributes: + $Type: Microflows$ExclusiveMerge + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: xUuozi7+DkaKHOnHCW2EZQ== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 15;0 + - Attributes: + $Type: Microflows$EndEvent + Documentation: "" + ReturnValue: "" + - - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: Jd4hAUJwpE6gt6868Ytiqw== + $Type: Microflows$EnumerationCase + Value: "true" + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: 0;-30 + OriginControlVector: 0;15 + - Attributes: + $Type: Microflows$ActionActivity + Action: + $Type: Microflows$LogMessageAction + ErrorHandlingType: Rollback + IncludeLatestStackTrace: false + Level: Info + MessageTemplate: + $Type: Microflows$StringTemplate + Parameters: [] + Text: test + Node: '''XXX''' + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: +2Dc4CHizkOnL9xyPXkCRA== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: 0;15 + OriginControlVector: 30;0 + - Attributes: + $Type: Microflows$ExclusiveMerge +MarkAsUsed: false +MicroflowActionInfo: null +MicroflowReturnType: + $Type: DataTypes$VoidType +Name: MicroflowSplitThenMerge ReturnVariableName: "" Url: "" UrlSearchParameters: [] WorkflowActionInfo: null +pseudocode: |- + MICROFLOW: MicroflowSplitThenMerge + RETURN TYPE: void + + PSEUDOCODE + ---------- + BEGIN + + Variable = false + + IF $Variable THEN + GOTO L002 + ELSE + GOTO L001 + END IF + + LABEL L001 + + + LABEL L002 + log info: "test" + GOTO L001 + + END diff --git a/resources/modelsource-v1/MyFirstModule/MyFirstLogic.Microflows$Microflow.yaml b/resources/modelsource-v1/MyFirstModule/MyFirstLogic.Microflows$Microflow.yaml index f3d8b86..5a424c1 100644 --- a/resources/modelsource-v1/MyFirstModule/MyFirstLogic.Microflows$Microflow.yaml +++ b/resources/modelsource-v1/MyFirstModule/MyFirstLogic.Microflows$Microflow.yaml @@ -12,22 +12,22 @@ ConcurrenyErrorMessage: Documentation: '#noqa' Excluded: false ExportLevel: Hidden -MarkAsUsed: false -MicroflowActionInfo: null -MicroflowReturnType: - $Type: DataTypes$VoidType -Name: MyFirstLogic -ObjectCollection: - $Type: Microflows$MicroflowObjectCollection - Objects: - - $Type: Microflows$StartEvent - - $Type: Microflows$EndEvent - Documentation: "" - ReturnValue: "" - - $Type: Microflows$Annotation - Caption: "Microflows are used to define server logic in your app.\r\n\r\n- For client logic you can use Nanoflows\r\n- For business process logic you can use Workflows\r\n\r\nDocumentation: https://docs.mendix.com/refguide/application-logic" - - $Type: Microflows$ActionActivity - Action: +MainFunction: + - Attributes: + $Type: Microflows$StartEvent + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: D3Po1QicOkyhuybPVJjvAQ== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -30;0 + OriginControlVector: 0;0 + - Attributes: + $Type: Microflows$ActionActivity + Action: $Type: Microflows$RetrieveAction ErrorHandlingType: Rollback ResultVariableName: SessionList @@ -35,12 +35,41 @@ ObjectCollection: $Type: Microflows$AssociationRetrieveSource AssociationId: System.Session_User StartVariableName: currentUser - AutoGenerateCaption: true - BackgroundColor: Default - Caption: Activity - Disabled: false - Documentation: "" + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: [] + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: 0;0 + OriginControlVector: 0;0 + - Attributes: + $Type: Microflows$EndEvent + Documentation: "" + ReturnValue: "" +MarkAsUsed: false +MicroflowActionInfo: null +MicroflowReturnType: + $Type: DataTypes$VoidType +Name: MyFirstLogic ReturnVariableName: "" Url: "" UrlSearchParameters: [] WorkflowActionInfo: null +pseudocode: |- + MICROFLOW: MyFirstLogic + RETURN TYPE: void + + PSEUDOCODE + ---------- + BEGIN + + SessionList = retrieve from database + + + END diff --git a/resources/modelsource-v1/MyFirstModule/VA_Age.Microflows$Microflow.yaml b/resources/modelsource-v1/MyFirstModule/VA_Age.Microflows$Microflow.yaml index 7439591..2fdc3f1 100644 --- a/resources/modelsource-v1/MyFirstModule/VA_Age.Microflows$Microflow.yaml +++ b/resources/modelsource-v1/MyFirstModule/VA_Age.Microflows$Microflow.yaml @@ -9,42 +9,46 @@ ConcurrenyErrorMessage: Documentation: "" Excluded: false ExportLevel: Hidden -MarkAsUsed: false -MicroflowActionInfo: null -MicroflowReturnType: - $Type: DataTypes$IntegerType -Name: VA_Age -ObjectCollection: - $Type: Microflows$MicroflowObjectCollection - Objects: - - $Type: Microflows$StartEvent - - $Type: Microflows$EndEvent - Documentation: "" - ReturnValue: $Variable - $Bike/Year - - $Type: Microflows$MicroflowParameter - DefaultValue: "" - Documentation: "" - HasVariableNameBeenChanged: false - IsRequired: true - Name: Bike - VariableType: - $Type: DataTypes$ObjectType - Entity: MyFirstModule.Bike - - $Type: Microflows$ActionActivity - Action: +MainFunction: + - Attributes: + $Type: Microflows$StartEvent + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: Zd8wxeDn2UG3o0H3iJTjqg== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -30;0 + OriginControlVector: 0;0 + - Attributes: + $Type: Microflows$ActionActivity + Action: $Type: Microflows$CreateVariableAction ErrorHandlingType: Rollback InitialValue: "2024" VariableName: Variable VariableType: $Type: DataTypes$IntegerType - AutoGenerateCaption: true - BackgroundColor: Default - Caption: Activity - Disabled: false - Documentation: "" - - $Type: Microflows$ActionActivity - Action: + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: wkvhJt34KU2JSNqkhjNmeQ== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -30;0 + OriginControlVector: 30;0 + - Attributes: + $Type: Microflows$ActionActivity + Action: $Type: Microflows$RetrieveAction ErrorHandlingType: Rollback ResultVariableName: PhotoList @@ -58,12 +62,47 @@ ObjectCollection: $Type: Microflows$ConstantRange SingleObject: false XpathConstraint: "" - AutoGenerateCaption: true - BackgroundColor: Default - Caption: Activity - Disabled: false - Documentation: "" + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: eTq+WKyueUuvBhP3PGvxdQ== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 30;0 + - Attributes: + $Type: Microflows$EndEvent + Documentation: "" + ReturnValue: $Variable - $Bike/Year +MarkAsUsed: false +MicroflowActionInfo: null +MicroflowReturnType: + $Type: DataTypes$IntegerType +Name: VA_Age ReturnVariableName: Variable Url: "" UrlSearchParameters: [] WorkflowActionInfo: null +pseudocode: |- + MICROFLOW: VA_Age + RETURN TYPE: integer + PARAMETERS: + - Bike: MyFirstModule.Bike (required) + + PSEUDOCODE + ---------- + BEGIN + + Variable = 2024 + + PhotoList = retrieve from database MyFirstModule.Photo + + + END diff --git a/resources/modelsource-v2/Metadata.yaml b/resources/modelsource-v2/Metadata.yaml index 99033d2..0a22dcf 100644 --- a/resources/modelsource-v2/Metadata.yaml +++ b/resources/modelsource-v2/Metadata.yaml @@ -1,5 +1,5 @@ -ProductVersion: 10.18.3.58900 -BuildVersion: 10.18.3.58900 +ProductVersion: 10.24.9.81004 +BuildVersion: 10.24.9.81004 Modules: - Name: Atlas_Web_Content ID: GMyJGqJY0U2f8EzUDi71Dg== diff --git a/resources/modelsource-v2/Module2/MicroflowLoopExample.Microflows$Microflow.yaml b/resources/modelsource-v2/Module2/MicroflowLoopExample.Microflows$Microflow.yaml new file mode 100644 index 0000000..cead6df --- /dev/null +++ b/resources/modelsource-v2/Module2/MicroflowLoopExample.Microflows$Microflow.yaml @@ -0,0 +1,191 @@ +$Type: Microflows$Microflow +AllowConcurrentExecution: true +AllowedModuleRoles: [] +ApplyEntityAccess: false +ConcurrencyErrorMicroflow: "" +ConcurrenyErrorMessage: + $Type: Texts$Text + Items: + - $Type: Texts$Translation + LanguageCode: en_US + Text: "" +Documentation: "" +Excluded: false +ExportLevel: Hidden +MainFunction: + - Attributes: + $Type: Microflows$StartEvent + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: [] + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -30;0 + OriginControlVector: 15;0 + - Attributes: + $Type: Microflows$ActionActivity + Action: + $Type: Microflows$RetrieveAction + ErrorHandlingType: Rollback + ResultVariableName: UserList + RetrieveSource: + $Type: Microflows$DatabaseRetrieveSource + Entity: System.User + NewSortings: + $Type: Microflows$SortingsList + Sortings: [] + Range: + $Type: Microflows$ConstantRange + SingleObject: false + XpathConstraint: "" + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: [] + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -30;0 + OriginControlVector: 30;0 + - Attributes: + $Type: Microflows$LoopedActivity + Documentation: "" + ErrorHandlingType: Rollback + LoopSource: + $Type: Microflows$IterableList + ListVariableName: UserList + VariableName: IteratorUser + ObjectCollection: + $Type: Microflows$MicroflowObjectCollection + Objects: + - $ID: g/PgRp//CUStmibDmOJGUQ== + $Type: Microflows$ExclusiveSplit + Caption: Blocked? + Documentation: "" + ErrorHandlingType: Rollback + RelativeMiddlePoint: 423;230 + Size: 90;60 + SplitCondition: + $ID: x671Oc5lIUqVaYCRFRq33Q== + $Type: Microflows$ExpressionSplitCondition + Expression: $IteratorUser/Blocked + - $ID: qvJvj4trREyhrd0EFQZqAA== + $Type: Microflows$ActionActivity + Action: + $ID: 0wFuJMG8Z0ODTTj4cFqdaw== + $Type: Microflows$ChangeAction + ChangeVariableName: IteratorUser + Commit: "Yes" + ErrorHandlingType: Rollback + Items: + - $ID: 3ndmYkpAQEG56GUahxkUVQ== + $Type: Microflows$ChangeActionItem + Association: "" + Attribute: System.User.Blocked + Type: Set + Value: "false" + RefreshInClient: false + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + RelativeMiddlePoint: 556;216 + Size: 120;60 + - $ID: FxQfVn3+6UalNzCY6BlRGQ== + $Type: Microflows$ActionActivity + Action: + $ID: BsJx2U6qc0mMSYhVzohrVA== + $Type: Microflows$LogMessageAction + ErrorHandlingType: Rollback + IncludeLatestStackTrace: false + Level: Info + MessageTemplate: + $ID: pPxO50LYuECvCnIPPyLU8w== + $Type: Microflows$StringTemplate + Parameters: + - $ID: QmUmW9/5wkGUIEBKeJFeIw== + $Type: Microflows$TemplateParameter + Expression: $IteratorUser/Name + Text: User {1} not blocked + Node: '''Module2''' + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + RelativeMiddlePoint: 89;259 + Size: 120;60 + - $ID: VbyRMrCfdECSP4TpmH3wJg== + $Type: Microflows$ActionActivity + Action: + $ID: ZZKOWEUdDUqCkmWvTkKvTg== + $Type: Microflows$MicroflowCallAction + ErrorHandlingType: Rollback + MicroflowCall: + $ID: CkMwoLD0zkeY4/gzHvyLIQ== + $Type: Microflows$MicroflowCall + Microflow: Module2.SubMicroflowExample + ParameterMappings: + - $ID: z1Oi4YYudUWjQw+shw//Og== + $Type: Microflows$MicroflowCallParameterMapping + Argument: $IteratorUser + Parameter: Module2.SubMicroflowExample.User + QueueSettings: null + ResultVariableName: "" + UseReturnVariable: true + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + RelativeMiddlePoint: 242;101 + Size: 120;60 + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: [] + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 30;0 + - Attributes: + $Type: Microflows$EndEvent + Documentation: "" + ReturnValue: "" +MarkAsUsed: false +MicroflowActionInfo: null +MicroflowReturnType: + $Type: DataTypes$VoidType +Name: MicroflowLoopExample +ReturnVariableName: "" +Url: "" +UrlSearchParameters: [] +WorkflowActionInfo: null +pseudocode: |- + MICROFLOW: MicroflowLoopExample + RETURN TYPE: void + + PSEUDOCODE + ---------- + BEGIN + + UserList = retrieve from database System.User + + FOR EACH IteratorUser IN UserList + IF $IteratorUser/Blocked THEN + IteratorUser.Blocked = false + commit IteratorUser + call Module2.SubMicroflowExample(User = $IteratorUser) + ELSE + log info: "User {1} not blocked" + END IF + END FOR + + + END diff --git a/resources/modelsource-v2/Module2/MultiLineMicroflow.Microflows$Microflow.yaml b/resources/modelsource-v2/Module2/MultiLineMicroflow.Microflows$Microflow.yaml new file mode 100644 index 0000000..3e2f37f --- /dev/null +++ b/resources/modelsource-v2/Module2/MultiLineMicroflow.Microflows$Microflow.yaml @@ -0,0 +1,146 @@ +$Type: Microflows$Microflow +AllowConcurrentExecution: true +AllowedModuleRoles: [] +ApplyEntityAccess: false +ConcurrencyErrorMicroflow: "" +ConcurrenyErrorMessage: + $Type: Texts$Text + Items: [] +Documentation: "" +Excluded: false +ExportLevel: Hidden +MainFunction: + - Attributes: + $Type: Microflows$StartEvent + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: [] + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 15;0 + - Attributes: + $Type: Microflows$ExclusiveSplit + Caption: hello + Documentation: "" + ErrorHandlingType: Rollback + SplitCondition: + $Type: Microflows$ExpressionSplitCondition + Expression: |- + if $currentUser/Name = 'Hello' then + true + else if $currentUser/Active then + true + else if $currentUser/Blocked then + false + else if $currentUser/FailedLogins > 0 then + false + + else + false + Splits: + - - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: kFLcqSkTTE2SbZHeWHs7RA== + $Type: Microflows$EnumerationCase + Value: "true" + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -30;0 + OriginControlVector: 15;0 + - Attributes: + $Type: Microflows$ActionActivity + Action: + $Type: Microflows$ChangeAction + ChangeVariableName: currentUser + Commit: "No" + ErrorHandlingType: Rollback + Items: + - $ID: pP7PeHh36UGf5MurbcmkNw== + $Type: Microflows$ChangeActionItem + Association: "" + Attribute: System.User.Name + Type: Set + Value: " if $currentUser/Name = 'a' then\n'b'\nelse if $currentUser/Name = 'b' then\n'c'\nelse\n$currentUser/Name\n" + RefreshInClient: false + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: [] + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 30;0 + - Attributes: + $Type: Microflows$EndEvent + Documentation: "" + ReturnValue: "" + - - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: Pp0aNAtKQEGJxbZFmKrXcw== + $Type: Microflows$EnumerationCase + Value: "false" + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: 0;-15 + OriginControlVector: 0;15 + - Attributes: + $Type: Microflows$EndEvent + Documentation: "" + ReturnValue: "" +MarkAsUsed: false +MicroflowActionInfo: null +MicroflowReturnType: + $Type: DataTypes$VoidType +Name: MultiLineMicroflow +ReturnVariableName: "" +Url: "" +UrlSearchParameters: [] +WorkflowActionInfo: null +pseudocode: |- + MICROFLOW: MultiLineMicroflow + RETURN TYPE: void + + PSEUDOCODE + ---------- + BEGIN + + IF if $currentUser/Name = 'Hello' then + true + else if $currentUser/Active then + true + else if $currentUser/Blocked then + false + else if $currentUser/FailedLogins > 0 then + false + + else + false THEN + GOTO L001 + ELSE + GOTO L002 + END IF + + LABEL L001 + currentUser.Name = if $currentUser/Name = 'a' then + 'b' + else if $currentUser/Name = 'b' then + 'c' + else + $currentUser/Name + + + + LABEL L002 + + END diff --git a/resources/modelsource-v2/Module2/SubMicroflowExample.Microflows$Microflow.yaml b/resources/modelsource-v2/Module2/SubMicroflowExample.Microflows$Microflow.yaml new file mode 100644 index 0000000..b9b15c3 --- /dev/null +++ b/resources/modelsource-v2/Module2/SubMicroflowExample.Microflows$Microflow.yaml @@ -0,0 +1,177 @@ +$Type: Microflows$Microflow +AllowConcurrentExecution: true +AllowedModuleRoles: [] +ApplyEntityAccess: false +ConcurrencyErrorMicroflow: "" +ConcurrenyErrorMessage: + $Type: Texts$Text + Items: [] +Documentation: "" +Excluded: false +ExportLevel: Hidden +MainFunction: + - Attributes: + $Type: Microflows$StartEvent + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: [] + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -30;0 + OriginControlVector: 15;0 + - Attributes: + $Type: Microflows$ActionActivity + Action: + $Type: Microflows$LogMessageAction + ErrorHandlingType: Rollback + IncludeLatestStackTrace: false + Level: Info + MessageTemplate: + $Type: Microflows$StringTemplate + Parameters: + - $ID: fzpeCz9EJ0euoHen2mxcIQ== + $Type: Microflows$TemplateParameter + Expression: $User/Name + Text: Hello {1} + Node: '''Example''' + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: [] + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -30;0 + OriginControlVector: 30;0 + - Attributes: + $Type: Microflows$ActionActivity + Action: + $Type: Microflows$CreateVariableAction + ErrorHandlingType: Rollback + InitialValue: "10" + VariableName: counter + VariableType: + $Type: DataTypes$IntegerType + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: [] + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 30;0 + - Attributes: + $Type: Microflows$ExclusiveMerge + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: [] + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 15;0 + - Attributes: + $Type: Microflows$ExclusiveSplit + Caption: more than 0? + Documentation: "" + ErrorHandlingType: Rollback + SplitCondition: + $Type: Microflows$ExpressionSplitCondition + Expression: $counter > 0 + Splits: + - - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: ckJSVPWxw0CZrqKfFsuO5A== + $Type: Microflows$EnumerationCase + Value: "false" + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 15;0 + - Attributes: + $Type: Microflows$EndEvent + Documentation: "" + ReturnValue: "" + - - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: JTA1JyHlTkOWjStmhI0qGg== + $Type: Microflows$EnumerationCase + Value: "true" + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: 0;-30 + OriginControlVector: 0;15 + - Attributes: + $Type: Microflows$ActionActivity + Action: + $Type: Microflows$ChangeVariableAction + ChangeVariableName: counter + ErrorHandlingType: Rollback + Value: $counter - 1 + AutoGenerateCaption: true + BackgroundColor: Default + Caption: Activity + Disabled: false + Documentation: "" + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: [] + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: 0;15 + OriginControlVector: -30;0 + - Attributes: + $Type: Microflows$ExclusiveMerge +MarkAsUsed: false +MicroflowActionInfo: null +MicroflowReturnType: + $Type: DataTypes$VoidType +Name: SubMicroflowExample +ReturnVariableName: "" +Url: "" +UrlSearchParameters: [] +WorkflowActionInfo: null +pseudocode: |- + MICROFLOW: SubMicroflowExample + RETURN TYPE: void + PARAMETERS: + - User: System.User (required) + + PSEUDOCODE + ---------- + BEGIN + + log info: "Hello {1}" + + counter = 10 + + LABEL L001 + + IF $counter > 0 THEN + GOTO L003 + ELSE + GOTO L002 + END IF + + LABEL L002 + + LABEL L003 + counter = $counter - 1 + GOTO L001 + + END diff --git a/resources/modelsource-v2/MyFirstModule/MyFirstLogic.Microflows$Microflow.yaml b/resources/modelsource-v2/MyFirstModule/MyFirstLogic.Microflows$Microflow.yaml index 39a214c..882a57e 100644 --- a/resources/modelsource-v2/MyFirstModule/MyFirstLogic.Microflows$Microflow.yaml +++ b/resources/modelsource-v2/MyFirstModule/MyFirstLogic.Microflows$Microflow.yaml @@ -9,21 +9,39 @@ ConcurrenyErrorMessage: Documentation: "" Excluded: false ExportLevel: Hidden +MainFunction: + - Attributes: + $Type: Microflows$StartEvent + - Attributes: + $Type: Microflows$SequenceFlow + CaseValues: + - $ID: D3Po1QicOkyhuybPVJjvAQ== + $Type: Microflows$NoCase + IsErrorHandler: false + Line: + $Type: Microflows$BezierCurve + DestinationControlVector: -15;0 + OriginControlVector: 0;0 + - Attributes: + $Type: Microflows$EndEvent + Documentation: "" + ReturnValue: "" MarkAsUsed: false MicroflowActionInfo: null MicroflowReturnType: $Type: DataTypes$VoidType Name: MyFirstLogic -ObjectCollection: - $Type: Microflows$MicroflowObjectCollection - Objects: - - $Type: Microflows$StartEvent - - $Type: Microflows$EndEvent - Documentation: "" - ReturnValue: "" - - $Type: Microflows$Annotation - Caption: "Microflows are used to define server logic in your app.\r\n\r\n- For client logic you can use Nanoflows\r\n- For business process logic you can use Workflows\r\n\r\nDocumentation: https://docs.mendix.com/refguide/application-logic" ReturnVariableName: "" Url: "" UrlSearchParameters: [] WorkflowActionInfo: null +pseudocode: |- + MICROFLOW: MyFirstLogic + RETURN TYPE: void + + PSEUDOCODE + ---------- + BEGIN + + + END diff --git a/resources/modelsource-v2/Settings$ProjectSettings.yaml b/resources/modelsource-v2/Settings$ProjectSettings.yaml index da42051..0a3b89e 100644 --- a/resources/modelsource-v2/Settings$ProjectSettings.yaml +++ b/resources/modelsource-v2/Settings$ProjectSettings.yaml @@ -8,6 +8,7 @@ Settings: UrlPrefix: p UseOptimizedClient: "No" - $Type: Settings$IntegrationProjectSettingsPart + ObsoleteEnableUrlEncoding: false - $Type: Settings$ConfigurationSettings Configurations: - $Type: Settings$ServerConfiguration @@ -27,6 +28,7 @@ Settings: OpenAdminPort: true OpenHttpPort: false ServerPortNumber: 8090 + Tracing: null - $Type: Settings$ModelSettings AfterStartupMicroflow: "" AllowUserMultipleSessions: true @@ -40,11 +42,13 @@ Settings: JavaVersion: Java21 RoundingMode: HalfUp ScheduledEventTimeZoneCode: Etc/UTC + SslCertificateAlgorithm: SunX509 UseDatabaseForeignKeyConstraints: true UseOQLVersion2: false UseSystemContextForBackgroundTasks: false - $Type: Settings$ConventionSettings ActionActivityDefaultColors: [] + DefaultAssociationStorage: Table DefaultSequenceFlowLineType: BezierCurve LowerCaseMicroflowVariables: false - $Type: Settings$LanguageSettings diff --git a/resources/modelsource-v2/Texts$SystemTextCollection.yaml b/resources/modelsource-v2/Texts$SystemTextCollection.yaml index 236181b..f46df55 100644 --- a/resources/modelsource-v2/Texts$SystemTextCollection.yaml +++ b/resources/modelsource-v2/Texts$SystemTextCollection.yaml @@ -1089,17 +1089,6 @@ SystemTexts: - $Type: Texts$Translation LanguageCode: en_US Text: You can’t complete this user task, it is not assigned to you. - - $Type: Texts$SystemText - InternalKey: mendix.platform.workflows.cant_complete_task_generic - Text: - $Type: Texts$Text - Items: - - $Type: Texts$Translation - LanguageCode: nl_NL - Text: Je kunt deze taak niet afronden, de taak is wellicht al afgerond, is niet langer geldig of the workflow is al verder gegaan. - - $Type: Texts$Translation - LanguageCode: en_US - Text: You can’t complete this user task, it may be already completed, invalid, or the workflow might have moved on. - $Type: Texts$SystemText InternalKey: mendix.platform.workflows.cant_lock_workflow_definition_locked Text: @@ -1177,17 +1166,6 @@ SystemTexts: - $Type: Texts$Translation LanguageCode: nl_NL Text: Jezelf verwijderen is niet mogelijk. - - $Type: Texts$SystemText - InternalKey: mendix.platform.creating_object_failed_because_of_security - Text: - $Type: Texts$Text - Items: - - $Type: Texts$Translation - LanguageCode: en_US - Text: Creating object of type {1} failed for security reasons. - - $Type: Texts$Translation - LanguageCode: nl_NL - Text: Een object creëren met type {1} is gefaald om veiligheidsredenen. - $Type: Texts$SystemText InternalKey: mendix.platform.deleting_object_failed_because_of_security Text: @@ -1254,3 +1232,69 @@ SystemTexts: - $Type: Texts$Translation LanguageCode: nl_NL Text: Kan de Jump-To opties niet genereren voor deze workflow instantie, omdat de huidige state het niet toestaat. + - $Type: Texts$SystemText + InternalKey: mxui.sys.UI.page_not_found + Text: + $Type: Texts$Text + Items: + - $Type: Texts$Translation + LanguageCode: en_US + Text: The page you requested was not found. You are redirected to the home page. + - $Type: Texts$Translation + LanguageCode: nl_NL + Text: Deze pagina kon niet gevonden worden. U word doorverwezen naar de home page + - $Type: Texts$SystemText + InternalKey: mendix.platform.workflows.cant_complete_task_outcome_already_set_by_you + Text: + $Type: Texts$Text + Items: + - $Type: Texts$Translation + LanguageCode: en_US + Text: You can't complete this user task because an outcome has already been set for this user. + - $Type: Texts$Translation + LanguageCode: nl_NL + Text: Je kunt deze taak niet afronden, want er is al een uitkomst gezet voor deze gebruiker. + - $Type: Texts$SystemText + InternalKey: mendix.platform.workflows.cant_complete_task_already_completed + Text: + $Type: Texts$Text + Items: + - $Type: Texts$Translation + LanguageCode: en_US + Text: You can't complete this user task because it is already completed. + - $Type: Texts$Translation + LanguageCode: nl_NL + Text: Je kunt deze taak niet afronden, want deze is al afgerond. + - $Type: Texts$SystemText + InternalKey: mendix.platform.workflows.cant_complete_task_not_in_progress + Text: + $Type: Texts$Text + Items: + - $Type: Texts$Translation + LanguageCode: en_US + Text: You can't complete this user task because it is not in progress. + - $Type: Texts$Translation + LanguageCode: nl_NL + Text: Je kunt deze taak niet afronden, want deze is niet actief. + - $Type: Texts$SystemText + InternalKey: mendix.platform.workflows.cant_complete_task_workflow_not_in_progress + Text: + $Type: Texts$Text + Items: + - $Type: Texts$Translation + LanguageCode: en_US + Text: You can't complete this user task because the workflow instance containing it is not in progress. + - $Type: Texts$Translation + LanguageCode: nl_NL + Text: Je kunt deze taak niet afronden, want de workflow waar deze onderdeel van is is niet actief. + - $Type: Texts$SystemText + InternalKey: mendix.platform.workflows.cant_complete_task_internal_error + Text: + $Type: Texts$Text + Items: + - $Type: Texts$Translation + LanguageCode: en_US + Text: You can’t complete this user task because there is an internal issue with it. Please contact your System Administrator. + - $Type: Texts$Translation + LanguageCode: nl_NL + Text: Je kunt deze taak niet afronden, want er is een interne fout opgetreden. Neem contact op met de applicatiebeheerder. diff --git a/resources/modelsource-v2/app.yaml b/resources/modelsource-v2/app.yaml index b42f73f..b4bca09 100644 --- a/resources/modelsource-v2/app.yaml +++ b/resources/modelsource-v2/app.yaml @@ -34,12 +34,21 @@ content: - name: Constant_3.Constants$Constant.yaml type: file path: Module2/Folder_testverylongl_TRUNCATED_70781_longlong name/Folder testverylongl_TRUNCATED_82413_glonglonglong/Constant_3.Constants$Constant.yaml + - name: MicroflowLoopExample.Microflows$Microflow.yaml + type: file + path: Module2/MicroflowLoopExample.Microflows$Microflow.yaml + - name: MultiLineMicroflow.Microflows$Microflow.yaml + type: file + path: Module2/MultiLineMicroflow.Microflows$Microflow.yaml - name: Projects$ModuleSettings.yaml type: file path: Module2/Projects$ModuleSettings.yaml - name: Security$ModuleSecurity.yaml type: file path: Module2/Security$ModuleSecurity.yaml + - name: SubMicroflowExample.Microflows$Microflow.yaml + type: file + path: Module2/SubMicroflowExample.Microflows$Microflow.yaml - name: _ type: directory path: Module2/_ diff --git a/scripts/update-modelsources.sh b/scripts/update-modelsources.sh index 6b90f09..897a2b1 100755 --- a/scripts/update-modelsources.sh +++ b/scripts/update-modelsources.sh @@ -1,5 +1,14 @@ #!/bin/sh # # -./bin/mxlint-darwin-arm64 export-model -i resources/app-mpr-v1 -o resources/modelsource-v1 -./bin/mxlint-darwin-arm64 export-model -i resources/app-mpr-v2 -o resources/modelsource-v2 +echo " +modelsource: resources/modelsource-v1 +projectDirectory: resources/app-mpr-v1 +" > /tmp/mxlint-dev.yaml +./bin/mxlint-darwin-arm64 export-model --config /tmp/mxlint-dev.yaml + +echo " +modelsource: resources/modelsource-v2 +projectDirectory: resources/app-mpr-v2 +" > /tmp/mxlint-dev.yaml +./bin/mxlint-darwin-arm64 export-model --config /tmp/mxlint-dev.yaml diff --git a/serve/serve.go b/serve/serve.go index 85c21e5..22edffa 100644 --- a/serve/serve.go +++ b/serve/serve.go @@ -54,7 +54,6 @@ func runServe(cmd *cobra.Command, args []string) { inputDirectory := config.ProjectDirectory outputDirectory := config.Modelsource - mode := config.Export.Mode rulesDirectory := config.Rules.Path port := intValue(config.Serve.Port, 8082) verbose, _ := cmd.Flags().GetBool("verbose") @@ -95,7 +94,6 @@ func runServe(cmd *cobra.Command, args []string) { log.Infof("Watching for changes in %s", expandedPath) log.Infof("Output directory: %s", outputDirectory) log.Infof("Rules directory: %s", rulesDirectory) - log.Infof("Mode: %s", mode) log.Infof("Debounce time: %d ms", debounceTime) // Create a mutex to protect the cached results @@ -197,7 +195,7 @@ func runServe(cmd *cobra.Command, args []string) { }() log.Infof("Running export-model and lint") - err := mpr.ExportModel(inputDirectory, outputDirectory, false, mode, false, "") + err := mpr.ExportModel(inputDirectory, outputDirectory, false, false, "") if err != nil { log.Warningf("Export failed: %s", err) resultMutex.Lock()