boundry 0.5.0 → 0.6.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/CHANGELOG.md +22 -0
- package/README.md +30 -25
- package/dist/adapters/visualizer/likec4.d.ts +21 -9
- package/dist/adapters/visualizer/likec4.js +117 -35
- package/dist/cli/index.js +6 -5
- package/dist/core/pipeline/pipeline.d.ts +6 -6
- package/dist/core/pipeline/pipeline.js +7 -7
- package/dist/core/ports/ports.d.ts +12 -11
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,28 @@ All notable changes to Boundry are documented here.
|
|
|
4
4
|
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/);
|
|
5
5
|
versioning follows [semver](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [0.6.0] — 2026-07-22
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **`boundry diff` now emits a single "proposed changes" view by default** ([#8]),
|
|
12
|
+
instead of one view per changed layer. The per-layer shape (added in 0.4.0,
|
|
13
|
+
extended per-altitude in 0.5.0) had two failure modes on real changes: it
|
|
14
|
+
multiplied views (one multi-slice change produced ~21), and its per-layer
|
|
15
|
+
`include *` collapsed deeply-nested proposals into their grey ancestor box, so a
|
|
16
|
+
nested proposed leaf silently lost its amber. The new `boundry_diff` view uses
|
|
17
|
+
`include * -> * where tag is #proposed` with **no** bare `include *`, so it pulls
|
|
18
|
+
in exactly the proposed edges and the leaf modules they touch — every change is
|
|
19
|
+
drawn at leaf level, uncollapsed and uniformly coloured, on one landing. A
|
|
20
|
+
`#proposed` box with no edge yet is included by fqn so a proposed-but-unwired
|
|
21
|
+
module still shows, and every endpoint's ancestor chain is included so each
|
|
22
|
+
change nests under its layer/system for context. `approve` still deletes the
|
|
23
|
+
derived file (0.5.0 behaviour).
|
|
24
|
+
- The per-altitude per-layer views from 0.5.0 remain available behind
|
|
25
|
+
**`boundry diff --per-layer`** — useful for a small change, opt-in.
|
|
26
|
+
|
|
27
|
+
[#8]: https://github.com/makspiechota/boundry/issues/8
|
|
28
|
+
|
|
7
29
|
## [0.5.0] — 2026-07-21
|
|
8
30
|
|
|
9
31
|
### Fixed
|
package/README.md
CHANGED
|
@@ -293,38 +293,41 @@ this styling back out with the marker: a `#proposed` edge returns to bare, a
|
|
|
293
293
|
`#proposed` box stays but loses its colour, a `#proposal-delete` is removed
|
|
294
294
|
outright. Requires **LikeC4 ≥ 1.58** to render.
|
|
295
295
|
|
|
296
|
-
### Reviewing a proposal —
|
|
296
|
+
### Reviewing a proposal — the diff view (prototype)
|
|
297
297
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
**focused view for every layer that draws a pending change** — into a derived
|
|
301
|
-
`boundry.diff.likec4`:
|
|
298
|
+
`diff` generates a single **proposed-changes** view — every pending change on one
|
|
299
|
+
landing — into a derived `boundry.diff.likec4`:
|
|
302
300
|
|
|
303
301
|
```bash
|
|
304
302
|
boundry diff --arch arch # (re)write boundry.diff.likec4
|
|
305
|
-
likec4 serve arch #
|
|
303
|
+
likec4 serve arch # open 'Boundry diff — proposed changes'
|
|
306
304
|
```
|
|
307
305
|
|
|
308
306
|
The highlighting is **generated, not hand-styled** — `diff` emits the LikeC4
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
307
|
+
rules into the derived file, so every `#proposed` box fills amber and edge goes
|
|
308
|
+
amber + solid, every `#proposal-delete` red, deterministically. That closes the
|
|
309
|
+
last manual seam: `annotate` marks, `diff` colours, no agent-dependent styling
|
|
310
|
+
step. Unchanged elements keep their defaults, and the rules live only in the
|
|
311
|
+
generated view, so your own views are untouched.
|
|
312
|
+
|
|
313
|
+
The view uses `include * -> * where tag is #proposed` (no bare `include *`), so it
|
|
314
|
+
pulls in exactly the proposed edges and the leaf modules they touch — a
|
|
315
|
+
deeply-nested proposal renders as its **own coloured node** instead of collapsing
|
|
316
|
+
into a grey ancestor. A proposed *module* with no edge yet is included too, so a
|
|
317
|
+
proposed-but-unwired box still shows. Each change nests under its layer/system for
|
|
318
|
+
context.
|
|
319
|
+
|
|
320
|
+
For a small change you can ask for the old per-layer shape instead — one focused
|
|
321
|
+
`view … of <scope>` for every layer that draws a change:
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
boundry diff --arch arch --per-layer
|
|
325
|
+
```
|
|
323
326
|
|
|
324
327
|
The file is a **derived artifact**: overwritten every run, removed when nothing is
|
|
325
328
|
proposed, so it always matches the current diagram. `approve` deletes it too, as
|
|
326
|
-
part of enacting — the moment the last proposal is approved the
|
|
327
|
-
|
|
329
|
+
part of enacting — the moment the last proposal is approved the view is stale, so
|
|
330
|
+
the post-approve workspace validates clean. It reads the diagram's own markers
|
|
328
331
|
(not the lock), so it frames whatever `annotate` or a human has marked. Being
|
|
329
332
|
derived, it's a `.gitignore` candidate (`boundry.diff.likec4`).
|
|
330
333
|
|
|
@@ -340,7 +343,7 @@ boundry generate [--arch <dir>] [--cwd <dir>] [--out <file>]
|
|
|
340
343
|
boundry verify [--arch <dir>] [--cwd <dir>]
|
|
341
344
|
boundry approve [--arch <dir>] [--cwd <dir>]
|
|
342
345
|
boundry annotate [--arch <dir>]
|
|
343
|
-
boundry diff [--arch <dir>]
|
|
346
|
+
boundry diff [--arch <dir>] [--per-layer]
|
|
344
347
|
```
|
|
345
348
|
|
|
346
349
|
| Flag | Meaning |
|
|
@@ -348,6 +351,7 @@ boundry diff [--arch <dir>]
|
|
|
348
351
|
| `--arch <dir>` | LikeC4 workspace directory (all `.likec4` files in it are merged). Default `.`. |
|
|
349
352
|
| `--cwd <dir>` | Repo root to check. `folder` paths are relative to it. Lets you run from anywhere. |
|
|
350
353
|
| `--out <file>` | `generate` only: where to write the dependency-cruiser config. Default `.dependency-cruiser.cjs`. |
|
|
354
|
+
| `--per-layer` | `diff` only: emit one focused view per layer instead of the single proposed-changes view. |
|
|
351
355
|
| `sources...` | `check` only: paths to lint. Default `src`. |
|
|
352
356
|
|
|
353
357
|
- **`check`** compiles the rules and runs the linter. Exits non-zero on any violation.
|
|
@@ -360,8 +364,9 @@ boundry diff [--arch <dir>]
|
|
|
360
364
|
removes `#proposal-delete`) and writes `boundry.lock`. For humans, not agents.
|
|
361
365
|
- **`annotate`** rewrites undeclared additions as `#proposed`, diffing against
|
|
362
366
|
`boundry.lock`.
|
|
363
|
-
- **`diff`** generates a
|
|
364
|
-
|
|
367
|
+
- **`diff`** generates a single colour-coded "proposed changes" review view into a
|
|
368
|
+
derived `boundry.diff.likec4` (or, with `--per-layer`, one focused view per layer
|
|
369
|
+
that draws a change).
|
|
365
370
|
|
|
366
371
|
Boundry warns (but does not fail) when a mapped folder matches **zero** files, and
|
|
367
372
|
**fails outright** when a check analysed no files at all — so a passing check can
|
|
@@ -46,14 +46,26 @@ export declare class LikeC4Visualizer implements VisualizerPort {
|
|
|
46
46
|
*/
|
|
47
47
|
styleMarkers(): Promise<void>;
|
|
48
48
|
/**
|
|
49
|
-
* Generate
|
|
50
|
-
* Walks the diagram's own `#proposed` / `#proposal-delete`
|
|
51
|
-
* lock — a `#proposal-delete` has no lock delta)
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
49
|
+
* Generate the review views for the diagram's pending changes, into a derived
|
|
50
|
+
* `boundry.diff.likec4`. Walks the diagram's own `#proposed` / `#proposal-delete`
|
|
51
|
+
* markers (never the lock — a `#proposal-delete` has no lock delta).
|
|
52
|
+
*
|
|
53
|
+
* By default it emits a **single `boundry_diff` view** that draws every change at
|
|
54
|
+
* once, uncollapsed and uniformly highlighted (see `renderSingleView`) — the diff
|
|
55
|
+
* landing. With `perLayer`, it instead emits one focused `view … of <scope>` for
|
|
56
|
+
* every layer that draws a change (a box in its parent layer; an edge in every
|
|
57
|
+
* layer that draws it, per `edgeScopes`) — useful for a small change, but it
|
|
58
|
+
* multiplies views and collapses deeply-nested proposals into grey ancestors on
|
|
59
|
+
* a broad `include *`, which is why the single view is the default (issue #8).
|
|
60
|
+
*
|
|
61
|
+
* The file is overwritten each run and removed when nothing is proposed, so it
|
|
62
|
+
* always reflects the current diagram.
|
|
63
|
+
*/
|
|
64
|
+
emitDiffViews(perLayer?: boolean): Promise<DiffView[]>;
|
|
65
|
+
/**
|
|
66
|
+
* The `--per-layer` shape: buckets each change into every layer that draws it and
|
|
67
|
+
* renders one scoped `view … of <scope>` per layer. Kept as an opt-in to the
|
|
68
|
+
* single-view default.
|
|
57
69
|
*/
|
|
58
|
-
|
|
70
|
+
private perLayerViews;
|
|
59
71
|
}
|
|
@@ -104,6 +104,61 @@ function renderDiffView(scope, highlight) {
|
|
|
104
104
|
const lines = [` title 'Boundry diff · ${scope ?? 'root'}'`, ' include *', ...highlight];
|
|
105
105
|
return `${opener}\n${lines.join('\n')}\n }`;
|
|
106
106
|
}
|
|
107
|
+
/** Every proper ancestor of an element, shallowest first — its parent chain up to (not including) the root. */
|
|
108
|
+
function ancestorFqns(fqn) {
|
|
109
|
+
const parts = fqn.split('.');
|
|
110
|
+
const out = [];
|
|
111
|
+
for (let len = 1; len <= parts.length - 1; len++)
|
|
112
|
+
out.push(parts.slice(0, len).join('.'));
|
|
113
|
+
return out;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* The single `boundry_diff` view: one landing that draws *every* pending change at
|
|
117
|
+
* once, with uniform highlighting and no empty views. It sidesteps the per-layer
|
|
118
|
+
* shape's two failure modes (issue #8):
|
|
119
|
+
*
|
|
120
|
+
* - **No collapse.** `include * -> * where tag is #proposed` (with NO bare
|
|
121
|
+
* `include *`) pulls in exactly the proposed edges and the leaf modules they
|
|
122
|
+
* touch — so a deeply-nested proposed leaf renders as its own amber node
|
|
123
|
+
* instead of collapsing into a grey ancestor, as it does under `include *`.
|
|
124
|
+
* - **Standalone boxes.** A `#proposed` box with no edge is included by fqn, so
|
|
125
|
+
* a proposed-but-unwired module still shows (and is coloured by the style rule).
|
|
126
|
+
*
|
|
127
|
+
* Every endpoint's and box's full ancestor chain is included too, so each change
|
|
128
|
+
* nests under its layer/system for context (verified against LikeC4 1.58). Rules
|
|
129
|
+
* are emitted only for marker tags actually in use — referencing an undeclared tag
|
|
130
|
+
* is a hard LikeC4 error.
|
|
131
|
+
*/
|
|
132
|
+
function renderSingleView(edges, boxes, usedTags) {
|
|
133
|
+
const lines = [` title 'Boundry diff — proposed changes'`];
|
|
134
|
+
// Edge includes: one per marker that appears on an edge. These pull the proposed
|
|
135
|
+
// edges and their endpoint leaves in at leaf level, uncollapsed.
|
|
136
|
+
if (edges.some((e) => e.marker === '#proposed')) {
|
|
137
|
+
lines.push(' include * -> * where tag is #proposed with { color amber; line solid }');
|
|
138
|
+
}
|
|
139
|
+
if (edges.some((e) => e.marker === '#proposal-delete')) {
|
|
140
|
+
lines.push(' include * -> * where tag is #proposal-delete with { color red; line solid }');
|
|
141
|
+
}
|
|
142
|
+
// Element includes: the proposed/proposal-delete boxes themselves (so a standalone
|
|
143
|
+
// one shows), plus the full ancestor chain of every endpoint and box (so each
|
|
144
|
+
// change nests under its containers). Deterministic: sorted, de-duplicated.
|
|
145
|
+
const includeFqns = new Set();
|
|
146
|
+
for (const box of boxes)
|
|
147
|
+
includeFqns.add(box.fqn);
|
|
148
|
+
const anchors = [...edges.flatMap((e) => [e.from, e.to]), ...boxes.map((b) => b.fqn)];
|
|
149
|
+
for (const fqn of anchors)
|
|
150
|
+
for (const ancestor of ancestorFqns(fqn))
|
|
151
|
+
includeFqns.add(ancestor);
|
|
152
|
+
if (includeFqns.size) {
|
|
153
|
+
lines.push(` include ${[...includeFqns].sort().join(', ')}`);
|
|
154
|
+
}
|
|
155
|
+
// Style rules colour the tagged boxes (edges are coloured by their include above).
|
|
156
|
+
if (usedTags.has('proposed'))
|
|
157
|
+
lines.push(' style element.tag = #proposed { color amber }');
|
|
158
|
+
if (usedTags.has('proposal-delete'))
|
|
159
|
+
lines.push(' style element.tag = #proposal-delete { color red }');
|
|
160
|
+
return ` view boundry_diff {\n${lines.join('\n')}\n }`;
|
|
161
|
+
}
|
|
107
162
|
/**
|
|
108
163
|
* An exemption pattern has to be a usable regex before it reaches the linter. A
|
|
109
164
|
* broken or empty one would otherwise be a silent hole: it exempts files from
|
|
@@ -582,28 +637,28 @@ export class LikeC4Visualizer {
|
|
|
582
637
|
}
|
|
583
638
|
}
|
|
584
639
|
/**
|
|
585
|
-
* Generate
|
|
586
|
-
* Walks the diagram's own `#proposed` / `#proposal-delete`
|
|
587
|
-
* lock — a `#proposal-delete` has no lock delta)
|
|
588
|
-
*
|
|
589
|
-
*
|
|
590
|
-
*
|
|
591
|
-
*
|
|
592
|
-
*
|
|
640
|
+
* Generate the review views for the diagram's pending changes, into a derived
|
|
641
|
+
* `boundry.diff.likec4`. Walks the diagram's own `#proposed` / `#proposal-delete`
|
|
642
|
+
* markers (never the lock — a `#proposal-delete` has no lock delta).
|
|
643
|
+
*
|
|
644
|
+
* By default it emits a **single `boundry_diff` view** that draws every change at
|
|
645
|
+
* once, uncollapsed and uniformly highlighted (see `renderSingleView`) — the diff
|
|
646
|
+
* landing. With `perLayer`, it instead emits one focused `view … of <scope>` for
|
|
647
|
+
* every layer that draws a change (a box in its parent layer; an edge in every
|
|
648
|
+
* layer that draws it, per `edgeScopes`) — useful for a small change, but it
|
|
649
|
+
* multiplies views and collapses deeply-nested proposals into grey ancestors on
|
|
650
|
+
* a broad `include *`, which is why the single view is the default (issue #8).
|
|
651
|
+
*
|
|
652
|
+
* The file is overwritten each run and removed when nothing is proposed, so it
|
|
653
|
+
* always reflects the current diagram.
|
|
593
654
|
*/
|
|
594
|
-
async emitDiffViews() {
|
|
655
|
+
async emitDiffViews(perLayer = false) {
|
|
595
656
|
const likec4 = await LikeC4.fromWorkspace(this.workspaceDir);
|
|
596
|
-
//
|
|
597
|
-
|
|
598
|
-
const
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
const layer = layers.get(key) ?? { scope, changes: 0 };
|
|
602
|
-
layer.changes += 1;
|
|
603
|
-
layers.set(key, layer);
|
|
604
|
-
};
|
|
605
|
-
// Which marker tags actually appear — so the emitted highlight rules only ever
|
|
606
|
-
// reference declared tags (an undeclared tag reference is a hard LikeC4 error).
|
|
657
|
+
// Lift every marked edge and box once; both view shapes are built from this.
|
|
658
|
+
const edges = [];
|
|
659
|
+
const boxes = [];
|
|
660
|
+
// Which marker tags actually appear — so the emitted rules only ever reference
|
|
661
|
+
// declared tags (an undeclared tag reference is a hard LikeC4 error).
|
|
607
662
|
const usedTags = new Set();
|
|
608
663
|
for (const doc of likec4.LangiumDocuments.all) {
|
|
609
664
|
const filePath = doc.uri.fsPath;
|
|
@@ -619,27 +674,54 @@ export class LikeC4Visualizer {
|
|
|
619
674
|
if (statement?.$type === 'Relation') {
|
|
620
675
|
const from = fqnOf(endpointElement(statement.source));
|
|
621
676
|
const to = fqnOf(endpointElement(statement.target));
|
|
622
|
-
// One view per layer that actually draws this edge, so the reviewer can
|
|
623
|
-
// judge it at every altitude — not only the common-ancestor layer (#7).
|
|
624
677
|
if (from && to)
|
|
625
|
-
|
|
626
|
-
record(scope);
|
|
678
|
+
edges.push({ from, to, marker });
|
|
627
679
|
}
|
|
628
680
|
else if (statement?.$type === 'Element') {
|
|
629
681
|
const fqn = fqnOf(statement);
|
|
630
682
|
if (fqn)
|
|
631
|
-
|
|
683
|
+
boxes.push({ fqn, marker });
|
|
632
684
|
}
|
|
633
685
|
});
|
|
634
686
|
}
|
|
635
687
|
const diffPath = join(this.workspaceDir, DIFF_FILE);
|
|
636
|
-
if (
|
|
688
|
+
if (edges.length === 0 && boxes.length === 0) {
|
|
637
689
|
// Nothing proposed — clear any stale views so `serve` never renders a diff
|
|
638
690
|
// that no longer exists (and never dangles a reference to an approved-away box).
|
|
639
691
|
if (existsSync(diffPath))
|
|
640
692
|
rmSync(diffPath);
|
|
641
693
|
return [];
|
|
642
694
|
}
|
|
695
|
+
const { header, body, views } = perLayer
|
|
696
|
+
? this.perLayerViews(edges, boxes, usedTags)
|
|
697
|
+
: {
|
|
698
|
+
header: 'a single landing view of every pending change',
|
|
699
|
+
body: renderSingleView(edges, boxes, usedTags),
|
|
700
|
+
views: [{ id: 'boundry_diff', changes: edges.length + boxes.length }],
|
|
701
|
+
};
|
|
702
|
+
writeFileSync(diffPath, `// Generated by \`boundry diff\` — ${header}.\n` +
|
|
703
|
+
`// Derived artifact: regenerate after approve; do not hand-edit.\n` +
|
|
704
|
+
`views {\n${body}\n}\n`);
|
|
705
|
+
return views;
|
|
706
|
+
}
|
|
707
|
+
/**
|
|
708
|
+
* The `--per-layer` shape: buckets each change into every layer that draws it and
|
|
709
|
+
* renders one scoped `view … of <scope>` per layer. Kept as an opt-in to the
|
|
710
|
+
* single-view default.
|
|
711
|
+
*/
|
|
712
|
+
perLayerViews(edges, boxes, usedTags) {
|
|
713
|
+
const layers = new Map();
|
|
714
|
+
const record = (scope) => {
|
|
715
|
+
const key = scopeViewId(scope);
|
|
716
|
+
const layer = layers.get(key) ?? { scope, changes: 0 };
|
|
717
|
+
layer.changes += 1;
|
|
718
|
+
layers.set(key, layer);
|
|
719
|
+
};
|
|
720
|
+
for (const edge of edges)
|
|
721
|
+
for (const scope of edgeScopes(edge.from, edge.to))
|
|
722
|
+
record(scope);
|
|
723
|
+
for (const box of boxes)
|
|
724
|
+
record(parentScope(box.fqn));
|
|
643
725
|
// Root first, then by fqn, so the output is stable across runs.
|
|
644
726
|
const ordered = [...layers.values()].sort((a, b) => {
|
|
645
727
|
if (!a.scope)
|
|
@@ -649,14 +731,14 @@ export class LikeC4Visualizer {
|
|
|
649
731
|
return a.scope.localeCompare(b.scope);
|
|
650
732
|
});
|
|
651
733
|
const highlight = highlightLines(usedTags);
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
}
|
|
734
|
+
return {
|
|
735
|
+
header: 'one focused view per layer with a pending change',
|
|
736
|
+
body: ordered.map((layer) => renderDiffView(layer.scope, highlight)).join('\n'),
|
|
737
|
+
views: ordered.map((layer) => ({
|
|
738
|
+
id: scopeViewId(layer.scope),
|
|
739
|
+
scope: layer.scope,
|
|
740
|
+
changes: layer.changes,
|
|
741
|
+
})),
|
|
742
|
+
};
|
|
661
743
|
}
|
|
662
744
|
}
|
package/dist/cli/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { join, relative, resolve } from 'node:path';
|
|
|
4
4
|
import { Pipeline } from '../core/pipeline/pipeline.js';
|
|
5
5
|
import { LikeC4Visualizer } from '../adapters/visualizer/likec4.js';
|
|
6
6
|
import { DepCruiserEnforcer } from '../adapters/enforcer/depcruiser.js';
|
|
7
|
-
const USAGE = 'usage: boundry <generate|check|approve|verify|annotate|diff> [--arch <dir>] [--cwd <dir>] [--out <file>] [sources...]';
|
|
7
|
+
const USAGE = 'usage: boundry <generate|check|approve|verify|annotate|diff> [--arch <dir>] [--cwd <dir>] [--out <file>] [--per-layer] [sources...]';
|
|
8
8
|
function optValue(args, flag) {
|
|
9
9
|
const i = args.indexOf(flag);
|
|
10
10
|
return i >= 0 ? args[i + 1] : undefined;
|
|
@@ -139,7 +139,8 @@ async function main() {
|
|
|
139
139
|
return;
|
|
140
140
|
}
|
|
141
141
|
if (command === 'diff') {
|
|
142
|
-
const
|
|
142
|
+
const perLayer = rest.includes('--per-layer');
|
|
143
|
+
const views = await pipeline.diffViews(perLayer);
|
|
143
144
|
const diffFile = join(archDir, 'boundry.diff.likec4');
|
|
144
145
|
if (views.length === 0) {
|
|
145
146
|
console.log('Boundry: ✓ nothing proposed — no diff views to draw');
|
|
@@ -147,10 +148,10 @@ async function main() {
|
|
|
147
148
|
}
|
|
148
149
|
console.log(`Boundry: ✎ wrote ${views.length} diff view(s) to ${relative(process.cwd(), diffFile)}:`);
|
|
149
150
|
for (const view of views) {
|
|
150
|
-
const
|
|
151
|
-
console.log(` ${view.id} (
|
|
151
|
+
const where = perLayer ? `layer ${view.scope ?? 'root'}, ` : '';
|
|
152
|
+
console.log(` ${view.id} (${where}${view.changes} change(s))`);
|
|
152
153
|
}
|
|
153
|
-
console.log(' Open the diagram in `likec4 serve` to review
|
|
154
|
+
console.log(' Open the diagram in `likec4 serve` to review.');
|
|
154
155
|
return;
|
|
155
156
|
}
|
|
156
157
|
console.error(USAGE);
|
|
@@ -60,11 +60,11 @@ export declare class Pipeline {
|
|
|
60
60
|
*/
|
|
61
61
|
annotate(lock: string): Promise<AnnotateResult>;
|
|
62
62
|
/**
|
|
63
|
-
* (Re)generate
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
63
|
+
* (Re)generate the review views for the diagram's pending changes. By default a
|
|
64
|
+
* single `boundry_diff` landing view draws every `#proposed` / `#proposal-delete`
|
|
65
|
+
* change at once; with `perLayer`, one focused view per layer that draws a change.
|
|
66
|
+
* Reads the diagram's own markers, so it composes with `annotate` (annotate marks
|
|
67
|
+
* drift, this frames it).
|
|
68
68
|
*/
|
|
69
|
-
diffViews(): Promise<DiffView[]>;
|
|
69
|
+
diffViews(perLayer?: boolean): Promise<DiffView[]>;
|
|
70
70
|
}
|
|
@@ -69,13 +69,13 @@ export class Pipeline {
|
|
|
69
69
|
return { edges, modules };
|
|
70
70
|
}
|
|
71
71
|
/**
|
|
72
|
-
* (Re)generate
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
72
|
+
* (Re)generate the review views for the diagram's pending changes. By default a
|
|
73
|
+
* single `boundry_diff` landing view draws every `#proposed` / `#proposal-delete`
|
|
74
|
+
* change at once; with `perLayer`, one focused view per layer that draws a change.
|
|
75
|
+
* Reads the diagram's own markers, so it composes with `annotate` (annotate marks
|
|
76
|
+
* drift, this frames it).
|
|
77
77
|
*/
|
|
78
|
-
async diffViews() {
|
|
79
|
-
return this.visualizer.emitDiffViews();
|
|
78
|
+
async diffViews(perLayer = false) {
|
|
79
|
+
return this.visualizer.emitDiffViews(perLayer);
|
|
80
80
|
}
|
|
81
81
|
}
|
|
@@ -23,25 +23,26 @@ export interface VisualizerPort {
|
|
|
23
23
|
*/
|
|
24
24
|
styleMarkers(): Promise<void>;
|
|
25
25
|
/**
|
|
26
|
-
* (Re)generate
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
26
|
+
* (Re)generate the review views for the diagram's pending changes — edges and
|
|
27
|
+
* boxes tagged `#proposed` or `#proposal-delete`. By default a single
|
|
28
|
+
* `boundry_diff` landing view draws every change at once, uncollapsed and
|
|
29
|
+
* uniformly highlighted. With `perLayer`, one focused `view … of <scope>` is
|
|
30
|
+
* emitted per layer that draws a change instead. A derived artifact: overwritten
|
|
31
31
|
* each run, and removed when nothing is proposed. Returns one entry per view.
|
|
32
32
|
*/
|
|
33
|
-
emitDiffViews(): Promise<DiffView[]>;
|
|
33
|
+
emitDiffViews(perLayer?: boolean): Promise<DiffView[]>;
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
36
|
-
* One emitted diff view
|
|
37
|
-
* pending change
|
|
36
|
+
* One emitted diff view. For the default single view there is one entry
|
|
37
|
+
* (`boundry_diff`) counting every pending change; in `perLayer` mode there is one
|
|
38
|
+
* per layer, each scoped to an element and counting the changes that fall in it.
|
|
38
39
|
*/
|
|
39
40
|
export interface DiffView {
|
|
40
|
-
/** The generated view id
|
|
41
|
+
/** The generated view id — `boundry_diff`, or `boundry_diff_<scope>` per layer. */
|
|
41
42
|
id: string;
|
|
42
|
-
/**
|
|
43
|
+
/** perLayer only: the scope element's fqn, or undefined for the model root. */
|
|
43
44
|
scope?: string;
|
|
44
|
-
/** How many pending `#proposed` / `#proposal-delete` changes this
|
|
45
|
+
/** How many pending `#proposed` / `#proposal-delete` changes this view holds. */
|
|
45
46
|
changes: number;
|
|
46
47
|
}
|
|
47
48
|
/** A generated linter config artifact. */
|
package/package.json
CHANGED