Commit 1f8864a
committed
feat: @anchor annotation for microflow sequence flow endpoints
Studio Pro renders each SequenceFlow against one of four sides of the
origin and destination activity boxes (top, right, bottom, left). Until
now the builder always derived the anchor side from the flow's visual
direction and the describer dropped the information entirely, so a
DESCRIBE → re-execute round-trip lost every manual side-tweak. Agent-
generated microflow patches therefore reshuffled the arrow layout in
the Studio Pro diagram even when they were semantically identical to
the original — the flow diagram had to be re-tidied by hand after each
iteration.
New optional annotation on microflow statements:
@anchor(from: right, to: left)
log info node 'App' 'hello';
Each side is independently optional. Missing sides fall back to the
builder's default for the visual flow direction — existing MDL scripts
are unchanged.
IF statements support a combined form for the incoming flow plus the
per-branch outgoing flows:
@anchor(to: top, true: (from: right, to: left), false: (from: bottom, to: top))
if condition then
...
else
...
end if;
top (0), right (1), bottom (2), left (3) — matching the indices Mendix
stores in OriginConnectionIndex / DestinationConnectionIndex on the
SequenceFlow BSON.
@anchor is emitted for every activity whenever flows are attached, so
describe → exec → describe is bit-exact on the anchor indices. For
splits the combined form is used when any of the three groups (incoming
to, true-branch, false-branch) has a non-default value.
- AST: ast.AnchorSide, ast.FlowAnchors; ActivityAnnotations gains
Anchor / TrueBranchAnchor / FalseBranchAnchor / IteratorAnchor /
BodyTailAnchor (all optional, AST-only for iterator/tail).
- Grammar: ANCHOR / TOP / BOTTOM lexer tokens; `@anchor(key: value)`
parser rule with a nested-params form for the split-branch shape.
- Visitor: populates anchor fields from annotation contexts.
- Builder: applyUserAnchors helper; mergeStatementAnnotations carries
anchor fields into pendingAnnotations; buildFlowGraph and
addIfStatement apply anchor indices per the user spec. Guard-pattern
IFs (no else, then returns) use the new nextFlowAnchor plumbing so
the deferred split→nextActivity flow also honours
@anchor(false: ...).
- Describer: emitAnchorAnnotation outputs `@anchor(from: X, to: Y)`
for non-split activities and a split-form variant for ExclusiveSplit
/ InheritanceSplit. Branch detection reuses findBranchFlows so all
CaseValue variants (ExpressionCase, EnumerationCase, BooleanCase,
value + pointer) are covered.
Tightening @anchor roundtrips exposed two pre-existing bugs in
expressionToString used for `if cond then`, regex literals, etc.:
- Using mdlQuote doubled every backslash, breaking regex escape
sequences like \d that the Mendix expression engine consumes
literally.
- Using only apostrophe-doubling emitted raw control characters (0x0A,
0x0D, 0x09) inside single-quoted literals, which STRING_LITERAL
rejects.
Fix: new quoteExpressionLiteral that escapes control chars and
backslashes followed by an MDL-significant letter (n/r/t/\/'), but
passes other backslash sequences through verbatim. Trailing backslash
at EOF is doubled so the lexer doesn't consume the closing quote as an
escape pair.
Loop describe output previously omitted the `begin` keyword the MDL
grammar requires after `loop $X in $Y`. It parsed by accident
because every body statement's leading keyword was accepted after the
header. With @anchor landing before the first body statement, the
parser started seeing `@position(...)` immediately after the loop
header and failed. Fix: emit `begin` unconditionally between the
loop header and body in every LoopedActivity call-site.
- visitor_anchor_test.go: syntax simple / partial / 4 sides / split
form / absence → nil.
- cmd_microflows_builder_anchor_test.go: override applied; default
kept when omitted; partial override preserves other side;
per-branch IF anchors.
- cmd_microflows_describe_anchor_test.go: @anchor emission;
no-flows case; roundtrip via builder.
- cmd_microflows_split_incoming_anchor_test.go: split incoming to;
EnumerationCase, ExpressionCase, BooleanCase branch forms.
- cmd_microflows_expr_literal_escape_test.go: regex passthrough; raw
control char escaping; apostrophe doubling; backslash-before-escape
letter doubling; trailing backslash doubling; idempotency.
- cmd_microflows_anchor_if_test.go: anchor preservation inside ELSE
branch (real mendixlabs#35 pattern); anchor(to: top) on return inside else.
- cmd_microflows_annotation_escape_test.go: mdlQuote control-char
escaping; apostrophe doubling.
- cmd_microflows_guard_pattern_test.go: guard-pattern IF carries
false-branch anchor through the deferred flow.
- cmd_microflows_loop_begin_test.go: loop describe output opens with
`begin`.
Tested against the Control Centre project (Mendix 9.24, ~200
microflows). On 5 representative cases including the attempt-mendixlabs#35 repro
(Apps.GetOrCreateMendixVersionFromString, MxAdmin.CreateMendixVersion
FromString, AcademyIntegration.GetOrCreateCertificate), the describe →
exec → describe round-trip preserves every anchor (0 drifts) and the
output parses through `mxcli check`.
CHANGELOG updated under [Unreleased] → Added.1 parent 0235cdb commit 1f8864a
32 files changed
Lines changed: 16415 additions & 14075 deletions
File tree
- cmd/mxcli
- mdl-examples/bug-tests
- mdl
- ast
- executor
- grammar
- parser
- visitor
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
| 16 | + | |
16 | 17 | | |
17 | 18 | | |
18 | 19 | | |
| |||
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 59 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
105 | 105 | | |
106 | 106 | | |
107 | 107 | | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
108 | 128 | | |
109 | | - | |
| 129 | + | |
110 | 130 | | |
111 | | - | |
112 | | - | |
113 | | - | |
114 | | - | |
115 | | - | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
116 | 150 | | |
117 | 151 | | |
118 | 152 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
34 | 41 | | |
35 | 42 | | |
36 | 43 | | |
37 | 44 | | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
38 | 49 | | |
39 | 50 | | |
40 | 51 | | |
| |||
0 commit comments