umlimator 0.10.0 → 0.12.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/README.md +91 -11
- package/lib/umlimator.d.ts +143 -1
- package/lib/umlimator.js +1070 -100
- package/lib/umlimator.schema.json +1139 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -7,22 +7,36 @@ that writes a self-contained HTML page and still pictures (SVG, PNG) for documen
|
|
|
7
7
|
|
|
8
8
|

|
|
9
9
|
|
|
10
|
-
**Examples:** [live on GitHub Pages](https://zintaen.github.io/umlimator/),
|
|
10
|
+
**Examples:** [live on GitHub Pages](https://zintaen.github.io/umlimator/), a [playground](https://zintaen.github.io/umlimator/examples/playground.html)
|
|
11
|
+
to try a model in, and [what each one shows](examples/README.md): a C4-style
|
|
11
12
|
drill-down, a data pipeline, an AI agent's skills, and host pages for embedding, live updates and editing.
|
|
12
13
|
|
|
13
14
|
## What it does
|
|
14
15
|
|
|
15
16
|
- **Layers**: a view per level (system, containers, components, flows). A stacked card opens its inner view, which the
|
|
16
17
|
host may load only when asked.
|
|
17
|
-
- **
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
- **Unfolding in place**: a stacked card can also open into a box on the map it is on (E, or Alt + click), its inner
|
|
19
|
+
view's cards inside and the lines to it moved onto them, the rest of the picture in its order.
|
|
20
|
+
- **Layout and routing**: columns in reading order, each ordered so the lines cross as little as they can, those that
|
|
21
|
+
skip columns included; each card level with the cards its lines come from, so lines run straight; orthogonal lines
|
|
22
|
+
that never run through a card, room for every label, containers kept apart, and cards with no lines in a row of their
|
|
23
|
+
own, under the view or at the bottom of their box. The same model gives the same picture.
|
|
20
24
|
- **Reading**: animated flow, neighbours lit on selection, numbered steps, tours, minimap, light and dark themes.
|
|
25
|
+
- **Exploring**: every path between two cards, or everything a card reaches, lit on the map; a view in plain sentences
|
|
26
|
+
(`describe()`); a tour along any path the host names.
|
|
27
|
+
- **Live data**: marks over the map without touching the model (`overlay()`): flow as fast as the traffic, errors that
|
|
28
|
+
pulse, slow hops that glow, labels and tabs; and an OpenTelemetry trace replayed along its lines (`replay()`).
|
|
29
|
+
- **Stories**: walk-throughs in the model, step by step (view, camera, selection, highlight, tour and a caption), played
|
|
30
|
+
on the map (`play()`) or from the page's Stories menu, recorded from the page, and written as an animated PNG.
|
|
21
31
|
- **Keyboard and screen readers**: cards, then lines, in the Tab order (a card's tabs and chips too, for a host that
|
|
22
32
|
listens for click); arrows between cards; selections announced.
|
|
23
33
|
- **Editing** (opt-in): gestures emit `change` events; the host applies them and calls `update()`.
|
|
24
34
|
- **Export**: any view as a stand-alone SVG or PNG, in the browser or from the CLI.
|
|
25
35
|
- **A layout check**: crossings, shared lines, detours, labels on lines, text that overflows its card.
|
|
36
|
+
- **Rules**: what the model says must hold ("apps never call a database directly", "no cycles between teams' boxes"),
|
|
37
|
+
marked on the map where it breaks; `umlimator.py check` fails on a broken rule, so CI does.
|
|
38
|
+
- **Change**: what a pull request changes, marked on the map and said in words (with a GitHub Action that posts it);
|
|
39
|
+
a time-lapse of a model's history, where cards glide, fade in and fade out; and drift, the map against the traffic seen.
|
|
26
40
|
|
|
27
41
|
## Install
|
|
28
42
|
|
|
@@ -30,7 +44,7 @@ drill-down, a data pipeline, an AI agent's skills, and host pages for embedding,
|
|
|
30
44
|
npm install umlimator
|
|
31
45
|
```
|
|
32
46
|
|
|
33
|
-
Or from GitHub, at a tag or any commit: `"umlimator": "github:zintaen/umlimator#v0.
|
|
47
|
+
Or from GitHub, at a tag or any commit: `"umlimator": "github:zintaen/umlimator#v0.12.0"`. npm 12 refuses git
|
|
34
48
|
dependencies unless the project opts in, so that also needs `allow-git=root` in the `.npmrc` next to `package.json`.
|
|
35
49
|
|
|
36
50
|
## Embed
|
|
@@ -61,11 +75,21 @@ function MapView({ model, onSelect }) {
|
|
|
61
75
|
```
|
|
62
76
|
|
|
63
77
|
- `render` draws one view at a time into a shadow root (give the element a height), with pan, zoom and drill-down.
|
|
64
|
-
Events (`click`, `select`, `open`, `viewchange`, `change`) name what they are about by ids from the model.
|
|
78
|
+
Events (`click`, `select`, `open`, `viewchange`, `change`, `expand`) name what they are about by ids from the model.
|
|
79
|
+
- `map.expand(id)` unfolds a stacked card in place and `map.collapse(id)` folds it; `layout(model, view, { expand })`
|
|
80
|
+
draws the same in Node.
|
|
65
81
|
- Colours are `--um-*` CSS variables, fonts are the host's (`--um-sans`, `--um-mono`), text is measured in that font,
|
|
66
82
|
and nothing is fetched.
|
|
67
|
-
- `layout(model, viewId)` returns a view's geometry without a DOM, in Node too
|
|
83
|
+
- `layout(model, viewId)` returns a view's geometry without a DOM, in Node too; `check(model, viewId)` runs the layout
|
|
84
|
+
check on it, and `validate(model)` finds dangling or repeated ids before anything is drawn. `rules(model)` lists every
|
|
85
|
+
rule the model breaks, view by view.
|
|
86
|
+
- `map.overlay(name, layer)`, `highlight(refs)`, `tour(path)` and `replay(spans)` put the host's marks, a tour and a
|
|
87
|
+
trace on the map; `paths()`, `reach()` and `describe()` walk a view and put it in words, in Node too.
|
|
68
88
|
- `editable: true` turns on editing gestures ([docs/editing.md](docs/editing.md); `examples/edit.html` is a working host).
|
|
89
|
+
- `diff(before, after)` returns `after` with each card and line marked added, changed or removed, what changed in words,
|
|
90
|
+
and the views that show it; `drift(model, observed)` marks the lines traffic ran on that nobody drew, and the drawn ones
|
|
91
|
+
that carried nothing. Both are models to draw, in Node too. `update()` eases into the next model (`examples/timelapse.html`);
|
|
92
|
+
the option `ease: false` draws it at once.
|
|
69
93
|
- `mountPage` is the whole standalone viewer that the CLI writes.
|
|
70
94
|
|
|
71
95
|
The API, its types and the decisions behind it: [docs/module-api.md](docs/module-api.md) and `lib/umlimator.d.ts`.
|
|
@@ -75,6 +99,8 @@ The API, its types and the decisions behind it: [docs/module-api.md](docs/module
|
|
|
75
99
|
A model has shared `nodes` and `edges`, and `views` that each show a subset, with optional `containers` (boxes),
|
|
76
100
|
`layout` (`[col, row]` per card), `render: "sequence"` for numbered run-order views and `tour` for a dot that rides a
|
|
77
101
|
path. The full schema is `engine/references/schema.md` (§ Map model); `examples/bookshop.json` uses most of it.
|
|
102
|
+
A model file that starts with `"$schema": "<path to>/umlimator.schema.json"` (exported as `umlimator/schema.json`)
|
|
103
|
+
gets completion and checks in editors, and `validate(model)` lists its errors and warnings, each with where it is.
|
|
78
104
|
|
|
79
105
|
Card kinds: `frontend`, `backend`, `ai`, `database`, `queue`, `security`, `cloud`, `external` and `file` (skill-map
|
|
80
106
|
kinds such as `public`, `lane`, `script`, `hook` and `board` work too). Fields beyond the schema:
|
|
@@ -91,12 +117,16 @@ kinds such as `public`, `lane`, `script`, `hook` and `board` work too). Fields b
|
|
|
91
117
|
| edge | `sublabel` | a second, smaller line under the label |
|
|
92
118
|
| edge | `fromSide`, `toSide` | the card sides the line uses |
|
|
93
119
|
| edge | `from`, `to` | may name a container of the view: the line ends on its box |
|
|
120
|
+
| edge | `style: "faded"` | the line in its kind's colour, faint and with no flow (drift's idle lines) |
|
|
121
|
+
| edge | `drift` | what `drift()` found: `undrawn` or `idle` |
|
|
94
122
|
| view | `gap`, `rgap` | the space between columns and between rows |
|
|
95
123
|
| view | `keepPairs` | A→B and B→A drawn as two lines |
|
|
96
124
|
| view | `repair: false` | no port repair |
|
|
97
125
|
| view | `subAndChips` | cards 80 px tall that show their sub-line, then their chips |
|
|
98
126
|
| view | `kindsFromLabels` | a line whose edges name no `kind` takes one guessed from its label |
|
|
99
127
|
| container | `badges` | tabs on the box's border |
|
|
128
|
+
| model | `rules` | what must hold: no line `from` some cards `to` others (picked by id, kind or box), or `noCycles` between boxes |
|
|
129
|
+
| model | `stories` | walk-throughs: steps that each set the view, camera, selection, highlight, tour and caption |
|
|
100
130
|
|
|
101
131
|
## Command line
|
|
102
132
|
|
|
@@ -105,11 +135,59 @@ python3 umlimator.py render examples/bookshop.json --out page.html # the inter
|
|
|
105
135
|
python3 umlimator.py stills page.html --out stills/ # every view as SVG and PNG
|
|
106
136
|
python3 umlimator.py stills page.html --out stills/ --views overview,api --scale 1.5 --theme light
|
|
107
137
|
python3 umlimator.py check page.html --views 'pic-*' # the layout check on chosen views
|
|
138
|
+
python3 umlimator.py diff before.json after.json --out diff.html --stills diff/ # what changed, marked and in words
|
|
139
|
+
python3 umlimator.py diff --base origin/main --out diff/ # every model changed since a ref, and a summary.md
|
|
140
|
+
python3 umlimator.py drift model.json traffic.json --out drift.html # drawn vs. seen (a Jaeger or Tempo dependency list)
|
|
141
|
+
python3 umlimator.py timelapse model.json --out history.html # the model's versions in git history, on a slider
|
|
142
|
+
python3 umlimator.py check page.html --expand # also each view with each stacked card unfolded
|
|
143
|
+
python3 umlimator.py record bike-share.html --story ride --out ride.png # bike-share's story as an animated PNG, a frame per step
|
|
108
144
|
```
|
|
109
145
|
|
|
110
|
-
|
|
146
|
+
`check` also reports each rule the model breaks, and then exits 1.
|
|
147
|
+
|
|
148
|
+
The page has breadcrumbs, a details panel per card, ⌘K search, deep links (`#view=<id>&node=<id>`, and
|
|
149
|
+
`#story=<id>&step=<n>` for a story's step), stories, and export.
|
|
111
150
|
`stills` skips a view whose inputs have not changed since its last export (`--all` exports every view). Needs Python
|
|
112
|
-
3.9+ (standard library only),
|
|
151
|
+
3.9+ (standard library only), Google Chrome or Chromium for `stills`, `check` and `record`, and Node 18+ for `diff`
|
|
152
|
+
and `drift`.
|
|
153
|
+
|
|
154
|
+
`record` writes an animated PNG, which browsers and GitHub show as it is. For a GIF or an MP4 (for chat or slides),
|
|
155
|
+
convert it with ffmpeg:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
ffmpeg -f apng -i ride.png -vf "split[a][b];[a]palettegen[p];[b][p]paletteuse" ride.gif
|
|
159
|
+
ffmpeg -f apng -i ride.png -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" -pix_fmt yuv420p ride.mp4
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
On pull requests, the diff Action posts what they change in your maps: one comment with the summary and a sketch, and
|
|
163
|
+
the pictures as the run's artifact.
|
|
164
|
+
|
|
165
|
+
```yaml
|
|
166
|
+
on: pull_request
|
|
167
|
+
permissions: { contents: read, pull-requests: write }
|
|
168
|
+
jobs:
|
|
169
|
+
maps:
|
|
170
|
+
runs-on: ubuntu-latest
|
|
171
|
+
steps:
|
|
172
|
+
- uses: actions/checkout@v4
|
|
173
|
+
- uses: zintaen/umlimator@v0.12.0
|
|
174
|
+
with:
|
|
175
|
+
models: "docs/*.json" # optional: where the models are (default: every .json that is a map model)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Map a repo with Claude Code
|
|
179
|
+
|
|
180
|
+
The `map-repo` skill reads a codebase, writes a C4-style model (context, containers, components), renders it to a page
|
|
181
|
+
and stills, and fixes what the layout check reports. Install it, then ask Claude Code to map the repository:
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
/plugin marketplace add zintaen/umlimator
|
|
185
|
+
/plugin install umlimator@umlimator
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
On Claude Code 2.1.275 or later, `/plugin install umlimator --marketplace zintaen/umlimator` does both in one step. The
|
|
189
|
+
skill needs git, Python 3.9+ and Chrome; on first use it fetches the CLI of one pinned release into
|
|
190
|
+
`~/.cache/umlimator/cli`.
|
|
113
191
|
|
|
114
192
|
## Icons
|
|
115
193
|
|
|
@@ -145,13 +223,15 @@ Release with that section as its notes, and publishes the package to npm (truste
|
|
|
145
223
|
CI also publishes the examples to GitHub Pages from `main`.
|
|
146
224
|
|
|
147
225
|
```
|
|
148
|
-
umlimator.py CLI: render, stills, check, pin-icons
|
|
226
|
+
umlimator.py CLI: render, stills, check, record, pin-icons, diff, drift, timelapse
|
|
227
|
+
action.yml the diff Action: what a pull request changes in its maps, posted on it
|
|
149
228
|
lib/ the module (umlimator.js), its types and the default theme
|
|
150
|
-
engine/ the page
|
|
229
|
+
engine/ the page templates the CLI inlines the module into; the upstream renderer and schema
|
|
151
230
|
docs/ the module's API and the editing design
|
|
152
231
|
tests/, bench/ tests, benchmark models and results
|
|
153
232
|
icons/ line icons and the logo manifest (sources and hashes only)
|
|
154
233
|
examples/ made-up systems: models, host pages and a Node script (live: zintaen.github.io/umlimator)
|
|
234
|
+
.claude-plugin/, plugins/ the Claude Code marketplace and its map-repo skill
|
|
155
235
|
```
|
|
156
236
|
|
|
157
237
|
## Licence
|
package/lib/umlimator.d.ts
CHANGED
|
@@ -9,6 +9,10 @@ export interface MapModel {
|
|
|
9
9
|
views: MapView[];
|
|
10
10
|
icons?: Record<string, { g?: string; src?: string; dark?: boolean }>;
|
|
11
11
|
authors?: Record<string, { name?: string; url?: string; avatar?: string }>;
|
|
12
|
+
/** What must hold: rules() lists what breaks them, the map marks it, and umlimator.py check fails on it. */
|
|
13
|
+
rules?: Rule[];
|
|
14
|
+
/** Narrated walk-throughs of the map (#69): handle.play(id), the standalone page's Stories menu, umlimator.py record. */
|
|
15
|
+
stories?: Story[];
|
|
12
16
|
[key: string]: unknown;
|
|
13
17
|
}
|
|
14
18
|
/** A badge: its text, and optionally a palette name for its colour (green, amber, rose, accent, violet ... : --um-<tone>). */
|
|
@@ -40,6 +44,14 @@ export interface MapEdge {
|
|
|
40
44
|
/** A second, smaller line under the label (a technology, say), placed with it and counted in the room left for labels.
|
|
41
45
|
* Shown only with a label. A line that stands for several edges shows each of their sublabels, joined by " / ". */
|
|
42
46
|
sublabel?: string;
|
|
47
|
+
/** A style that wins over the kind's colour: emphasis (green), added (green, flowing), dashed or async (violet),
|
|
48
|
+
* security (rose, dashed), removed (rose, dashed, faded) or faded (its kind's colour, faint, with no flow). */
|
|
49
|
+
style?: 'emphasis' | 'added' | 'dashed' | 'async' | 'security' | 'removed' | 'faded';
|
|
50
|
+
/** A change mark: added and removed draw only with the matching `style` on a map; diff() sets both, and marks a
|
|
51
|
+
* changed line `edited`. */
|
|
52
|
+
change?: 'added' | 'removed' | 'changed';
|
|
53
|
+
/** What drift() found: undrawn (traffic ran on it, nobody drew it) or idle (drawn, carried nothing). */
|
|
54
|
+
drift?: 'undrawn' | 'idle';
|
|
43
55
|
[key: string]: unknown;
|
|
44
56
|
}
|
|
45
57
|
export interface MapView {
|
|
@@ -70,6 +82,11 @@ export interface Events {
|
|
|
70
82
|
open: { target: Ref; view: string; preventDefault(): void }; // view: the one the card opens, which may not be in the model yet
|
|
71
83
|
viewchange: { view: string; from: string };
|
|
72
84
|
change: Change; // only with `editable`
|
|
85
|
+
/** E or Alt + click on a stacked card, or the ⤡ tab of the box it unfolded into (#71): before the card unfolds in place
|
|
86
|
+
* (expanded: true) or folds back (false). view: the card's inner view, which may not be in the model yet; the card
|
|
87
|
+
* unfolds once it is (the host loads it and calls update() right here, or later expand()). preventDefault(): no change. */
|
|
88
|
+
expand: { target: Extract<Ref, { type: 'node' }>; view: string; expanded: boolean; preventDefault(): void };
|
|
89
|
+
story: { story: string; step: number | null; steps: number }; // a story shows its step (0-based); step null: it ended
|
|
73
90
|
}
|
|
74
91
|
|
|
75
92
|
/** Where the user dropped or placed something: a point in the view and, on a column view, its column and row. */
|
|
@@ -95,12 +112,19 @@ export interface RenderOptions {
|
|
|
95
112
|
editable?: boolean | { add?: boolean; rename?: boolean; move?: boolean; delete?: boolean; reorder?: boolean };
|
|
96
113
|
/** Cards keep their places across update() (in this handle only, never in the model). Default true. */
|
|
97
114
|
stableLayout?: boolean;
|
|
115
|
+
/** update() eases into the next model: moved cards glide, new ones fade in, removed ones fade out (#67). Default true;
|
|
116
|
+
* never under prefers-reduced-motion. false draws the next model at once. */
|
|
117
|
+
ease?: boolean;
|
|
98
118
|
on?: { [K in keyof Events]?: (e: Events[K]) => void };
|
|
99
119
|
}
|
|
100
120
|
|
|
101
121
|
export interface ExportOptions { view?: string; scale?: number; fontCSS?: string }
|
|
102
122
|
|
|
103
123
|
export interface Handle {
|
|
124
|
+
/** Draws the next model, redrawing only what changed and keeping the view, camera and selection. With motion it eases
|
|
125
|
+
* in (#67): moved cards glide from where they were, new cards and rerouted lines fade in, and what left fades out
|
|
126
|
+
* where it was; none of it with the option `ease: false` or under prefers-reduced-motion, and an export at any point
|
|
127
|
+
* draws where things end up. */
|
|
104
128
|
update(model: MapModel): void;
|
|
105
129
|
setView(id: string): Promise<void> | void;
|
|
106
130
|
select(ref: Ref | null): void;
|
|
@@ -117,12 +141,74 @@ export interface Handle {
|
|
|
117
141
|
* the selected card or line. */
|
|
118
142
|
focus(ref?: Ref | null): void;
|
|
119
143
|
on<K extends keyof Events>(type: K, fn: (e: Events[K]) => void): () => void;
|
|
144
|
+
/** Unfolds a stacked card of the view shown into a box in place (#71): its inner view's own cards inside, this view's
|
|
145
|
+
* lines to it moved onto them, the rest of the picture in its order. In this handle only, never in the model; kept per
|
|
146
|
+
* view across update(). False when it can't: no loaded inner view, nothing of its own inside, a numbered (sequence)
|
|
147
|
+
* view in or opened, an editable map. No expand event: that is for gestures. */
|
|
148
|
+
expand(id: string): boolean;
|
|
149
|
+
/** Folds an unfolded card back (and anything unfolded inside it). False when it was not unfolded. */
|
|
150
|
+
collapse(id: string): boolean;
|
|
151
|
+
readonly expanded: string[]; // the cards unfolded on the view shown, in the order they were
|
|
120
152
|
readonly view: string | null;
|
|
121
153
|
readonly selection: Ref | null; // the latest selected
|
|
122
154
|
readonly selected: Ref[]; // every selected thing (Shift / Cmd / Ctrl + click adds cards), the latest last
|
|
155
|
+
/** Sets (or, with null, removes) a named layer of marks, drawn over the picture without touching the model. Layers stack
|
|
156
|
+
* in the order first set: each property comes from the latest layer that sets it, and a card or line is as lit as its
|
|
157
|
+
* lowest level. They survive update() and setView(); ids the view doesn't show are ignored. toSVG() and toPNG() draw them. */
|
|
158
|
+
overlay(name: string, layer: Overlay | null): void;
|
|
159
|
+
/** The 'highlight' layer: these cards and lines lit, the rest dimmed (in place of the selection's dimming), or null to clear.
|
|
160
|
+
* A Ref's level (0 to 1), else its distance (as reach() gives it), fades it. A chip's or badge's Ref lights its card. */
|
|
161
|
+
highlight(refs: Lit[] | null): void;
|
|
162
|
+
/** The tour dot rides the line between each pair of cards in turn (either way), through each card to its next line; a card
|
|
163
|
+
* it reaches flashes, and a pair with no line between them is skipped. Resolves true at the end, false when cut short (a
|
|
164
|
+
* new tour or replay, tour(null), a new picture of the view, destroy()). With reduced motion it resolves at once.
|
|
165
|
+
* speed: map units a second (default 240). */
|
|
166
|
+
tour(path: string[] | null, options?: { speed?: number }): Promise<boolean>;
|
|
167
|
+
/** Plays a trace: each call from one card to another (a span and its parent's) runs along their line at the trace's relative
|
|
168
|
+
* time; the line glows while the call lasts and keeps its duration as a label (the 'replay' layer, until stop() or the next
|
|
169
|
+
* replay). A span's service names its card: through `match`, else as a card's id, else as its label (any case).
|
|
170
|
+
* duration: the whole trace's playing time in ms (default 6000). With reduced motion the labels appear at once. */
|
|
171
|
+
replay(spans: Span[], options?: { match?: Record<string, string>; duration?: number }): Replay;
|
|
172
|
+
/** Tells one of the model's stories (#69): each step in turn sets the view, camera, selection, highlight and caption
|
|
173
|
+
* (drawn in a bar on the map and said to screen readers), then plays its tour. auto (default true): the next step
|
|
174
|
+
* follows once a step's duration is up and its tour has ended. step: where to start (0-based). The bar and the keys
|
|
175
|
+
* (← → PageUp PageDown, Esc) step through and stop it. null when the model has no story `id` with steps. */
|
|
176
|
+
play(id: string, options?: { step?: number; auto?: boolean }): StoryPlayer | null;
|
|
123
177
|
destroy(): void;
|
|
124
178
|
}
|
|
125
179
|
|
|
180
|
+
/** A walk-through: its steps, in order. */
|
|
181
|
+
export interface Story { id: string; title?: string; steps: StoryStep[] }
|
|
182
|
+
/** What one step shows. select: a card id, a line id, or a Ref. highlight: card ids, line ids or Lits; the lines between
|
|
183
|
+
* two cards it names light too. tour: card ids, the dot's path. camera: 'fit' (the default), a point and zoom, or a card
|
|
184
|
+
* to frame. duration: the step's time in ms when playing (default 4000; its tour runs to its end first). */
|
|
185
|
+
export interface StoryStep {
|
|
186
|
+
view: string; caption?: string; select?: string | Ref; highlight?: (string | Lit)[]; tour?: string[];
|
|
187
|
+
camera?: 'fit' | { x: number; y: number; zoom?: number } | { card: string; zoom?: number }; duration?: number;
|
|
188
|
+
}
|
|
189
|
+
/** A story being told. step: the one shown (0-based). next() past the last step ends it (done: true); stop() closes it
|
|
190
|
+
* (done: false). */
|
|
191
|
+
export interface StoryPlayer {
|
|
192
|
+
readonly story: string; readonly step: number; readonly steps: number; readonly playing: boolean; readonly done: Promise<boolean>;
|
|
193
|
+
next(): void; prev(): void; pause(): void; resume(): void; stop(): void;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** A mark on a card. tone: a palette name (--um-<tone>), drawn as a ring; badge: a tab after the card's own; level: 0 to 1. */
|
|
197
|
+
export interface CardMark { tone?: string; badge?: Badge; pulse?: boolean; level?: number }
|
|
198
|
+
/** A mark on a line. speed: its flow's speed, as a factor (0 stops it); tone: a glow under it; label: a pill under its own;
|
|
199
|
+
* dash: drawn dashed; level: 0 to 1. A drawn line that stands for several edges takes the strongest of their marks. */
|
|
200
|
+
export interface LineMark { tone?: string; speed?: number; pulse?: boolean; label?: string; level?: number; dash?: boolean }
|
|
201
|
+
/** A layer of marks: cards by node id, lines by edge id ("<from>-><to>#<n>" for an edge without one, as Refs name it).
|
|
202
|
+
* dim: what the layer doesn't name fades. */
|
|
203
|
+
export interface Overlay { nodes?: Record<string, CardMark>; edges?: Record<string, LineMark>; dim?: boolean }
|
|
204
|
+
/** A Ref for highlight(), with how lit it is: level (0 to 1), else distance (each step out a little fainter). */
|
|
205
|
+
export type Lit = Ref & { level?: number; distance?: number };
|
|
206
|
+
/** A span of a trace: start and end in milliseconds; service names the card it ran in; parent is its caller's span id. */
|
|
207
|
+
export interface Span { id: string; parent?: string | null; service: string; start: number; end: number; name?: string }
|
|
208
|
+
/** A replay in progress. hops: the calls it plays; skipped: spans whose service has no card on the view, or whose call has
|
|
209
|
+
* no line there. done: true when it played to the end, false when stopped or cut short. */
|
|
210
|
+
export interface Replay { readonly hops: number; readonly skipped: number; readonly done: Promise<boolean>; pause(): void; resume(): void; stop(): void }
|
|
211
|
+
|
|
126
212
|
export interface Geometry {
|
|
127
213
|
nodes: { id: string; x: number; y: number; w: number; h: number; [key: string]: unknown }[];
|
|
128
214
|
edges: { from: string; to: string; ids: string[]; pts: [number, number][]; weight: 1 | 2 | 3; wk: WireKind;
|
|
@@ -135,6 +221,62 @@ export function render(container: HTMLElement, model: MapModel, options?: Render
|
|
|
135
221
|
/** Undo for a host: it pushes each model it applies, and hands undo() / redo() results to handle.update(). */
|
|
136
222
|
export interface History { readonly model: MapModel; readonly canUndo: boolean; readonly canRedo: boolean; push(m: MapModel): MapModel; undo(): MapModel; redo(): MapModel }
|
|
137
223
|
export function history(model: MapModel, limit?: number): History;
|
|
138
|
-
|
|
224
|
+
/** expand: cards of the view unfolded in place (#71), as handle.expand() draws them; the geometry's `unfolded` lists those
|
|
225
|
+
* that did (one inside another after it), and its `families` the boxes they became (`unfolds`: the inner view). */
|
|
226
|
+
export function layout(model: MapModel, viewId: string, options?: { repair?: boolean; measure?: (text: string, px: number) => number; expand?: string[] }): Geometry & { unfolded?: string[] };
|
|
227
|
+
/** A model's own problem. path says where: "views[2].nodeIds[4]". Errors draw as holes or not at all (missing,
|
|
228
|
+
* repeated or dangling ids, a box inside itself); warnings draw other than they say (an unknown kind, weight or side,
|
|
229
|
+
* a view a card opens that the host has not loaded yet). The JSON Schema is umlimator/schema.json. */
|
|
230
|
+
export interface Problem { level: 'error' | 'warning'; path: string; message: string }
|
|
231
|
+
export function validate(model: MapModel): Problem[];
|
|
232
|
+
/** One issue of the layout check: its message, as the page's check words it, and the cards, lines and boxes it is about
|
|
233
|
+
* (exactly those, even where two cards share a label). */
|
|
234
|
+
export interface CheckIssue { message: string; targets: Ref[] }
|
|
235
|
+
/** The layout check's geometry for one view, on layout()'s geometry: no browser needed. The page's check (CLI) adds what
|
|
236
|
+
* it measures in the DOM (text overflowing its card, titles, edge labels on cards or each other). In Node, text widths
|
|
237
|
+
* are an estimate unless `measure` is given, so the layout, and what is found, can differ from a browser's. */
|
|
238
|
+
export function check(model: MapModel, viewId: string, options?: { repair?: boolean; measure?: (text: string, px: number) => number; expand?: string[] }): CheckIssue[];
|
|
239
|
+
/** Picks cards by id, kind (as the map draws it: "db" picks databases) or box (at any depth), each a value or a list;
|
|
240
|
+
* every key given must hold, and `not` turns a selector round. A line's end on a box is that box: in it, of no kind. */
|
|
241
|
+
export interface Selector { id?: string | string[]; kind?: string | string[]; container?: string | string[]; not?: Selector }
|
|
242
|
+
/** What the model says must hold (`model.rules`): no line from the cards `from` picks to the cards `to` picks (a side left
|
|
243
|
+
* out picks every card), or, with noCycles, no boxes that reach each other through their lines (a line counts between
|
|
244
|
+
* the two boxes that hold its ends right under the box they share). A rule that names a box (a container, or a box's
|
|
245
|
+
* id, in from, to or a not) holds only in the views that draw one of the boxes it names; any other, in every view.
|
|
246
|
+
* `views` narrows that further. */
|
|
247
|
+
export interface Rule { id: string; title?: string; views?: string[]; from?: Selector; to?: Selector; noCycles?: boolean }
|
|
248
|
+
/** A rule broken in a view: its message (as umlimator.py check prints it), and the lines, and for a cycle the boxes, it is
|
|
249
|
+
* about. The map draws those lines rose, with a mark that names the rule. */
|
|
250
|
+
export interface RuleBreak { rule: string; view: string; message: string; targets: Ref[] }
|
|
251
|
+
/** Every rule the model breaks, view by view. No browser needed. */
|
|
252
|
+
export function rules(model: MapModel): RuleBreak[];
|
|
253
|
+
/** Every card and line on a path from one card to another along the view's lines, as Refs ([] when none joins them). */
|
|
254
|
+
export function paths(model: MapModel, viewId: string, from: string, to: string): Ref[];
|
|
255
|
+
/** What a card's lines lead to, or (backward) what leads to it, as Refs with their distance in lines; the card first, at 0. */
|
|
256
|
+
export function reach(model: MapModel, viewId: string, from: string, options?: { backward?: boolean; depth?: number }): (Ref & { distance: number })[];
|
|
257
|
+
/** A view in plain sentences: cards and kinds, boxes, what each card's lines do, cards with no line. Deterministic. */
|
|
258
|
+
export function describe(model: MapModel, viewId: string): string;
|
|
259
|
+
/** The spans of an OpenTelemetry trace in OTLP JSON (resourceSpans), as replay() takes them. */
|
|
260
|
+
export function otlpSpans(otlp: unknown): Span[];
|
|
261
|
+
/** What changed from one model to the next (#66), as one model to draw: `after`, with each card marked added, changed or
|
|
262
|
+
* removed (`change`: a NEW or CHANGED tab; REMOVED is faded, dashed and struck through) and each line likewise (`style`
|
|
263
|
+
* added or removed; a changed one `edited`); what left comes back in its views, boxes and places, and a card put into
|
|
264
|
+
* or taken out of a view is marked in that view only (`nodeOverrides`). Cards and lines match by id (a line without one
|
|
265
|
+
* by its ends, as a Ref names it). `summary`: what changed in words, in model order ("adds Payments queue between
|
|
266
|
+
* Trip service and Payment provider"); `views`: those that show a change. The marks are the model's own fields, so a
|
|
267
|
+
* page or still the CLI makes shows them. Neither input is changed. */
|
|
268
|
+
export interface DiffResult { model: MapModel; summary: string[]; views: string[] }
|
|
269
|
+
export function diff(before: MapModel | null, after: MapModel | null): DiffResult;
|
|
270
|
+
/** A call between two services as traffic showed it: { from, to, count }, or a Jaeger or Tempo dependency. */
|
|
271
|
+
export type Observed = { from: string; to: string; count?: number } | { parent: string; child: string; callCount?: number };
|
|
272
|
+
/** The map against the traffic seen (#68). A line that ran but is not drawn comes in (`drift: 'undrawn'`: rose, dashed,
|
|
273
|
+
* labelled "not drawn" with its calls); a drawn line between two cards traffic reached, that carried none, fades
|
|
274
|
+
* (`drift: 'idle'`, style `faded`); other lines are left as they are. A service is the card `match` names, else the one
|
|
275
|
+
* with its id, else with its label (case aside). `counts`: lines that carried traffic, came in, are idle, or could not
|
|
276
|
+
* be judged (an end traffic never reached), and the services with no card; `views`: those that show drift. The counts
|
|
277
|
+
* are of model edges, not drawn lines: a line that stands for several edges (A→B and B→A) fades only when every one of
|
|
278
|
+
* them is idle, so a map can show fewer faded lines than `idle` counts. */
|
|
279
|
+
export interface DriftResult { model: MapModel; counts: { carried: number; undrawn: number; idle: number; unknown: number; unmatched: string[] }; views: string[] }
|
|
280
|
+
export function drift(model: MapModel, observed: Observed[] | { data: Observed[] }, options?: { match?: Record<string, string> }): DriftResult;
|
|
139
281
|
/** The whole standalone viewer (top bar, views list, details panel, search, export) that umlimator.py writes. */
|
|
140
282
|
export function mountPage(container: HTMLElement, model: MapModel, options?: { params?: URLSearchParams; instant?: boolean }): Handle;
|