@principal-ai/subsystems-react 0.53.5 → 0.54.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/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/pierre/PierreTrailCodeView.d.ts.map +1 -1
- package/dist/pierre/PierreTrailCodeView.js +7 -5
- package/dist/pierre/PierreTrailCodeView.js.map +1 -1
- package/dist/stories/Subsystem/ComponentGraph/fixtures.d.ts.map +1 -1
- package/dist/stories/Subsystem/ComponentGraph/fixtures.js +1 -2
- package/dist/stories/Subsystem/ComponentGraph/fixtures.js.map +1 -1
- package/dist/subsystem/C4Graph.d.ts +144 -9
- package/dist/subsystem/C4Graph.d.ts.map +1 -1
- package/dist/subsystem/C4Graph.js +924 -148
- package/dist/subsystem/C4Graph.js.map +1 -1
- package/dist/subsystem/C4NodeCard.d.ts +22 -1
- package/dist/subsystem/C4NodeCard.d.ts.map +1 -1
- package/dist/subsystem/C4NodeCard.js +10 -2
- package/dist/subsystem/C4NodeCard.js.map +1 -1
- package/dist/subsystem/ComponentDeclaration.d.ts +5 -4
- package/dist/subsystem/ComponentDeclaration.d.ts.map +1 -1
- package/dist/subsystem/ComponentDeclaration.js +12 -4
- package/dist/subsystem/ComponentDeclaration.js.map +1 -1
- package/dist/subsystem/ConstructsCatalog.d.ts.map +1 -1
- package/dist/subsystem/ConstructsCatalog.js +10 -7
- package/dist/subsystem/ConstructsCatalog.js.map +1 -1
- package/dist/subsystem/GraphSidebar.d.ts +71 -0
- package/dist/subsystem/GraphSidebar.d.ts.map +1 -0
- package/dist/subsystem/GraphSidebar.js +145 -0
- package/dist/subsystem/GraphSidebar.js.map +1 -0
- package/dist/subsystem/GraphWithSidebar.d.ts +24 -0
- package/dist/subsystem/GraphWithSidebar.d.ts.map +1 -0
- package/dist/subsystem/GraphWithSidebar.js +25 -0
- package/dist/subsystem/GraphWithSidebar.js.map +1 -0
- package/dist/subsystem/SubsystemComponentGraph.d.ts +33 -0
- package/dist/subsystem/SubsystemComponentGraph.d.ts.map +1 -1
- package/dist/subsystem/SubsystemComponentGraph.js +364 -411
- package/dist/subsystem/SubsystemComponentGraph.js.map +1 -1
- package/dist/subsystem/TrailStepsNav.d.ts +48 -0
- package/dist/subsystem/TrailStepsNav.d.ts.map +1 -0
- package/dist/subsystem/TrailStepsNav.js +189 -0
- package/dist/subsystem/TrailStepsNav.js.map +1 -0
- package/dist/subsystem/TrailsPanel.d.ts.map +1 -1
- package/dist/subsystem/TrailsPanel.js +3 -4
- package/dist/subsystem/TrailsPanel.js.map +1 -1
- package/dist/subsystem/__fixtures__/c4Drilldown.d.ts +151 -0
- package/dist/subsystem/__fixtures__/c4Drilldown.d.ts.map +1 -0
- package/dist/subsystem/__fixtures__/c4Drilldown.js +783 -0
- package/dist/subsystem/__fixtures__/c4Drilldown.js.map +1 -0
- package/dist/subsystem/c4.d.ts +39 -8
- package/dist/subsystem/c4.d.ts.map +1 -1
- package/dist/subsystem/c4.js.map +1 -1
- package/dist/subsystem/declarationRef.d.ts +26 -18
- package/dist/subsystem/declarationRef.d.ts.map +1 -1
- package/dist/subsystem/declarationRef.js +9 -4
- package/dist/subsystem/declarationRef.js.map +1 -1
- package/dist/subsystem/model.d.ts +19 -1
- package/dist/subsystem/model.d.ts.map +1 -1
- package/dist/subsystem/model.js +12 -2
- package/dist/subsystem/model.js.map +1 -1
- package/dist/subsystem/nodes.d.ts.map +1 -1
- package/dist/subsystem/nodes.js +24 -4
- package/dist/subsystem/nodes.js.map +1 -1
- package/dist/subsystem/trailBrief.d.ts.map +1 -1
- package/dist/subsystem/trailBrief.js +6 -1
- package/dist/subsystem/trailBrief.js.map +1 -1
- package/dist/utils/elkLayout.d.ts.map +1 -1
- package/dist/utils/elkLayout.js +10 -8
- package/dist/utils/elkLayout.js.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +9 -2
- package/src/pierre/PierreTrailCodeView.tsx +9 -13
- package/src/stories/Subsystem/C4Graph/C4ToComponentDrill.stories.tsx +496 -0
- package/src/stories/Subsystem/ComponentGraph/AnimatedProgression.stories.tsx +7 -7
- package/src/stories/Subsystem/ComponentGraph/Constructs.stories.tsx +19 -25
- package/src/stories/Subsystem/ComponentGraph/DetailPanel.stories.tsx +8 -10
- package/src/stories/Subsystem/ComponentGraph/Issues.stories.tsx +19 -19
- package/src/stories/Subsystem/ComponentGraph/ProposedTrails.stories.tsx +6 -6
- package/src/stories/Subsystem/ComponentGraph/TrailAutoplay.stories.tsx +7 -7
- package/src/stories/Subsystem/ComponentGraph/Trails.stories.tsx +27 -30
- package/src/stories/Subsystem/ComponentGraph/fixtures.ts +1 -2
- package/src/stories/Subsystem/ConstructsCatalog.stories.tsx +10 -13
- package/src/stories/Subsystem/EgoGraph/EgoGraph.stories.tsx +3 -4
- package/src/stories/Subsystem/Sidebar/GraphSidebar.stories.tsx +206 -0
- package/src/subsystem/C4Graph.groups.test.ts +96 -2
- package/src/subsystem/C4Graph.tsx +1377 -165
- package/src/subsystem/C4NodeCard.test.ts +1 -2
- package/src/subsystem/C4NodeCard.tsx +24 -2
- package/src/subsystem/ComponentDeclaration.tsx +18 -8
- package/src/subsystem/ConstructsCatalog.tsx +23 -8
- package/src/subsystem/GraphSidebar.test.tsx +152 -0
- package/src/subsystem/GraphSidebar.tsx +300 -0
- package/src/subsystem/GraphWithSidebar.test.tsx +78 -0
- package/src/subsystem/GraphWithSidebar.tsx +60 -0
- package/src/subsystem/SubsystemComponentGraph.tsx +284 -370
- package/src/subsystem/TrailStepsNav.test.tsx +179 -0
- package/src/subsystem/TrailStepsNav.tsx +372 -0
- package/src/subsystem/TrailsPanel.tsx +3 -4
- package/src/subsystem/__fixtures__/c4Drilldown.test.ts +338 -0
- package/src/subsystem/__fixtures__/c4Drilldown.ts +847 -0
- package/src/subsystem/c4.ts +41 -8
- package/src/subsystem/declarationRef.ts +28 -19
- package/src/subsystem/model.test.ts +32 -12
- package/src/subsystem/model.ts +30 -1
- package/src/subsystem/nodes.group.test.tsx +82 -0
- package/src/subsystem/nodes.tsx +30 -2
- package/src/subsystem/trailBrief.test.ts +2 -2
- package/src/subsystem/trailBrief.ts +6 -1
- package/src/utils/elkLayout.ts +10 -8
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
import {
|
|
3
|
+
CLI,
|
|
4
|
+
DISK,
|
|
5
|
+
DRILLDOWN_C4_MODEL,
|
|
6
|
+
DRILLDOWN_COMPONENTS,
|
|
7
|
+
DRILLDOWN_DOC,
|
|
8
|
+
DRILLDOWN_EDGES,
|
|
9
|
+
DRILLDOWN_MODEL_SOURCE,
|
|
10
|
+
DRILLDOWN_MEMBERS,
|
|
11
|
+
DRILLDOWN_TRAILS,
|
|
12
|
+
GITHUB,
|
|
13
|
+
HOST,
|
|
14
|
+
RENDERER,
|
|
15
|
+
SITE,
|
|
16
|
+
deriveCodeProcessKeys,
|
|
17
|
+
deriveElementMembers,
|
|
18
|
+
deriveLitC4Edges,
|
|
19
|
+
deriveTrailPlayerElements,
|
|
20
|
+
drilldownMembersOf,
|
|
21
|
+
rollupEdgeTrailRefs,
|
|
22
|
+
} from './c4Drilldown';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The fixture is the test case for the C4 → component-graph drill-down,
|
|
26
|
+
* grounded in the real, verified model sg-1788913589907-ieokymqg9. Two kinds
|
|
27
|
+
* of truth are asserted:
|
|
28
|
+
*
|
|
29
|
+
* fidelity — the document half is a faithful copy of the real model, so the
|
|
30
|
+
* test case is genuinely "pulled from a reviewed subsystem model";
|
|
31
|
+
*
|
|
32
|
+
* consistency — the assumed-accepted C4 layer's claims (process keys,
|
|
33
|
+
* memberships, edge provenance) are exactly what the document supports,
|
|
34
|
+
* which is also the spec for the eventual `buildC4Model` rollup.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
const membersOf = (id: string) => drilldownMembersOf(id);
|
|
38
|
+
|
|
39
|
+
/** Flat list of the steps a C4 edge's refs point at, in document order. */
|
|
40
|
+
function stepsOf(edge: (typeof DRILLDOWN_EDGES)[number]) {
|
|
41
|
+
const byId = new Map(DRILLDOWN_TRAILS.map((t) => [t.id, t]));
|
|
42
|
+
return (edge.trailRefs ?? []).flatMap((ref) => {
|
|
43
|
+
const trail = byId.get(ref.trailId);
|
|
44
|
+
if (!trail) return [];
|
|
45
|
+
return ref.stepIndices.map((i) => trail.steps[i]).filter(Boolean);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function sortRefs(refs: ReturnType<typeof rollupEdgeTrailRefs>) {
|
|
50
|
+
return [...refs]
|
|
51
|
+
.sort((a, b) => a.trailId.localeCompare(b.trailId))
|
|
52
|
+
.map((r) => ({ ...r, stepIndices: [...r.stepIndices].sort((x, y) => x - y) }));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
// Fidelity to the real reviewed model.
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
describe('c4Drilldown fixture — faithful copy of sg-1788913589907-ieokymqg9', () => {
|
|
60
|
+
test('doc metadata matches the real model', () => {
|
|
61
|
+
expect(DRILLDOWN_DOC.title).toBe(DRILLDOWN_MODEL_SOURCE.title);
|
|
62
|
+
expect(DRILLDOWN_MODEL_SOURCE.repo).toBe('pkg:github/principal-ai/subsystem-modeling');
|
|
63
|
+
expect(DRILLDOWN_COMPONENTS).toHaveLength(19);
|
|
64
|
+
expect(DRILLDOWN_TRAILS).toHaveLength(3);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test('component alias → process map is exactly the real model\'s', () => {
|
|
68
|
+
const expected: Array<[string, string | undefined]> = [
|
|
69
|
+
['site-gist-page', 'site/web'],
|
|
70
|
+
['gist-load', 'site/web'],
|
|
71
|
+
['to-portable', 'site/web'],
|
|
72
|
+
['is-portable', 'subsystems-core/types'],
|
|
73
|
+
['portable-doc', 'subsystems-core/types'],
|
|
74
|
+
['host-binding', 'subsystems-core/types'],
|
|
75
|
+
['github-gists-api', 'external/github'],
|
|
76
|
+
['react-graph', 'subsystems-react/ui'],
|
|
77
|
+
['cli-create', 'principal-studio-cli'],
|
|
78
|
+
['studio-create', 'subsystems-studio/host'],
|
|
79
|
+
['studio-update', 'subsystems-studio/host'],
|
|
80
|
+
['studio-get', 'subsystems-studio/host'],
|
|
81
|
+
['model-disk-store', 'local/disk'],
|
|
82
|
+
['index-entry', 'subsystems-studio/host'],
|
|
83
|
+
['studio-list', 'subsystems-studio/renderer'],
|
|
84
|
+
['studio-model-view', 'subsystems-studio/renderer'],
|
|
85
|
+
['open-tab', 'subsystems-studio/host'],
|
|
86
|
+
['gist-share-ui', 'proposed/studio-gist'],
|
|
87
|
+
['gist-ref', 'proposed/studio-gist'],
|
|
88
|
+
];
|
|
89
|
+
expect(
|
|
90
|
+
DRILLDOWN_COMPONENTS.map((c) => [c.alias, c.process] as [string, string | undefined]),
|
|
91
|
+
).toEqual(expected);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test('trail ids, titles, and step counts match the real model', () => {
|
|
95
|
+
expect(
|
|
96
|
+
DRILLDOWN_TRAILS.map((t) => [t.id, t.title, t.steps.length]),
|
|
97
|
+
).toEqual([
|
|
98
|
+
['tl-site-view-gist', 'Someone opens the shared gist on the site', 4],
|
|
99
|
+
['tl-persist-local-store', 'Persist a local model to ~/.principal/subsystem-models', 4],
|
|
100
|
+
['tl-proposed-share-gist', 'Proposed: share local model as gist (create or update)', 5],
|
|
101
|
+
]);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('model-level verification state is carried through', () => {
|
|
105
|
+
expect(DRILLDOWN_MODEL_SOURCE.verifiedCount).toBe(15);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
// Consistency of the assumed-accepted C4 layer.
|
|
111
|
+
// ---------------------------------------------------------------------------
|
|
112
|
+
|
|
113
|
+
describe('c4Drilldown fixture — C4 layer agrees with the document', () => {
|
|
114
|
+
test('every trail step endpoints a component alias that exists', () => {
|
|
115
|
+
const aliases = new Set(DRILLDOWN_COMPONENTS.map((c) => c.alias));
|
|
116
|
+
for (const trail of DRILLDOWN_TRAILS) {
|
|
117
|
+
for (const step of trail.steps) {
|
|
118
|
+
expect(aliases.has(step.from), `${trail.id} step .from`).toBe(true);
|
|
119
|
+
expect(aliases.has(step.to), `${trail.id} step .to`).toBe(true);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test('every member of every C4 element is a real component alias', () => {
|
|
125
|
+
const aliases = new Set(DRILLDOWN_COMPONENTS.map((c) => c.alias));
|
|
126
|
+
for (const element of DRILLDOWN_C4_MODEL.nodes) {
|
|
127
|
+
const members = element.kind === 'container'
|
|
128
|
+
? (DRILLDOWN_MEMBERS[element.id] ?? [])
|
|
129
|
+
: (element.members ?? []);
|
|
130
|
+
for (const alias of members) {
|
|
131
|
+
expect(aliases.has(alias), `${element.id} member ${alias}`).toBe(true);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test('container memberships derive exactly from their process claims', () => {
|
|
137
|
+
const byElement = deriveElementMembers(DRILLDOWN_C4_MODEL.nodes, DRILLDOWN_COMPONENTS);
|
|
138
|
+
expect([...byElement.entries()].sort((a, b) => a[0].localeCompare(b[0]))).toEqual([
|
|
139
|
+
['component:cli-command', ['cli-create']],
|
|
140
|
+
['component:host-store', ['studio-create', 'studio-update', 'studio-get', 'index-entry']],
|
|
141
|
+
['component:host-tabs', ['open-tab']],
|
|
142
|
+
['component:renderer-views', ['studio-list', 'studio-model-view']],
|
|
143
|
+
['component:site-gist', ['site-gist-page', 'gist-load', 'to-portable']],
|
|
144
|
+
[CLI, ['cli-create']],
|
|
145
|
+
[SITE, ['site-gist-page', 'gist-load', 'to-portable']],
|
|
146
|
+
[HOST, ['studio-create', 'studio-update', 'studio-get', 'index-entry', 'open-tab']],
|
|
147
|
+
[RENDERER, ['studio-list', 'studio-model-view']],
|
|
148
|
+
[DISK, ['model-disk-store']],
|
|
149
|
+
[GITHUB, ['github-gists-api']],
|
|
150
|
+
]);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test('top-level memberships split all claimed components disjointly', () => {
|
|
154
|
+
const seen = new Set<string>();
|
|
155
|
+
for (const id of [HOST, RENDERER, CLI, SITE, GITHUB, DISK]) {
|
|
156
|
+
for (const alias of drilldownMembersOf(id) ?? []) {
|
|
157
|
+
expect(seen.has(alias), `${id} reuses ${alias}`).toBe(false);
|
|
158
|
+
seen.add(alias);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// 19 components total; the 6 library/proposed ones are intentionally
|
|
162
|
+
// claimed by nothing (asserted next), so 13 sit inside the C4 boxes.
|
|
163
|
+
expect(seen.size).toBe(13);
|
|
164
|
+
const unclaimed = DRILLDOWN_COMPONENTS.map((c) => c.alias).filter((a) => !seen.has(a));
|
|
165
|
+
expect(unclaimed.sort()).toEqual([
|
|
166
|
+
'gist-ref',
|
|
167
|
+
'gist-share-ui',
|
|
168
|
+
'host-binding',
|
|
169
|
+
'is-portable',
|
|
170
|
+
'portable-doc',
|
|
171
|
+
'react-graph',
|
|
172
|
+
]);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test('no container claims a library or proposed process — the anti-"library" rule', () => {
|
|
176
|
+
const claimed = new Set(
|
|
177
|
+
DRILLDOWN_C4_MODEL.nodes
|
|
178
|
+
.filter((n) => n.kind === 'container')
|
|
179
|
+
.map((n) => (n as { process?: string }).process)
|
|
180
|
+
.filter((p): p is string => !!p),
|
|
181
|
+
);
|
|
182
|
+
for (const excluded of ['subsystems-core/types', 'subsystems-react/ui', 'proposed/studio-gist']) {
|
|
183
|
+
expect(claimed.has(excluded), `claims ${excluded}`).toBe(false);
|
|
184
|
+
}
|
|
185
|
+
// …and every claim it DOES make exists in the document.
|
|
186
|
+
for (const process of claimed) {
|
|
187
|
+
expect(
|
|
188
|
+
DRILLDOWN_COMPONENTS.some((c) => c.process === process),
|
|
189
|
+
`claim ${process}`,
|
|
190
|
+
).toBe(true);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test('the rollup recomputes exactly the hand-authored trailRefs', () => {
|
|
195
|
+
for (const edge of DRILLDOWN_EDGES) {
|
|
196
|
+
const computed = rollupEdgeTrailRefs({
|
|
197
|
+
source: edge.source,
|
|
198
|
+
target: edge.target,
|
|
199
|
+
trails: DRILLDOWN_TRAILS,
|
|
200
|
+
membersOf,
|
|
201
|
+
});
|
|
202
|
+
expect(sortRefs(computed), `${edge.id} rollup`).toEqual(
|
|
203
|
+
sortRefs(edge.trailRefs ?? []),
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test('count is the total referenced steps; mechanisms their distinct verbs', () => {
|
|
209
|
+
for (const edge of DRILLDOWN_EDGES) {
|
|
210
|
+
if ((edge.trailRefs ?? []).length === 0) continue;
|
|
211
|
+
const steps = stepsOf(edge);
|
|
212
|
+
expect(edge.count, `${edge.id} count`).toBe(steps.length);
|
|
213
|
+
const verbs = [...new Set(steps.map((s) => s.mechanism))];
|
|
214
|
+
expect(edge.mechanisms, `${edge.id} mechanisms`).toEqual(verbs);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
test('the proposed trail contributes no accepted edges (its components are not claimed)', () => {
|
|
219
|
+
// The proposed gist-share walkthrough touches host/site/github, but its
|
|
220
|
+
// unclaimed proposed components keep it out of the accepted fold.
|
|
221
|
+
for (const edge of DRILLDOWN_EDGES) {
|
|
222
|
+
for (const ref of edge.trailRefs ?? []) {
|
|
223
|
+
expect(ref.trailId).not.toBe('tl-proposed-share-gist');
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
test('the renderer has no incident edges — only the proposed trail would attach lines to it', () => {
|
|
229
|
+
const incident = DRILLDOWN_EDGES.filter(
|
|
230
|
+
(e) => e.source === RENDERER || e.target === RENDERER,
|
|
231
|
+
);
|
|
232
|
+
expect(incident).toEqual([]);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
test('trail players: the containers/externals/parts each walkthrough actually touches', () => {
|
|
236
|
+
const playersOf = (id: string) =>
|
|
237
|
+
deriveTrailPlayerElements(
|
|
238
|
+
DRILLDOWN_TRAILS.find((t) => t.id === id)!.steps,
|
|
239
|
+
DRILLDOWN_MEMBERS,
|
|
240
|
+
);
|
|
241
|
+
const sortIds = (s: Set<string>) => [...s].sort();
|
|
242
|
+
|
|
243
|
+
// Site viewer: site page/loader parts + the GitHub API. The site CONTAINER
|
|
244
|
+
// is a player because its process claim owns the aliases — the visible
|
|
245
|
+
// card lights up at container view, and stays lit when opened (its parts
|
|
246
|
+
// are players too).
|
|
247
|
+
expect(sortIds(playersOf('tl-site-view-gist'))).toEqual(
|
|
248
|
+
sortIds(new Set([SITE, 'component:site-gist', GITHUB])),
|
|
249
|
+
);
|
|
250
|
+
// CLI create → host store → disk + tab open: both the CLI and host
|
|
251
|
+
// containers AND the authored parts nested under them play.
|
|
252
|
+
expect(sortIds(playersOf('tl-persist-local-store'))).toEqual(
|
|
253
|
+
sortIds(
|
|
254
|
+
new Set([
|
|
255
|
+
CLI,
|
|
256
|
+
'component:cli-command',
|
|
257
|
+
HOST,
|
|
258
|
+
'component:host-store',
|
|
259
|
+
'component:host-tabs',
|
|
260
|
+
DISK,
|
|
261
|
+
]),
|
|
262
|
+
),
|
|
263
|
+
);
|
|
264
|
+
// Proposed share: host + site parts + GitHub; no container for the
|
|
265
|
+
// unclaimed proposed aliases (gist-share-ui, gist-ref) — they light
|
|
266
|
+
// nothing, exactly like the anti-library stance.
|
|
267
|
+
expect(sortIds(playersOf('tl-proposed-share-gist'))).toEqual(
|
|
268
|
+
sortIds(new Set([HOST, 'component:host-store', SITE, 'component:site-gist', GITHUB])),
|
|
269
|
+
);
|
|
270
|
+
// A step between two unclaimed aliases (library/proposed components)
|
|
271
|
+
// contributes no players at all — the dim set is the whole model.
|
|
272
|
+
expect(
|
|
273
|
+
playersOf('tl-site-view-gist').size,
|
|
274
|
+
).toBeGreaterThan(0);
|
|
275
|
+
expect(
|
|
276
|
+
deriveTrailPlayerElements(
|
|
277
|
+
[{ from: 'react-graph', to: 'gist-ref' }],
|
|
278
|
+
DRILLDOWN_MEMBERS,
|
|
279
|
+
),
|
|
280
|
+
).toEqual(new Set());
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
test('lit edges: only the lines that carry the focused trail / hovered step', () => {
|
|
284
|
+
const lit = (source: { trailId: string; stepIndex?: number }) =>
|
|
285
|
+
[...deriveLitC4Edges(source, DRILLDOWN_EDGES)].sort();
|
|
286
|
+
|
|
287
|
+
// Whole trail → every line its steps fold into.
|
|
288
|
+
expect(lit({ trailId: 'tl-persist-local-store' })).toEqual(['e:cli-host', 'e:host-disk']);
|
|
289
|
+
expect(lit({ trailId: 'tl-site-view-gist' })).toEqual(['e:site-github']);
|
|
290
|
+
|
|
291
|
+
// A boundary step lights exactly its folding line.
|
|
292
|
+
expect(lit({ trailId: 'tl-persist-local-store', stepIndex: 0 })).toEqual(['e:cli-host']);
|
|
293
|
+
expect(lit({ trailId: 'tl-persist-local-store', stepIndex: 1 })).toEqual(['e:host-disk']);
|
|
294
|
+
expect(lit({ trailId: 'tl-site-view-gist', stepIndex: 1 })).toEqual(['e:site-github']);
|
|
295
|
+
|
|
296
|
+
// A step entirely internal to a container folds into NO line — lit is
|
|
297
|
+
// empty, so every edge dims: no drawn edge represents that hop.
|
|
298
|
+
expect(lit({ trailId: 'tl-persist-local-store', stepIndex: 2 })).toEqual([]); // studio-create → index-entry, both in HOST
|
|
299
|
+
expect(lit({ trailId: 'tl-site-view-gist', stepIndex: 0 })).toEqual([]); // site-gist-page → gist-load, both in SITE
|
|
300
|
+
expect(lit({ trailId: 'tl-site-view-gist', stepIndex: 3 })).toEqual([]); // site → react-graph, unclaimed target
|
|
301
|
+
|
|
302
|
+
// The proposed trail is outside the accepted fold: it lights no line.
|
|
303
|
+
expect(lit({ trailId: 'tl-proposed-share-gist' })).toEqual([]);
|
|
304
|
+
expect(lit({ trailId: 'tl-proposed-share-gist', stepIndex: 3 })).toEqual([]);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
test('code process keys: exactly the processes the accepted element set backs with nothing', () => {
|
|
308
|
+
// An element backs a process by claiming the key (containers) or carrying
|
|
309
|
+
// a member whose component claims it (externals, L3 children). What
|
|
310
|
+
// nobody backs draws as a code boundary in the component graph — package
|
|
311
|
+
// chrome, not the solid runtime chrome a deployment unit wears.
|
|
312
|
+
const code = deriveCodeProcessKeys(DRILLDOWN_C4_MODEL.nodes, DRILLDOWN_COMPONENTS);
|
|
313
|
+
expect([...code].sort()).toEqual([
|
|
314
|
+
'proposed/studio-gist',
|
|
315
|
+
'subsystems-core/types',
|
|
316
|
+
'subsystems-react/ui',
|
|
317
|
+
]);
|
|
318
|
+
|
|
319
|
+
// Every process an accepted element covers keeps its runtime chrome:
|
|
320
|
+
// the four container-backed units plus the two store/external systems.
|
|
321
|
+
const runtime = [
|
|
322
|
+
'external/github',
|
|
323
|
+
'local/disk',
|
|
324
|
+
'principal-studio-cli',
|
|
325
|
+
'site/web',
|
|
326
|
+
'subsystems-studio/host',
|
|
327
|
+
'subsystems-studio/renderer',
|
|
328
|
+
];
|
|
329
|
+
for (const key of runtime) expect(code.has(key)).toBe(false);
|
|
330
|
+
|
|
331
|
+
// And the set covers every distinct process in the model — nothing is
|
|
332
|
+
// decided by omission.
|
|
333
|
+
const all = new Set(
|
|
334
|
+
DRILLDOWN_COMPONENTS.map((c) => c.process).filter((p): p is string => Boolean(p)),
|
|
335
|
+
);
|
|
336
|
+
expect(new Set([...all].filter((k) => !code.has(k))).size).toBe(runtime.length);
|
|
337
|
+
});
|
|
338
|
+
});
|