figdown 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -166,10 +166,12 @@ flowline check -> accept class=yes
166
166
  flowline check -> reject class=no
167
167
  ```
168
168
 
169
- A class a flowline joins MUST declare `stroke=` or `style=`; a `fill=`-only
170
- class joined by one is an error naming `stroke=`. `fill=` and `stroke=` are
171
- legal on any drawn element, but a flowline has no interior, so `fill=` on one
172
- is an error.
169
+ A class a flowline joins MUST NOT declare `fill=` with no `stroke=`: that is
170
+ an error naming `stroke=`. A class that declares **no paint at all** is
171
+ legal it claims a meaning, draws it in the derived legend with no swatch,
172
+ and leaves the flowline its default line. `fill=` and `stroke=` are legal on
173
+ any drawn element, but a flowline has no interior, so `fill=` on one is an
174
+ error.
173
175
 
174
176
  The connector's operators are `->`, `<-`, `--` and `<->`. In a procedure you
175
177
  almost always want `->`: a step follows another step in one direction, and an
@@ -0,0 +1,252 @@
1
+ # Genre `sequence` — EXPERIMENTAL
2
+
3
+ The genre is outside the conformance surface: it may change or be
4
+ **withdrawn** in a later `0.x` without a migration. There is no portable
5
+ rewrite of a sequence figure — a scene genre cannot carry time order — so a
6
+ figure written here is written here.
7
+
8
+ **It draws a ladder.** Participants are columns, left to right in `lifeline`
9
+ declaration order; time runs down the page, one row per `message` or `state`
10
+ in the order you wrote them. A `fragment` is a frame around the rows that
11
+ name it, with its operator in a tab at the top-left corner; an `operand` is a
12
+ compartment of that frame, as wide as the frame, divided from the one above
13
+ by a dashed rule, with its guard drawn `[in brackets]` at the left; a `state`
14
+ is a pill centred on its own column. A message to and from the same lifeline
15
+ draws a small rectangular loop; a message between non-adjacent columns is one
16
+ straight shaft over the lifelines it crosses, which are left intact; `<->`
17
+ draws ONE shaft with two heads, because it is one message and not two.
18
+
19
+ **You place nothing.** This genre has no key that moves a coordinate — not
20
+ `flow`, not `rank`, not a position. `layout` and `pin` still parse, because
21
+ they are the language's and no genre may redefine them, and a `pin` here
22
+ changes nothing at all: the drawing is identical with and without it.
23
+ Everything you can change about the figure, you change by changing what the
24
+ source SAYS.
25
+
26
+ **There are no activation bars.** UML draws a bar for the period a
27
+ participant is executing; that is a different thing from a message, this
28
+ genre has no word for it, and the renderer will not invent one out of which
29
+ messages happen to be adjacent.
30
+
31
+ **It needs `figdown 0.4` on line 1.** `figdown 0.3 sequence` is a line error,
32
+ and a deliberately named one: `genre "sequence" requires figdown 0.4`.
33
+
34
+ ## The vocabulary, which is five words
35
+
36
+ **This file is `sequence`'s whole vocabulary.** Load it and you can author in
37
+ this genre; do not load another genre's file, because another genre's
38
+ declaration of a word is not authority for this one.
39
+
40
+ | Line | What it declares |
41
+ |---|---|
42
+ | `lifeline <id> ["label"]` | a participant column — this genre's word for a node |
43
+ | `message <a> -> <b> ["label"]` | one message from `<a>` to `<b>` — this genre's word for a connector |
44
+ | `state <lifeline-id> "<state name>"` | the named state a lifeline is in from here on |
45
+ | `fragment <id> ["label"] type=<operator>` | a combined fragment — a framed region of the exchange |
46
+ | `operand <id> ["guard"] in=<fragment-id>` | one compartment of a fragment |
47
+
48
+ All five are taken from OMG UML 2.5.1 clause 17, which is this genre's source
49
+ standard, and every one of them is published by ISO as well, in ISO/IEC
50
+ 19505-2 clause 14. Three more words are legal because they are not about
51
+ exchanges at all: `class` (what a colour means), `title`, and `layout`/`pin`
52
+ — though a `pin` has nothing to place here.
53
+
54
+ **`flow` and `rank` are NOT this genre's keywords**, and that is a
55
+ consequence rather than an omission: both axes are already ordered by the
56
+ source. Columns are in `lifeline` declaration order; time runs down the page
57
+ in the order the `message` and `state` lines are written. A key that
58
+ reordered either would make the drawing disagree with the text.
59
+
60
+ **A `bitfield`, `table` or `timing` region cannot be opened here either.** A
61
+ scene genre can host one because it has a scene to host it in; a ladder has
62
+ no scene, so those three openers are line errors under `sequence`. Put the
63
+ companion table in its own section with its own header line.
64
+
65
+ ## Order is declaration order, and it is TOTAL
66
+
67
+ The figure's time axis is the `message` and `state` lines **in the order you
68
+ wrote them**. There is one order, it is total, and every reader gets the same
69
+ one. UML and ITU-T Z.120 both define a *partial* order — total along each
70
+ participant's own axis only, with cross-participant order coming from the
71
+ messages themselves. FigDown asserts more than either, deliberately, so that
72
+ one source never admits two equally legal drawings and a reader never has to
73
+ compute an ordering. **Write the lines in the order the events happen.**
74
+
75
+ The one way to say that two messages are NOT ordered is a `par` fragment
76
+ around them. That makes `type=par` part of the order model rather than a
77
+ convenience: without it, adjacent means earlier-than, always.
78
+
79
+ ## `message`: three operators, and `--` is an error
80
+
81
+ ```figdown
82
+ figdown 0.4 sequence
83
+ lifeline c "Client"
84
+ lifeline s "Server"
85
+ message c -> s "DHCPDISCOVER"
86
+ message c <- s "DHCPOFFER"
87
+ message c <-> s "keepalive"
88
+ ```
89
+
90
+ `->` and `<-` give the direction; `<->` is a sustained two-way exchange whose
91
+ individual messages are not enumerated — one message, drawn with one shaft
92
+ and two heads. **`--` is a line error here** and legal in every other genre:
93
+ a message has a sending event and a receiving event, so one with no direction
94
+ is not a thing this domain has.
95
+
96
+ The trailing quoted string is the message text, and it is where to write it.
97
+ The shared connector grammar also accepts a label in the inline bracket
98
+ position — `message c -[DHCPDISCOVER]-> s` — and both spellings reach the
99
+ same one field, so **writing both on one line is a line error**. Prefer the
100
+ trailing form; the bracket position reads as an annotation on the line rather
101
+ than as the message itself. `[tail]` and `[head]` are a different thing and
102
+ are unaffected: they label the two ends, not the message.
103
+
104
+ Both endpoints must be declared `lifeline` ids.
105
+
106
+ ## `state`: slot 1 REFERENCES a lifeline
107
+
108
+ ```figdown
109
+ figdown 0.4 sequence
110
+ lifeline c "Client"
111
+ state c "BOUND"
112
+ ```
113
+
114
+ This is the one place a word means something different from what it means in
115
+ another genre. Under `statechart`, `state locked "LOCKED"` **declares** the id
116
+ `locked`. Under `sequence`, `state c "BOUND"` **references** the lifeline `c`
117
+ and declares nothing: nothing here refers to a state occurrence, so it needs no
118
+ id of its own. The quoted name is **mandatory** — a state occurrence with no
119
+ name asserts nothing.
120
+
121
+ Two consecutive `state` lines naming the same lifeline and the same name are a
122
+ line error: a state that has not changed is never restated.
123
+
124
+ ## `fragment` and `operand`: `type=` is mandatory
125
+
126
+ ```figdown
127
+ figdown 0.4 sequence
128
+ lifeline c "Client"
129
+ lifeline s "Server"
130
+ fragment renew "renewal cycle" type=loop
131
+ operand t1 "while the lease is live" in=renew
132
+ message c -> s "DHCPREQUEST" in=t1
133
+ ```
134
+
135
+ `type=` takes one of **twelve** values, bare, taken whole from UML's
136
+ `InteractionOperatorKind`:
137
+
138
+ `alt` `opt` `loop` `par` `strict` `seq` `critical` `neg` `assert` `ignore`
139
+ `consider` `break`
140
+
141
+ There is **no default**. UML gives the attribute one (`seq`) and FigDown does
142
+ not, because a default draws a frame that looks like an assertion and is not
143
+ one. An `operand` is a compartment **of** a fragment, so its `in=` is
144
+ mandatory, and its quoted string is the guard. A fragment or an operand with
145
+ no members is a line error: a container's extent is the span of the lines
146
+ that name it, and a container with no extent asserts nothing.
147
+
148
+ ## `in=`: five acceptors, one meaning, one level
149
+
150
+ `in=` means *the element this one lives inside*, and its value is always a
151
+ `fragment` or an `operand` id. It is accepted on **`message`, `operand`,
152
+ `lifeline`, `state` and `fragment`** — five acceptors, all the same meaning.
153
+ An `operand`'s `in=` is narrower still: a compartment belongs to a FRAGMENT,
154
+ never to another compartment.
155
+
156
+ Three rules come with it:
157
+
158
+ - **Members must be CONTIGUOUS** in declaration order. An operand denotes the
159
+ ordered run of the occurrences it contains, so an occurrence that is not in
160
+ it cannot happen between two that are. A line that splits a run is a line
161
+ error naming the run.
162
+ - **Fragment nesting is capped at ONE level.** A fragment may sit in an
163
+ operand of one enclosing fragment and no deeper. Write a deeper interaction
164
+ as a sibling fragment, or state it in `description=`.
165
+ - **Containment is a tree.** A container that ends up inside itself is a line
166
+ error, because a cycle denotes nothing.
167
+
168
+ ## Three things this genre refuses, and what to write instead
169
+
170
+ Each is a line error with a named diagnostic — the engine tells you the ground
171
+ and the replacement. They are listed here so you do not reach for them.
172
+
173
+ - **`gap` — refused.** The vertical axis is not proportional: non-zero time has
174
+ already passed between every adjacent pair of events, so the line would say
175
+ nothing new, and *draw it further apart* is a rendering request. Put the
176
+ elapsed time into the following message's label or its `description=`.
177
+ - **`group` — refused.** UML clause 17 has no lifeline-grouping construct, and
178
+ a band across a column span would silently enclose non-members. Declare a
179
+ `class` naming what the participants have in common and put `class=` on each
180
+ `lifeline`: it asserts membership without asserting adjacency, and it earns a
181
+ legend entry.
182
+ - **`lost=` — refused, and no option key was added for it.** For a message that
183
+ was sent and not delivered, declare `class dropped "Sent, never delivered"`,
184
+ put `class=dropped` on the message, and put the per-message reason in
185
+ `description=`.
186
+
187
+ ## A whole document
188
+
189
+ ```figdown
190
+ figdown 0.4 sequence
191
+ title "Address lease and renewal"
192
+ class dropped "Sent, never delivered" stroke=#b91c1c style=dashed
193
+ lifeline c "DHCP client"
194
+ lifeline s "DHCP server"
195
+ message c -> s "DHCPDISCOVER"
196
+ message c <- s "DHCPOFFER"
197
+ state c "BOUND"
198
+ fragment renew "renewal cycle" type=loop
199
+ operand t1 "when the renewal timer fires" in=renew
200
+ message c -> s "DHCPREQUEST" in=t1 class=dropped description="the issuing server does not answer"
201
+ state c "RENEWING" in=t1
202
+ ```
203
+
204
+ Presentation is the same everywhere: `fill=` the interior, `stroke=` the
205
+ outline and the whole of a line, `class=` one or more declared class ids
206
+ comma-separated, and `style=solid|dashed|dotted` for the dash pattern.
207
+ `fill=` is an error on a `message`, on a `fragment` and on an `operand` — a
208
+ line has no interior, and a frame drawn over messages must not hide them.
209
+ `shape=` is accepted by nothing here: every shape in the ladder is the
210
+ engine's. `note=` is a drawn aside in prose and `description=` is authored
211
+ documentation that is never drawn; neither is where a structural fact lives.
212
+ A `fill=`-only class joined by a `message`, a `fragment` or an `operand` is a
213
+ **line error**: a line has no interior, so that class reaches nothing on it —
214
+ write `stroke=`. (This was accepted, when the check ran over
215
+ `edge`s only; it reaches every collection that takes `class=`.) A class that declares **no paint at all** is legal on any
216
+ member and always was here: it draws its meaning in the derived legend with
217
+ no swatch, which is what `class dropped "Sent, never delivered"` does in the
218
+ reference figure. Read a paint-less class as a claim about MEANING, never as
219
+ a missing colour.
220
+
221
+ ## What you may conclude from a `sequence` figure
222
+
223
+ - **Every `message` is a message**, its direction is the direction it travels,
224
+ and its position in the source is its position in time.
225
+ - **The order is total.** Two messages written one after the other happened in
226
+ that order.
227
+ - **`<->` is ONE message**, an exchange in both directions whose individual
228
+ messages are not enumerated — never a count of two.
229
+ - **The set of participants is closed.** A participant not declared is not
230
+ asserted to exist. Column position is declaration order and means nothing
231
+ else: not seniority, not layering, not a path.
232
+ - **A `state` line is the condition its lifeline is in from that point on**,
233
+ as free text — quotable, attributable, never parsable.
234
+ - **A `fragment` says what KIND of run its members are**, and its `type=` is
235
+ that claim; an `operand`'s quoted string is the guard on that compartment.
236
+
237
+ **Still not conclusible:**
238
+
239
+ - **No elapsed time, ever.** Vertical distance means only that non-zero time
240
+ passed. There is no duration, no timestamp and no rate in this genre.
241
+ - **No concurrency unless a `par` fragment says so.** Two adjacent messages are
242
+ ordered, not simultaneous.
243
+ - **No failure, no retransmission and no loss** unless a `class` says so in
244
+ words. There is no keyword for any of them, and a `class` meaning is prose:
245
+ attribute it to the prose, not to the model.
246
+ - **No activation, no execution period, no "busy".** Nothing is drawn for it
247
+ and nothing may be inferred from message adjacency.
248
+ - **No identity** between two messages with the same label, and none between a
249
+ state name here and a state in a statechart document. A shared `class` is a
250
+ shared category, never a shared identity.
251
+ - **Nothing from the layout zone.** Here that rule is total rather than
252
+ conventional: a `pin` changes no coordinate, because there is none to change.
@@ -79,9 +79,11 @@ spaces. Values from a fixed list are bare (`shape=box`, `style=dashed`,
79
79
  `shape=` is pure geometry and changes only the drawing — `shape=box` (the
80
80
  default), `shape=rounded`, `shape=circle`, `shape=ellipse`, `shape=diamond`,
81
81
  `shape=cylinder`. `style=` takes `style=solid`, `style=dashed` or
82
- `style=dotted`. A class a transition joins MUST declare `stroke=` or
83
- `style=`; `fill=` on a transition is an error, because a line has no
84
- interior. Under `figdown 0.3` a line may carry `note=`, a drawn aside in
82
+ `style=dotted`. A class a transition joins MUST NOT declare `fill=` with no
83
+ `stroke=` that is an error naming `stroke=`; a class that declares **no
84
+ paint at all** is legal and claims only a meaning, which the derived legend
85
+ draws with no swatch. `fill=` on a transition is an error, because a line has
86
+ no interior. Under `figdown 0.3` a line may carry `note=`, a drawn aside in
85
87
  prose — never parsable, never where a structural fact lives.
86
88
 
87
89
  ## What the genre adds, which is a reading and not a syntax
@@ -73,10 +73,12 @@ with what it *is* — "the internet", "the transit provider" — written in the
73
73
  label. `style=` takes `style=solid`, `style=dashed` or `style=dotted`.
74
74
 
75
75
  `class` declares what a colour **means** and is the only way to make colour
76
- carry meaning; a class an edge joins MUST declare `stroke=` or `style=`, and
77
- a `fill=`-only class joined by an edge is an error naming `stroke=`. `fill=`
78
- and `stroke=` are legal on any element, but an `edge` has no interior, so
79
- `fill=` on one is an error.
76
+ carry meaning; a class an edge joins MUST NOT declare `fill=` with no
77
+ `stroke=` that is an error naming `stroke=`. A class that declares **no
78
+ paint at all** is legal: it claims a meaning, draws it in the derived legend
79
+ with no swatch, and leaves the edge its default line. `fill=` and `stroke=`
80
+ are legal on any element, but an `edge` has no interior, so `fill=` on one is
81
+ an error.
80
82
 
81
83
  Endpoint labels nest (`edge a [xe-0/0/0:1] -- b`); quote them when they hold
82
84
  a line break or an unbalanced bracket (`edge a ["slot\n1/1"] -- b`). A `#`
@@ -94,14 +94,19 @@ language, so reading any of the three out of a figure is invention.
94
94
 
95
95
  ## What you MUST NOT infer
96
96
 
97
- - **Ignore the layout zone.** Everything from the `layout` keyword down is
98
- geometry, it exists only to stabilise the SVG, and no keyword turns this on
99
- or off. *(One exception, and it is a workaround for a missing construct:
100
- if the layout looks load-bearing dense pins forming a stack, a grid or a
101
- map, where stack order, cross-layer alignment or spans are the point
102
- read it, and say in your summary that you did. Such a document has a
103
- semantics gap.)* A document with no `layout` line may use an older
104
- `# --- layout` comment as an informal boundary.
97
+ - **Ignore the layout namespace.** Its one member today is `pin`. Ignore every
98
+ member **wherever it appears** membership decides, never position. A `pin`
99
+ written *before* the `layout` line is ignored on exactly the same terms as
100
+ one written after it, and about half of them are written before it. The
101
+ members are geometry, they exist only to stabilise the SVG, and no keyword
102
+ turns this on or off. *(One exception, and it is a workaround for a missing
103
+ construct: if the layout looks load-bearing dense pins forming a stack, a
104
+ grid or a map, where stack order, cross-layer alignment or spans are the
105
+ point — read it, and say in your summary that you did. Such a document has a
106
+ semantics gap.)* The `layout` line, and an older `# --- layout` comment in a
107
+ document that has no `layout` line, are a **reader's signpost** and not the
108
+ test: they say where the author collected the geometry, which is useful and
109
+ is not what decides.
105
110
  - **Arrangement is not precedence.** Declaration order records the author's
106
111
  statement order — a focus and reading-order signal. It is not a ranking, a
107
112
  priority or a sequence.
@@ -122,7 +127,7 @@ language, so reading any of the three out of a figure is invention.
122
127
  one file may legitimately carry sections at different versions. The
123
128
  permanent exceptions: `figdown`, `title`,
124
129
  `layout` and `pin` mean the same thing everywhere — which is exactly what
125
- lets you skip the layout zone without first knowing the genre.
130
+ lets you skip the layout namespace without first knowing the genre.
126
131
  - **A shared `class` is a shared category, not an identity.** The language
127
132
  has no equivalence or alias relation.
128
133
  - **Status is not visible in the syntax.** A line that parses tells you
@@ -137,9 +137,14 @@ edge check -> accept class=yes
137
137
  edge check -> reject class=no
138
138
  ```
139
139
 
140
- A class an edge joins MUST declare `stroke=` or `style=`; a `fill=`-only
141
- class and a paint-less class are both errors naming `stroke=`. One class may
142
- carry both keys and serve nodes and edges at once do not split it.
140
+ A class an edge joins MUST NOT declare `fill=` with no `stroke=`: an edge has
141
+ no interior, so that class reaches nothing on it — write `stroke=`, and a
142
+ `style=` beside the `fill=` does not answer for it. A class that declares
143
+ **no paint at all** is legal on every member: it draws its meaning in the
144
+ derived legend with no swatch, and the edge keeps its default line. Read a
145
+ paint-less class as a claim about MEANING, never as a missing colour. One
146
+ class may carry both keys and serve nodes and edges at once — do not split
147
+ it.
143
148
 
144
149
  **Never invent a label.** If the shape genuinely carries no text — a
145
150
  junction, a bare glyph — write an explicitly empty label: `node j ""`. It