figdown 0.1.8 → 0.3.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.
- package/.claude-plugin/plugin.json +1 -1
- package/dist/figdown.js +971 -169
- package/dist/figdown.mjs +971 -169
- package/examples/evpn-fabric.svg +3 -4
- package/examples/showcase/arp-resolution.svg +1 -1
- package/examples/showcase/ethernet-frame.svg +1 -1
- package/examples/showcase/l2-forwarding-logic.svg +9 -9
- package/examples/showcase/tcp-handshake.svg +1 -1
- package/examples/showcase/tcp-header.svg +1 -1
- package/examples/showcase/tcp-state-machine.svg +77 -55
- package/guide/expressing.md +30 -18
- package/guide/layout.md +19 -19
- package/guide/showcase.md +62 -56
- package/package.json +2 -2
- package/skill/figdown/SKILL.md +30 -4
- package/skill/figdown/figdown.html +1030 -194
- package/skill/figdown/reference/experimental/block.md +60 -0
- package/skill/figdown/reference/experimental/chart.md +32 -0
- package/skill/figdown/reference/experimental/flowchart.md +148 -20
- package/skill/figdown/reference/experimental/statechart.md +138 -0
- package/skill/figdown/reference/experimental/timing.md +1 -1
- package/skill/figdown/reference/experimental/topology.md +148 -22
- package/skill/figdown/reference/reading.md +25 -1
- package/skill/figdown/reference/scene.md +78 -10
- package/skill/figdown/reference/experimental/constructs.md +0 -90
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Genre `block` — markers and zones (EXPERIMENTAL)
|
|
2
|
+
|
|
3
|
+
`threshold` and `band` are **outside the v0.1 conformance surface and outside
|
|
4
|
+
the compatibility promise**. The engine accepts them and your document keeps
|
|
5
|
+
working, but they may change or be withdrawn in a later `0.x`. The parser
|
|
6
|
+
emits no warning, so a line that parses tells you nothing. Use them when the
|
|
7
|
+
figure genuinely needs them; if the figure must be portable, do not, and if
|
|
8
|
+
you use one anyway, say so beside the figure.
|
|
9
|
+
|
|
10
|
+
**Both belong to `block` alone.** They are declared by this genre and by no
|
|
11
|
+
other: writing either under `topology`, `flowchart` or `statechart` is a line
|
|
12
|
+
error that says so and gives the ground. `block` earns them because it is the
|
|
13
|
+
genre those figures are actually authored in; a state's box, a flowchart
|
|
14
|
+
stage's box and a device's box have no extent that means anything, so a line
|
|
15
|
+
drawn 60% down one asserts nothing a reader can read.
|
|
16
|
+
|
|
17
|
+
Load `../scene.md` first — this file adds two words to `block`'s vocabulary
|
|
18
|
+
and changes none of it.
|
|
19
|
+
|
|
20
|
+
```figdown
|
|
21
|
+
figdown 0.1 block
|
|
22
|
+
group pool "Storage pool"
|
|
23
|
+
node used "In use" in=pool
|
|
24
|
+
threshold "High watermark = stop writes" in=pool offset=80%
|
|
25
|
+
threshold "Low watermark = resume writes" in=pool offset=45%
|
|
26
|
+
band "Reserved" 15% in=pool fill=#fee2e2
|
|
27
|
+
band "Shared quota" 20..70% in=pool extend=down
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
- `threshold` needs a quoted label **and** `offset=<0..100>%`, both mandatory
|
|
31
|
+
— the `%` included. There is no `value=` and no `ref=`.
|
|
32
|
+
- `band` needs a quoted label **first**, then either one percentage (a size)
|
|
33
|
+
or an explicit `<a>..<b>%` range. `..` is the language's ONE range
|
|
34
|
+
separator; the hyphen form is a line error. `extend=up|down|left|right`, and `up`
|
|
35
|
+
is the default.
|
|
36
|
+
- Both attach to a node or a group via `in=`.
|
|
37
|
+
- **Attach at the scope the fact belongs to.** A limit shared by everything in
|
|
38
|
+
a group is one group-level marker; a fact true of one element attaches to
|
|
39
|
+
that element. The renderer may draw the two the same way — the difference is
|
|
40
|
+
in the text, and the text is the knowledge.
|
|
41
|
+
|
|
42
|
+
## The label is the knowledge, and `offset=` is not a value
|
|
43
|
+
|
|
44
|
+
`offset=` is a fraction of the target's **rendered extent** — where to paint
|
|
45
|
+
the line — **not a value of any quantity**. The target declares no scale, so
|
|
46
|
+
there is no conversion and nothing to convert. Put the number in the label or
|
|
47
|
+
it is not in the document.
|
|
48
|
+
|
|
49
|
+
**This is the trap, and it is worth naming.** In the domain these figures
|
|
50
|
+
usually come from, a threshold is a queue depth **with a numeric value**: an
|
|
51
|
+
active-queue-management minimum and maximum threshold (RFC 2309, RFC 7567)
|
|
52
|
+
is a number of packets or bytes. FigDown borrowed the word from exactly that
|
|
53
|
+
domain and did **not** borrow the attribute the domain defines it by. So
|
|
54
|
+
`threshold "Max cap" in=q offset=80%` invites a reader to take 80% as the
|
|
55
|
+
threshold value. It is a paint position. Write
|
|
56
|
+
`threshold "Max cap = 800 KB" in=q offset=80%` and the figure says what you
|
|
57
|
+
mean.
|
|
58
|
+
|
|
59
|
+
The same holds for `band`: a band is a range over that same scale-free
|
|
60
|
+
extent. Its label is the whole of what it asserts.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Charts from a table — `chart`, `type=` (EXPERIMENTAL)
|
|
2
|
+
|
|
3
|
+
Outside the v0.1 conformance surface and outside the compatibility promise:
|
|
4
|
+
the engine accepts it, but it may change or be withdrawn in a later `0.x`,
|
|
5
|
+
and the parser emits no warning. If the figure must be portable, keep the
|
|
6
|
+
table and drop the chart.
|
|
7
|
+
|
|
8
|
+
**`chart` is composition, not subject vocabulary.** It says nothing about
|
|
9
|
+
what the figure is *of*, so it is not one of the words a genre declares for
|
|
10
|
+
its own domain — it is legal wherever a `table` region is legal, which is the
|
|
11
|
+
`table` genre and every scene genre, and it means the same thing in all of
|
|
12
|
+
them.
|
|
13
|
+
|
|
14
|
+
```figdown
|
|
15
|
+
figdown 0.1 table
|
|
16
|
+
table t "Throughput"
|
|
17
|
+
| Port | Gbps |
|
|
18
|
+
|------|------|
|
|
19
|
+
| 1 | 25 |
|
|
20
|
+
| 2 | 40 |
|
|
21
|
+
chart t type=bar3d
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- `chart <table-id>` is the whole grammar. It draws from a `table` declared
|
|
25
|
+
in the same document and is defined by that reference, so the id must
|
|
26
|
+
already exist.
|
|
27
|
+
- `type=` is the only option key and `bar3d` is its only value.
|
|
28
|
+
- A scene document can carry both halves: open a `table` region inside it for
|
|
29
|
+
the numbers, then `chart` that id.
|
|
30
|
+
|
|
31
|
+
For anything a chart library would do better, keep the raster and put the
|
|
32
|
+
numbers in a table (`../transcribe.md`).
|
|
@@ -1,16 +1,39 @@
|
|
|
1
|
-
# Genre `flowchart` — EXPERIMENTAL
|
|
1
|
+
# Genre `flowchart` — EXPERIMENTAL
|
|
2
2
|
|
|
3
3
|
The genre itself is outside the v0.1 conformance surface: it may change or be
|
|
4
|
-
withdrawn in a later `0.x
|
|
4
|
+
withdrawn in a later `0.x` without a migration entry. A portable figure uses
|
|
5
|
+
`block` instead.
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
and adds the three role keywords below. `flow down` is the default here.
|
|
7
|
+
Use `flowchart` when the figure is a **procedure**: stages performed in
|
|
8
|
+
order, with branches. `flow down` is the default here.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
**This file is `flowchart`'s whole vocabulary.** Load it and `../layout.md`
|
|
11
|
+
and you can author in this genre; do not load another genre's file, because
|
|
12
|
+
another genre's declaration of a word is not authority for this one. In
|
|
13
|
+
particular this genre declares **no container**: there is no `group`, and
|
|
14
|
+
`in=` and `gap=` are **not this genre's option keys** — `in=` named a `group`
|
|
15
|
+
id and nothing else, so it went out with `group` rather than stay accepted with
|
|
16
|
+
no value that could resolve. Writing either is a line error that names the
|
|
17
|
+
withdrawal. Say what a container would have said with a `class`
|
|
18
|
+
whose label states it — it earns a legend entry and applies to every member at
|
|
19
|
+
once — or split the procedure into two figures joined by `external` endpoints.
|
|
20
|
+
|
|
21
|
+
**Under `figdown 0.2` the connector is `flowline`, not `edge`** — the word the
|
|
22
|
+
flowchart domain commonly uses for the symbol ISO 5807 §9.3.1 names *Line*.
|
|
23
|
+
Same operators, same labels, same option keys, same model; only the word
|
|
24
|
+
changed.
|
|
25
|
+
|
|
26
|
+
**The spelling is gated by the version you declare.** Under
|
|
27
|
+
`figdown 0.1 flowchart`, `edge` is still the word and `flowline` is a line
|
|
28
|
+
error naming the version; under `figdown 0.2 flowchart` it is the other way
|
|
29
|
+
round. Each version accepts exactly one spelling — two in one version would be
|
|
30
|
+
an alias. A document that writes `flowline` must declare `figdown 0.2`, and
|
|
31
|
+
`edge` under 0.1 stays legal until v1.0.
|
|
32
|
+
|
|
33
|
+
## Three role keywords, and when to write `node` instead
|
|
11
34
|
|
|
12
35
|
```figdown
|
|
13
|
-
figdown 0.
|
|
36
|
+
figdown 0.2 flowchart
|
|
14
37
|
flow down
|
|
15
38
|
terminator start "Request received"
|
|
16
39
|
process parse "Parse body"
|
|
@@ -19,13 +42,13 @@ process apply "Apply change"
|
|
|
19
42
|
process reject "Reject"
|
|
20
43
|
terminator done "Response sent"
|
|
21
44
|
node log "Audit store" shape=cylinder
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
45
|
+
flowline start -> parse
|
|
46
|
+
flowline parse -> valid
|
|
47
|
+
flowline valid -[yes]-> apply
|
|
48
|
+
flowline valid -[no]-> reject
|
|
49
|
+
flowline apply -> done
|
|
50
|
+
flowline reject -> log
|
|
51
|
+
flowline log -> parse
|
|
29
52
|
decision kind "Change kind?" shape=ellipse
|
|
30
53
|
```
|
|
31
54
|
|
|
@@ -44,13 +67,118 @@ wrong roughly one time in five.
|
|
|
44
67
|
model still records the role. That is the escape hatch for matching a source
|
|
45
68
|
drawing without lying about what the step is.
|
|
46
69
|
|
|
47
|
-
**
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
70
|
+
**Prefer a role. `node` is the fallback, not the default.** Reach for
|
|
71
|
+
`process`, `decision` or `terminator` first, and write `node` only when **the
|
|
72
|
+
source does not state which** the stage is.
|
|
73
|
+
|
|
74
|
+
That is what a bare `node` says here, and it is all it says: *the source does
|
|
75
|
+
not state the role.* ISO 5807 is a standard for **drawing** flowcharts, so it
|
|
76
|
+
has no "unclassified" — the person with the pen must draw some symbol, and
|
|
77
|
+
every drawn stage therefore has a classification. FigDown separates role from
|
|
78
|
+
geometry, so it can record the absence instead of inventing a role. A
|
|
79
|
+
transcriber who genuinely cannot tell a Process from a Predefined process
|
|
80
|
+
writes `node`, and that is the honest line.
|
|
81
|
+
|
|
82
|
+
**`node` is NOT the spelling for "an ISO symbol FigDown has not implemented."**
|
|
83
|
+
Nine ISO stage symbols have no word in this genre — Data (input/output),
|
|
84
|
+
Stored data, Predefined process, Preparation, Manual operation, Manual input,
|
|
85
|
+
Document, Parallel mode, Loop limit. That is a **gap in FigDown**, not a fact
|
|
86
|
+
about your figure, and writing a bare `node` for one of them files the gap as
|
|
87
|
+
if it were your judgement. When your source states a role this genre cannot
|
|
88
|
+
spell:
|
|
89
|
+
|
|
90
|
+
- write `node` — `process` would be a false claim, and nothing in the figure
|
|
91
|
+
could catch it;
|
|
92
|
+
- **name the ISO symbol in a comment** on the same line, so the classification
|
|
93
|
+
survives as text a reader can quote (a comment is never parsed, and never a
|
|
94
|
+
second semantic channel);
|
|
95
|
+
- report the gap, so it can be counted and closed.
|
|
96
|
+
|
|
97
|
+
```figdown
|
|
98
|
+
node cfg "Read config file" # ISO 5807 Data (input/output) — no FigDown role
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
So do not "upgrade" a `node` to `process` to make it look decided — and do not
|
|
102
|
+
write `node` because deciding was work. Those are different acts with the same
|
|
103
|
+
spelling, and only you know which one you did.
|
|
51
104
|
|
|
52
105
|
**Label every exit from a `decision`.** Use the on-line label form
|
|
53
|
-
(`
|
|
54
|
-
the reader has to guess at.
|
|
106
|
+
(`flowline d -[yes]-> x`) or an endpoint label; an unlabelled branch is a
|
|
107
|
+
figure the reader has to guess at.
|
|
55
108
|
|
|
56
109
|
**There is no loop keyword.** A plain back-edge *is* the loop.
|
|
110
|
+
|
|
111
|
+
## `external` — the boundary, which is not the `terminator`
|
|
112
|
+
|
|
113
|
+
```figdown
|
|
114
|
+
figdown 0.2 flowchart
|
|
115
|
+
flow down
|
|
116
|
+
external ingress "Frame arrives on a port"
|
|
117
|
+
terminator start "Begin lookup"
|
|
118
|
+
process lookup "Look up destination"
|
|
119
|
+
external egress "Frame leaves the switch"
|
|
120
|
+
flowline ingress -> start
|
|
121
|
+
flowline start -> lookup
|
|
122
|
+
flowline lookup -> egress
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
`external` is an **out-of-figure endpoint**: the procedure connects to it and
|
|
126
|
+
this figure does not describe it. It is **never drawn** — the flowline simply
|
|
127
|
+
ends open — and it takes **no option key at all**. `terminator` is the
|
|
128
|
+
opposite: a drawn stage of this procedure, its start or its end.
|
|
129
|
+
|
|
130
|
+
So the question to ask is *whose* start it is. The first box of **this**
|
|
131
|
+
procedure is a `terminator`. A step that belongs to some other procedure, or
|
|
132
|
+
to the world outside the figure, is an `external`.
|
|
133
|
+
|
|
134
|
+
ISO 5807 §9.4.2 names this concept — its **Terminator** symbol is "an exit
|
|
135
|
+
to, or an entry from, the outside world" — and this genre already spells that
|
|
136
|
+
word `terminator` for the drawn start/end symbol, so the ISO term is taken
|
|
137
|
+
and `external` keeps FigDown's own spelling. Note what follows: ISO has no
|
|
138
|
+
word at all for a boundary that is *never drawn*, which is what `external`
|
|
139
|
+
is. The spelling is FigDown's, not ISO's, and this file is the only place
|
|
140
|
+
that says so.
|
|
141
|
+
|
|
142
|
+
## Presentation, layout intent and quoting
|
|
143
|
+
|
|
144
|
+
`flow` takes `flow right|down|left|up` — one of the four, once per document,
|
|
145
|
+
before the stages. `flow down` is this genre's default. `rank a,b,c` pulls
|
|
146
|
+
peers onto one row or column: ONE comma-delimited token, no spaces.
|
|
147
|
+
|
|
148
|
+
Values from a fixed list are written **bare**, never quoted: `shape=box`,
|
|
149
|
+
`style=dashed`, `flow down`. So are ids. Labels always take quotes.
|
|
150
|
+
|
|
151
|
+
`shape=` is pure geometry — `shape=box` (the default), `shape=rounded`,
|
|
152
|
+
`shape=circle`, `shape=ellipse`, `shape=diamond`, `shape=cylinder`, and
|
|
153
|
+
nothing else. `style=` takes `style=solid`, `style=dashed` or `style=dotted`.
|
|
154
|
+
|
|
155
|
+
`class` declares what a colour **means**, and colour that means something
|
|
156
|
+
must be a `class`:
|
|
157
|
+
|
|
158
|
+
```figdown
|
|
159
|
+
figdown 0.2 flowchart
|
|
160
|
+
class yes "Yes path" stroke=#16a34a
|
|
161
|
+
class no "No path" stroke=#dc2626
|
|
162
|
+
decision check "Valid?"
|
|
163
|
+
process accept "Accept"
|
|
164
|
+
process reject "Reject"
|
|
165
|
+
flowline check -> accept class=yes
|
|
166
|
+
flowline check -> reject class=no
|
|
167
|
+
```
|
|
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.
|
|
173
|
+
|
|
174
|
+
The connector's operators are `->`, `<-`, `--` and `<->`. In a procedure you
|
|
175
|
+
almost always want `->`: a step follows another step in one direction, and an
|
|
176
|
+
undirected or two-way flowline asserts an order the reader cannot recover.
|
|
177
|
+
|
|
178
|
+
Endpoint labels nest (`flowline a [retry 1] -- b`); quote them when they hold
|
|
179
|
+
a line break or an unbalanced bracket. A `#` inside a bracket label is
|
|
180
|
+
ordinary text and needs no quotes, because `[ ]` is a verbatim region.
|
|
181
|
+
|
|
182
|
+
Under `figdown 0.3` any of these lines may carry `note=`, a drawn aside in
|
|
183
|
+
prose: `process parse "Parse body" note="…"`. It is never parsable and never
|
|
184
|
+
where a structural fact lives.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Genre `statechart` — EXPERIMENTAL
|
|
2
|
+
|
|
3
|
+
The genre itself is outside the conformance surface: it may change or be
|
|
4
|
+
**withdrawn** in a later `0.x` without a migration. A portable figure uses
|
|
5
|
+
`block` instead — that is what these figures were spelled as before `figdown
|
|
6
|
+
0.2`, and the rewrite back is one line.
|
|
7
|
+
|
|
8
|
+
**It needs `figdown 0.2` on line 1.** `figdown 0.1 statechart` is a line
|
|
9
|
+
error, and a deliberately named one: `genre "statechart" requires figdown 0.2`.
|
|
10
|
+
An engine may not read a `0.1` document as though it were `0.2`.
|
|
11
|
+
|
|
12
|
+
## The vocabulary, which is two words
|
|
13
|
+
|
|
14
|
+
**This file is `statechart`'s whole vocabulary.** Load it and `../layout.md`
|
|
15
|
+
and you can author in this genre; do not load another genre's file, because
|
|
16
|
+
another genre's declaration of a word is not authority for this one.
|
|
17
|
+
|
|
18
|
+
This genre declares **two** words of its own — a node is a **`state`** and a
|
|
19
|
+
connector is a **`transition`**, both taken from OMG UML 2.5.1 §14 — and
|
|
20
|
+
**that is the entire list**. It names no container, no boundary, no marker,
|
|
21
|
+
no band and no bundle. Writing one of those here is a line error that states
|
|
22
|
+
the ground rather than guessing at a spelling, and `node` or `edge` here is a
|
|
23
|
+
line error naming the word to write instead.
|
|
24
|
+
|
|
25
|
+
Three more words are legal because they are not about states at all:
|
|
26
|
+
`class` (what a colour means), `flow` and `rank` (layout intent). Nothing in
|
|
27
|
+
UML competes for them.
|
|
28
|
+
|
|
29
|
+
Two consequences worth stating, because an author arriving from another genre
|
|
30
|
+
will reach for both:
|
|
31
|
+
|
|
32
|
+
- **There is no grouping construct.** `in=` and `gap=` are **not this genre's
|
|
33
|
+
option keys** — writing either is a line error that names the withdrawal.
|
|
34
|
+
A composite state, a region and a history are things this genre cannot
|
|
35
|
+
express; a `class` can say two states share a mode, and that is a different
|
|
36
|
+
and weaker claim. Do not fake a superstate. **`in=`'s spelling is RESERVED
|
|
37
|
+
here**: if composite states are ever earned, they arrive as nesting on
|
|
38
|
+
`state` through this exact key, with a `state` id as its value (UML 2.5.1
|
|
39
|
+
§14.2.3.4) — which is why the key was withdrawn rather than left pointing at
|
|
40
|
+
a container.
|
|
41
|
+
- **There is no out-of-figure endpoint.** A transition to something the
|
|
42
|
+
figure does not describe has no spelling. Draw the state, or leave the
|
|
43
|
+
transition out and say so in the prose beside the figure.
|
|
44
|
+
|
|
45
|
+
**`external` in particular is not available, and it is reserved.** UML 2.5.1
|
|
46
|
+
§14 already defines `TransitionKind` as `external | internal | local`, where
|
|
47
|
+
an *external* transition is one that exits and re-enters its source state,
|
|
48
|
+
firing its exit and entry behaviours. That is a defined term of art in this
|
|
49
|
+
genre's own source standard. If `external` ever appears in `statechart` it
|
|
50
|
+
will mean what UML means by it, never "an endpoint outside the figure".
|
|
51
|
+
|
|
52
|
+
`flow right` is the default, as in `block`; `flowchart`'s `down` default does
|
|
53
|
+
**not** apply here.
|
|
54
|
+
|
|
55
|
+
**Why this genre loses `node` and `flowchart` keeps it:** a statechart has
|
|
56
|
+
exactly one kind of node, so there is nothing to leave unstated and `state`
|
|
57
|
+
gives up nothing. A flowchart stage can have a role **the source does not
|
|
58
|
+
state**, and there `node` is the only way to say so without asserting a role
|
|
59
|
+
the source never gave.
|
|
60
|
+
|
|
61
|
+
```figdown
|
|
62
|
+
figdown 0.2 statechart
|
|
63
|
+
title "Turnstile"
|
|
64
|
+
class mode "A mode of the mechanism" fill=#e0e7ff
|
|
65
|
+
state locked "LOCKED" class=mode
|
|
66
|
+
state unlocked "UNLOCKED" class=mode
|
|
67
|
+
transition locked -[coin]-> unlocked
|
|
68
|
+
transition unlocked -[push]-> locked
|
|
69
|
+
transition locked -[push]-> locked # self-transition: the event happens
|
|
70
|
+
# and the machine stays
|
|
71
|
+
flow right
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`flow` takes `flow right|down|left|up` — one of the four, once per document.
|
|
75
|
+
`rank a,b` pulls peers onto one row or column: ONE comma-delimited token, no
|
|
76
|
+
spaces. Values from a fixed list are bare (`shape=box`, `style=dashed`,
|
|
77
|
+
`flow right`); labels always take quotes.
|
|
78
|
+
|
|
79
|
+
`shape=` is pure geometry and changes only the drawing — `shape=box` (the
|
|
80
|
+
default), `shape=rounded`, `shape=circle`, `shape=ellipse`, `shape=diamond`,
|
|
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
|
|
85
|
+
prose — never parsable, never where a structural fact lives.
|
|
86
|
+
|
|
87
|
+
## What the genre adds, which is a reading and not a syntax
|
|
88
|
+
|
|
89
|
+
Everything above parses identically under `block`. The genre earns its
|
|
90
|
+
existence in what you are entitled to conclude from it.
|
|
91
|
+
|
|
92
|
+
**Under `statechart`, and not under `flowchart` or `block`:**
|
|
93
|
+
|
|
94
|
+
- **Every top-level `state` is a state** — a *mode the machine is in*, not a
|
|
95
|
+
step it performs. It has duration; the machine sits in it until something
|
|
96
|
+
happens.
|
|
97
|
+
- **Every `transition` is a transition**, and its direction is the direction of the
|
|
98
|
+
change. An undirected `--` between two states asserts a relationship the
|
|
99
|
+
genre has no reading for; do not read it as a transition in both directions.
|
|
100
|
+
- **A mid label is a transition inscription** — the trigger, and optionally a
|
|
101
|
+
guard and an effect — as free text. There is no structure in it. Quote it,
|
|
102
|
+
attribute it to its edge, and stop; you may not parse `event / action` into
|
|
103
|
+
fields, because nothing in the language promises that shape.
|
|
104
|
+
- **A self-loop is "the event occurs and the machine stays"**, which is a
|
|
105
|
+
fact about the machine. Under `flowchart` the same drawing is a *poll* —
|
|
106
|
+
"check again" — and that is a different claim entirely.
|
|
107
|
+
- **The set of states is closed.** The nodes are all the modes the figure
|
|
108
|
+
asserts; a state not drawn is not asserted to exist.
|
|
109
|
+
|
|
110
|
+
**Still not conclusible, and the list is the same as everywhere else:**
|
|
111
|
+
|
|
112
|
+
- **No current state.** Nothing in a figure says which state the machine is
|
|
113
|
+
in now. A fill colour does not, a `class` does not, position does not.
|
|
114
|
+
- **No initial and no final state.** The language has no vocabulary for
|
|
115
|
+
either at `figdown 0.2` — deliberately, pending evidence, and **no `start`
|
|
116
|
+
keyword was added**: ISO's terminator symbol is *both* ends distinguished by
|
|
117
|
+
its label, so there is no word to borrow, and a reader who lacks one answers
|
|
118
|
+
"unstated" rather than answering wrongly. A state with no incoming
|
|
119
|
+
transition is *drawn* that way; it is not *declared* initial, and reading it
|
|
120
|
+
as initial is inventing a fact.
|
|
121
|
+
- **No ordering among transitions.** Peer edges have no sequence, and an
|
|
122
|
+
ordinal in a label is naming, not order.
|
|
123
|
+
- **No hierarchy, no regions, no history.** There is no grouping construct to
|
|
124
|
+
misuse for one.
|
|
125
|
+
- **Nothing from the layout zone.** `pin` is arrangement for humans; skip it.
|
|
126
|
+
|
|
127
|
+
**Reclassifying costs more than one line now.** Changing `flowchart` to
|
|
128
|
+
`statechart` on line 1 no longer suffices: every `flowline` becomes a
|
|
129
|
+
`transition` and every `node` a `state`. Run `tools/migrate-figdown.js` — it
|
|
130
|
+
rewrites both, scoped by the header genre.
|
|
131
|
+
|
|
132
|
+
**Do not upgrade a `flowchart` to a `statechart` on structure.** It was
|
|
133
|
+
measured: cycles do not separate the two (of the state machines and the
|
|
134
|
+
flowcharts in this project's own corpus, both are usually cyclic), and
|
|
135
|
+
self-loops appear in almost none. A retry loop drawn as a flowchart is exactly
|
|
136
|
+
the figure that reads wrong as a statechart. **Only the declared genre says
|
|
137
|
+
which it is** — and a title that contains the words "state machine" does not,
|
|
138
|
+
because a polling flowchart is routinely titled that way.
|
|
@@ -1,38 +1,164 @@
|
|
|
1
|
-
# Genre `topology` — EXPERIMENTAL
|
|
1
|
+
# Genre `topology` — EXPERIMENTAL
|
|
2
2
|
|
|
3
3
|
The genre itself is outside the v0.1 conformance surface: it may change or be
|
|
4
|
-
withdrawn in a later `0.x
|
|
5
|
-
|
|
6
|
-
the compatibility promise.
|
|
4
|
+
withdrawn in a later `0.x` without a migration entry. A portable figure uses
|
|
5
|
+
`block` instead, which is inside the compatibility promise.
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
intent
|
|
7
|
+
Use `topology` when the figure is a **network of devices and the links
|
|
8
|
+
between them** — fabrics, overlays, access layers, peering diagrams. The
|
|
9
|
+
nodes are devices or endpoints and the edges are physical or logical links,
|
|
10
|
+
not dataflow steps. That intent is what the genre carries; it matters to a
|
|
11
|
+
reader and to nothing else.
|
|
12
|
+
|
|
13
|
+
**This file is `topology`'s whole vocabulary.** Load it and `../layout.md`
|
|
14
|
+
and you can author in this genre; do not load another genre's file, because
|
|
15
|
+
another genre's declaration of a word is not authority for this one. Words
|
|
16
|
+
`topology` does **not** declare — and there are several a `block` author
|
|
17
|
+
would reach for — are line errors that say so and give the ground.
|
|
18
|
+
|
|
19
|
+
## The vocabulary, in one figure
|
|
12
20
|
|
|
13
21
|
```figdown
|
|
14
22
|
figdown 0.1 topology
|
|
15
23
|
title "Leaf-spine fabric"
|
|
16
|
-
|
|
24
|
+
|
|
25
|
+
flow right # reading direction; ONE per document,
|
|
26
|
+
# before the nodes
|
|
27
|
+
|
|
17
28
|
node s1 "Spine 1"
|
|
18
29
|
node s2 "Spine 2"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
node
|
|
22
|
-
|
|
23
|
-
|
|
30
|
+
|
|
31
|
+
group pod "Pod A" gap=0 # a container; gap=0 packs its members
|
|
32
|
+
node l1 "Leaf 1" in=pod # flush against each other. The id is
|
|
33
|
+
node l2 "Leaf 2" in=pod # required and exists only so other lines
|
|
34
|
+
# can name it
|
|
35
|
+
|
|
36
|
+
node fw "Firewall" shape=rounded
|
|
37
|
+
node store "Config store" shape=cylinder style=solid
|
|
38
|
+
|
|
39
|
+
external wan "To WAN" # outside the figure. NEVER drawn as a
|
|
40
|
+
# shape — the link simply ends open there
|
|
41
|
+
|
|
42
|
+
edge l1 -- s1 # ops: -> <- -- <->
|
|
24
43
|
edge l1 -- s2
|
|
25
44
|
edge l2 -- s1
|
|
26
45
|
edge l2 -- s2
|
|
27
|
-
edge s1
|
|
28
|
-
|
|
46
|
+
edge s1 -> wan # arrow points at `wan`
|
|
47
|
+
edge wan <- s2
|
|
48
|
+
edge fw <-> store
|
|
49
|
+
edge l1 -[lacp]-> fw # on-line label splits the operator
|
|
50
|
+
edge l2 [ge-0/0/1] -- [xe-0/0/0] fw # endpoint labels: ports, roles
|
|
51
|
+
edge s1 -- s2 style=dotted # spines not cabled to each other
|
|
52
|
+
|
|
53
|
+
rank l1,l2 # pull peers onto one row/column. ONE
|
|
54
|
+
# comma-delimited token, no spaces
|
|
55
|
+
|
|
56
|
+
class uplink "Uplink, 40G" stroke=#0284c7
|
|
29
57
|
edge l2 -- s2 class=uplink
|
|
58
|
+
|
|
59
|
+
bundle lag1 "LAG to the leaf pair" l1--s1,l2--s1
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`flow` takes `flow right|down|left|up` — one of the four, once per document.
|
|
63
|
+
|
|
64
|
+
Values from a fixed list are written **bare**, never quoted: `shape=box`,
|
|
65
|
+
`style=dashed`, `flow down`, `gap=0`. So are ids. Labels are the opposite
|
|
66
|
+
and always take quotes.
|
|
67
|
+
|
|
68
|
+
`shape=` is **pure geometry, no domain nouns** — `shape=box` (the default),
|
|
69
|
+
`shape=rounded`, `shape=circle`, `shape=ellipse`, `shape=diamond`,
|
|
70
|
+
`shape=cylinder`, and nothing else. There is no router symbol, no switch
|
|
71
|
+
symbol and no cloud: a cloud in a source drawing is an ellipse or a group,
|
|
72
|
+
with what it *is* — "the internet", "the transit provider" — written in the
|
|
73
|
+
label. `style=` takes `style=solid`, `style=dashed` or `style=dotted`.
|
|
74
|
+
|
|
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.
|
|
80
|
+
|
|
81
|
+
Endpoint labels nest (`edge a [xe-0/0/0:1] -- b`); quote them when they hold
|
|
82
|
+
a line break or an unbalanced bracket (`edge a ["slot\n1/1"] -- b`). A `#`
|
|
83
|
+
inside a bracket label is ordinary text and needs no quotes —
|
|
84
|
+
`edge a -[hop #1]-> b` — because `[ ]` is a verbatim region.
|
|
85
|
+
|
|
86
|
+
Under `figdown 0.3` any of these lines may carry `note=`, a drawn aside in
|
|
87
|
+
prose: `node s1 "Spine 1" note="…"`, `edge l1 -- s1 note="…"`,
|
|
88
|
+
`title "Fabric" note="…"`. It is never parsable and never where a structural
|
|
89
|
+
fact lives.
|
|
90
|
+
|
|
91
|
+
## `group` is not a multicast group
|
|
92
|
+
|
|
93
|
+
`group` here is a **container**: a box drawn round its members, one nesting
|
|
94
|
+
level deep — a pod, a rack, a site, a tenant. It is not IGMP or MLD
|
|
95
|
+
membership, and `group g "224.0.0.5"` does not say what a reader of that
|
|
96
|
+
address expects.
|
|
97
|
+
|
|
98
|
+
The spelling stays anyway, because in this domain every synonym is more
|
|
99
|
+
taken than the word is: `zone` belongs to DNS and to firewalls, `cluster` to
|
|
100
|
+
route reflection (RFC 4456), `domain` to inter-domain traffic engineering
|
|
101
|
+
(RFC 7926), `area` to OSPF, `site` to EVPN. Trading a soft collision for a
|
|
102
|
+
hard one is a bad trade — and this collision **is** soft, because the drawing
|
|
103
|
+
contradicts the wrong reading: a multicast group is never drawn as a box
|
|
104
|
+
round its members.
|
|
105
|
+
|
|
106
|
+
## `external` is not an external route
|
|
107
|
+
|
|
108
|
+
`external` is an **out-of-figure endpoint**: something this figure talks to
|
|
109
|
+
but does not describe. It is never drawn, it takes **no option key at all**,
|
|
110
|
+
and the link to it simply ends open.
|
|
111
|
+
|
|
112
|
+
It is not an external route — not an OSPF Type 5 or Type 7 LSA, not an eBGP
|
|
113
|
+
peer, not "the external interface". Same soft collision, same reason for
|
|
114
|
+
keeping the spelling: an `external` is never drawn at all, so a reader who
|
|
115
|
+
starts with the routing sense finds nothing on the page to sustain it. Where
|
|
116
|
+
the figure means *the router that faces outside*, that router is a `node`
|
|
117
|
+
with a label saying so; `external` is for what the figure leaves out.
|
|
118
|
+
|
|
119
|
+
## `bundle` — a LAG, an ECMP set, an Ethernet Segment
|
|
120
|
+
|
|
121
|
+
```figdown
|
|
122
|
+
figdown 0.1 topology
|
|
123
|
+
node leaf "Leaf"
|
|
124
|
+
node s1 "Spine 1"
|
|
125
|
+
node s2 "Spine 2"
|
|
126
|
+
edge leaf -- s1
|
|
127
|
+
edge leaf -- s2
|
|
128
|
+
bundle ecmp "ECMP uplink set, 2 × 100G" leaf--s1,leaf--s2
|
|
30
129
|
```
|
|
31
130
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
131
|
+
A **link bundle**: a set of parallel links between the same pair of devices
|
|
132
|
+
operated as one logical link. Its referents are the ones this domain already
|
|
133
|
+
names — a link aggregation group (IEEE 802.1AX), an equal-cost multipath
|
|
134
|
+
set, an EVPN Ethernet Segment — and the ring drawn round the member links is
|
|
135
|
+
the same thing the domain means. The domain reading and the drawn reading
|
|
136
|
+
are one reading; this is the cell where the word and the referent agree, and
|
|
137
|
+
it is why `topology` declares `bundle` and the general-purpose genre has no
|
|
138
|
+
use for it.
|
|
139
|
+
|
|
140
|
+
`bundle` is EXPERIMENTAL even inside this experimental genre. It is spelled
|
|
141
|
+
`bundle` and not after the standard's own noun deliberately: *aggregation*
|
|
142
|
+
is right for a link aggregation group and false for an equal-cost multipath
|
|
143
|
+
set and for an Ethernet Segment, so the standard's word cannot be taken
|
|
144
|
+
whole and an umbrella spelling is the honest one.
|
|
145
|
+
|
|
146
|
+
- The member list is ONE comma-delimited token, no spaces.
|
|
147
|
+
- Each member must name an edge that **already exists** and is unambiguous.
|
|
148
|
+
There is no way to address one of two parallel edges between the same
|
|
149
|
+
pair, so a bundle over parallel links cannot be spelled — declare the
|
|
150
|
+
members as distinct edges to distinct peers, as above.
|
|
151
|
+
- `bundle` takes `fill=`, `stroke=` and `style=`; the dashed ring is drawn
|
|
152
|
+
for you.
|
|
153
|
+
|
|
154
|
+
## Two mistakes this genre invites
|
|
155
|
+
|
|
156
|
+
**A shared medium is not a star.** Flattening a bus, a broadcast segment, a
|
|
157
|
+
shared VLAN or a fabric's underlay into point-to-point links changes what the
|
|
158
|
+
figure asserts: the shared thing reaches every participant at once. Model it
|
|
159
|
+
as one intermediate `node` that fans out.
|
|
35
160
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
161
|
+
**Geography is not carried by the layout zone.** If where a device sits is
|
|
162
|
+
part of the claim — a site, a rack, a country — say it with a `group` and a
|
|
163
|
+
label. Delete every `pin` and the figure must still be the same figure
|
|
164
|
+
(`../layout.md`).
|