Skip to content

Commit 93a0ae5

Browse files
akoclaude
andcommitted
feat(check): warn on @caption applied to a loop (MDL042)
@caption on a loop is silently dropped — Mendix for-loops have no caption (Microflows$LoopedActivity has no Caption property; Studio Pro auto-labels them from the iterator). Previously mxcli accepted the annotation and discarded it, so users had no signal it was ignored. Emit an MDL042 warning at check time pointing users to @annotation (the supported way to attach a note to a loop). @annotation and plain loops are unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 528e19d commit 93a0ae5

2 files changed

Lines changed: 65 additions & 0 deletions

File tree

mdl/executor/validate_microflow.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,17 @@ func (v *microflowValidator) walkBody(body []ast.MicroflowStatement) {
166166
// RETRIEVE populates a list variable — remove from empty tracking
167167
delete(v.emptyListVars, stmt.Variable)
168168
case *ast.LoopStmt:
169+
// Check: @caption on a loop is silently dropped — Mendix for-loops
170+
// have no caption (Microflows$LoopedActivity has no Caption
171+
// property; Studio Pro auto-labels them from the iterator). The
172+
// supported way to label a loop is an annotation note.
173+
if stmt.Annotations != nil && stmt.Annotations.Caption != "" {
174+
v.addViolation("MDL042", linter.SeverityWarning,
175+
"@caption on a loop has no effect — Mendix loops have no caption "+
176+
"(the loop activity has no Caption property, so it is dropped). "+
177+
"Use @annotation to attach a note to the loop instead.",
178+
"Replace @caption with @annotation to label the loop")
179+
}
169180
// Check: nested loop anti-pattern
170181
if v.loopDepth > 0 {
171182
v.addViolation("MDL001", linter.SeverityWarning,
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package executor
4+
5+
import (
6+
"testing"
7+
8+
"github.com/mendixlabs/mxcli/mdl/ast"
9+
)
10+
11+
func mfWithLoopAnnotations(ann *ast.ActivityAnnotations) *ast.CreateMicroflowStmt {
12+
return &ast.CreateMicroflowStmt{
13+
Name: ast.QualifiedName{Module: "Sample", Name: "MF"},
14+
Body: []ast.MicroflowStatement{
15+
&ast.LoopStmt{
16+
LoopVariable: "Item",
17+
ListVariable: "Items",
18+
Annotations: ann,
19+
Body: []ast.MicroflowStatement{},
20+
},
21+
},
22+
}
23+
}
24+
25+
func loopHasMDL042(stmt *ast.CreateMicroflowStmt) bool {
26+
for _, v := range ValidateMicroflow(stmt) {
27+
if v.RuleID == "MDL042" {
28+
return true
29+
}
30+
}
31+
return false
32+
}
33+
34+
// TestValidateMicroflow_CaptionOnLoopWarns guards MDL042: @caption on a loop is
35+
// silently dropped (Mendix loops have no Caption property), so check must warn.
36+
func TestValidateMicroflow_CaptionOnLoopWarns(t *testing.T) {
37+
if !loopHasMDL042(mfWithLoopAnnotations(&ast.ActivityAnnotations{Caption: "Process things"})) {
38+
t.Error("expected MDL042 warning for @caption on a loop")
39+
}
40+
}
41+
42+
// @annotation (the supported way to label a loop) must NOT warn.
43+
func TestValidateMicroflow_AnnotationOnLoopNoWarn(t *testing.T) {
44+
if loopHasMDL042(mfWithLoopAnnotations(&ast.ActivityAnnotations{AnnotationText: "Process things"})) {
45+
t.Error("MDL042 must not fire for @annotation on a loop")
46+
}
47+
}
48+
49+
// A loop with no annotations must not warn.
50+
func TestValidateMicroflow_PlainLoopNoWarn(t *testing.T) {
51+
if loopHasMDL042(mfWithLoopAnnotations(nil)) {
52+
t.Error("MDL042 must not fire for a plain loop")
53+
}
54+
}

0 commit comments

Comments
 (0)