@opensip-cli/dashboard 0.1.10 → 0.1.12

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.
Files changed (150) hide show
  1. package/README.md +4 -2
  2. package/dist/client-bundle.generated.d.ts.map +1 -1
  3. package/dist/client-bundle.generated.js +1 -1
  4. package/dist/client-bundle.generated.js.map +1 -1
  5. package/dist/code-paths/graph-view-model.js +0 -1
  6. package/dist/code-paths/graph-view-model.js.map +1 -1
  7. package/dist/css/theme.js +1 -1
  8. package/dist/generator.d.ts +2 -0
  9. package/dist/generator.d.ts.map +1 -1
  10. package/dist/generator.js +10 -4
  11. package/dist/generator.js.map +1 -1
  12. package/dist/report-cup-icon.d.ts +17 -0
  13. package/dist/report-cup-icon.d.ts.map +1 -0
  14. package/dist/report-cup-icon.js +34 -0
  15. package/dist/report-cup-icon.js.map +1 -0
  16. package/dist/tool-tabs-registrations.js +10 -0
  17. package/dist/tool-tabs-registrations.js.map +1 -1
  18. package/package.json +3 -3
  19. package/dist/__tests__/catalog-provenance.test.d.ts +0 -11
  20. package/dist/__tests__/catalog-provenance.test.d.ts.map +0 -1
  21. package/dist/__tests__/catalog-provenance.test.js +0 -112
  22. package/dist/__tests__/catalog-provenance.test.js.map +0 -1
  23. package/dist/__tests__/coupling-attribution.test.d.ts +0 -9
  24. package/dist/__tests__/coupling-attribution.test.d.ts.map +0 -1
  25. package/dist/__tests__/coupling-attribution.test.js +0 -95
  26. package/dist/__tests__/coupling-attribution.test.js.map +0 -1
  27. package/dist/__tests__/dashboard-bundle-weight.test.d.ts +0 -23
  28. package/dist/__tests__/dashboard-bundle-weight.test.d.ts.map +0 -1
  29. package/dist/__tests__/dashboard-bundle-weight.test.js +0 -80
  30. package/dist/__tests__/dashboard-bundle-weight.test.js.map +0 -1
  31. package/dist/__tests__/dashboard-cell-containment.test.d.ts +0 -2
  32. package/dist/__tests__/dashboard-cell-containment.test.d.ts.map +0 -1
  33. package/dist/__tests__/dashboard-cell-containment.test.js +0 -52
  34. package/dist/__tests__/dashboard-cell-containment.test.js.map +0 -1
  35. package/dist/__tests__/dashboard-cytoscape-vendor.test.d.ts +0 -10
  36. package/dist/__tests__/dashboard-cytoscape-vendor.test.d.ts.map +0 -1
  37. package/dist/__tests__/dashboard-cytoscape-vendor.test.js +0 -40
  38. package/dist/__tests__/dashboard-cytoscape-vendor.test.js.map +0 -1
  39. package/dist/__tests__/dashboard-editor-link.test.d.ts +0 -14
  40. package/dist/__tests__/dashboard-editor-link.test.d.ts.map +0 -1
  41. package/dist/__tests__/dashboard-editor-link.test.js +0 -87
  42. package/dist/__tests__/dashboard-editor-link.test.js.map +0 -1
  43. package/dist/__tests__/dashboard-el.test.d.ts +0 -18
  44. package/dist/__tests__/dashboard-el.test.d.ts.map +0 -1
  45. package/dist/__tests__/dashboard-el.test.js +0 -90
  46. package/dist/__tests__/dashboard-el.test.js.map +0 -1
  47. package/dist/__tests__/dashboard-filters.test.d.ts +0 -9
  48. package/dist/__tests__/dashboard-filters.test.d.ts.map +0 -1
  49. package/dist/__tests__/dashboard-filters.test.js +0 -87
  50. package/dist/__tests__/dashboard-filters.test.js.map +0 -1
  51. package/dist/__tests__/dashboard-function-card-singleton.test.d.ts +0 -9
  52. package/dist/__tests__/dashboard-function-card-singleton.test.d.ts.map +0 -1
  53. package/dist/__tests__/dashboard-function-card-singleton.test.js +0 -75
  54. package/dist/__tests__/dashboard-function-card-singleton.test.js.map +0 -1
  55. package/dist/__tests__/dashboard-function-card.test.d.ts +0 -10
  56. package/dist/__tests__/dashboard-function-card.test.d.ts.map +0 -1
  57. package/dist/__tests__/dashboard-function-card.test.js +0 -439
  58. package/dist/__tests__/dashboard-function-card.test.js.map +0 -1
  59. package/dist/__tests__/dashboard-function-row.test.d.ts +0 -11
  60. package/dist/__tests__/dashboard-function-row.test.d.ts.map +0 -1
  61. package/dist/__tests__/dashboard-function-row.test.js +0 -102
  62. package/dist/__tests__/dashboard-function-row.test.js.map +0 -1
  63. package/dist/__tests__/dashboard-generator-graph-catalog.test.d.ts +0 -9
  64. package/dist/__tests__/dashboard-generator-graph-catalog.test.d.ts.map +0 -1
  65. package/dist/__tests__/dashboard-generator-graph-catalog.test.js +0 -77
  66. package/dist/__tests__/dashboard-generator-graph-catalog.test.js.map +0 -1
  67. package/dist/__tests__/dashboard-graph-offline.integration.test.d.ts +0 -13
  68. package/dist/__tests__/dashboard-graph-offline.integration.test.d.ts.map +0 -1
  69. package/dist/__tests__/dashboard-graph-offline.integration.test.js +0 -57
  70. package/dist/__tests__/dashboard-graph-offline.integration.test.js.map +0 -1
  71. package/dist/__tests__/dashboard-graph-scc.test.d.ts +0 -17
  72. package/dist/__tests__/dashboard-graph-scc.test.d.ts.map +0 -1
  73. package/dist/__tests__/dashboard-graph-scc.test.js +0 -89
  74. package/dist/__tests__/dashboard-graph-scc.test.js.map +0 -1
  75. package/dist/__tests__/dashboard-graph-view-model.test.d.ts +0 -12
  76. package/dist/__tests__/dashboard-graph-view-model.test.d.ts.map +0 -1
  77. package/dist/__tests__/dashboard-graph-view-model.test.js +0 -331
  78. package/dist/__tests__/dashboard-graph-view-model.test.js.map +0 -1
  79. package/dist/__tests__/dashboard-help-drawer.test.d.ts +0 -9
  80. package/dist/__tests__/dashboard-help-drawer.test.d.ts.map +0 -1
  81. package/dist/__tests__/dashboard-help-drawer.test.js +0 -95
  82. package/dist/__tests__/dashboard-help-drawer.test.js.map +0 -1
  83. package/dist/__tests__/dashboard-html.test.d.ts +0 -2
  84. package/dist/__tests__/dashboard-html.test.d.ts.map +0 -1
  85. package/dist/__tests__/dashboard-html.test.js +0 -169
  86. package/dist/__tests__/dashboard-html.test.js.map +0 -1
  87. package/dist/__tests__/dashboard-indexes.test.d.ts +0 -11
  88. package/dist/__tests__/dashboard-indexes.test.d.ts.map +0 -1
  89. package/dist/__tests__/dashboard-indexes.test.js +0 -214
  90. package/dist/__tests__/dashboard-indexes.test.js.map +0 -1
  91. package/dist/__tests__/dashboard-pagination.test.d.ts +0 -15
  92. package/dist/__tests__/dashboard-pagination.test.d.ts.map +0 -1
  93. package/dist/__tests__/dashboard-pagination.test.js +0 -140
  94. package/dist/__tests__/dashboard-pagination.test.js.map +0 -1
  95. package/dist/__tests__/dashboard-path-utils.test.d.ts +0 -13
  96. package/dist/__tests__/dashboard-path-utils.test.d.ts.map +0 -1
  97. package/dist/__tests__/dashboard-path-utils.test.js +0 -62
  98. package/dist/__tests__/dashboard-path-utils.test.js.map +0 -1
  99. package/dist/__tests__/dashboard-search.test.d.ts +0 -10
  100. package/dist/__tests__/dashboard-search.test.d.ts.map +0 -1
  101. package/dist/__tests__/dashboard-search.test.js +0 -52
  102. package/dist/__tests__/dashboard-search.test.js.map +0 -1
  103. package/dist/__tests__/dashboard-sessions.test.d.ts +0 -14
  104. package/dist/__tests__/dashboard-sessions.test.d.ts.map +0 -1
  105. package/dist/__tests__/dashboard-sessions.test.js +0 -332
  106. package/dist/__tests__/dashboard-sessions.test.js.map +0 -1
  107. package/dist/__tests__/dashboard-trace.test.d.ts +0 -16
  108. package/dist/__tests__/dashboard-trace.test.d.ts.map +0 -1
  109. package/dist/__tests__/dashboard-trace.test.js +0 -170
  110. package/dist/__tests__/dashboard-trace.test.js.map +0 -1
  111. package/dist/__tests__/dashboard-validation.integration.test.d.ts +0 -14
  112. package/dist/__tests__/dashboard-validation.integration.test.d.ts.map +0 -1
  113. package/dist/__tests__/dashboard-validation.integration.test.js +0 -221
  114. package/dist/__tests__/dashboard-validation.integration.test.js.map +0 -1
  115. package/dist/__tests__/dashboard-view-conformance.test.d.ts +0 -12
  116. package/dist/__tests__/dashboard-view-conformance.test.d.ts.map +0 -1
  117. package/dist/__tests__/dashboard-view-conformance.test.js +0 -52
  118. package/dist/__tests__/dashboard-view-conformance.test.js.map +0 -1
  119. package/dist/__tests__/dashboard-view-coupling.test.d.ts +0 -7
  120. package/dist/__tests__/dashboard-view-coupling.test.d.ts.map +0 -1
  121. package/dist/__tests__/dashboard-view-coupling.test.js +0 -360
  122. package/dist/__tests__/dashboard-view-coupling.test.js.map +0 -1
  123. package/dist/__tests__/dashboard-view-distribution.test.d.ts +0 -10
  124. package/dist/__tests__/dashboard-view-distribution.test.d.ts.map +0 -1
  125. package/dist/__tests__/dashboard-view-distribution.test.js +0 -249
  126. package/dist/__tests__/dashboard-view-distribution.test.js.map +0 -1
  127. package/dist/__tests__/dashboard-view-graph.test.d.ts +0 -13
  128. package/dist/__tests__/dashboard-view-graph.test.d.ts.map +0 -1
  129. package/dist/__tests__/dashboard-view-graph.test.js +0 -299
  130. package/dist/__tests__/dashboard-view-graph.test.js.map +0 -1
  131. package/dist/__tests__/dashboard-view-template.test.d.ts +0 -20
  132. package/dist/__tests__/dashboard-view-template.test.d.ts.map +0 -1
  133. package/dist/__tests__/dashboard-view-template.test.js +0 -206
  134. package/dist/__tests__/dashboard-view-template.test.js.map +0 -1
  135. package/dist/__tests__/dashboard.test.d.ts +0 -2
  136. package/dist/__tests__/dashboard.test.d.ts.map +0 -1
  137. package/dist/__tests__/dashboard.test.js +0 -129
  138. package/dist/__tests__/dashboard.test.js.map +0 -1
  139. package/dist/__tests__/graph-tab.test.d.ts +0 -10
  140. package/dist/__tests__/graph-tab.test.d.ts.map +0 -1
  141. package/dist/__tests__/graph-tab.test.js +0 -78
  142. package/dist/__tests__/graph-tab.test.js.map +0 -1
  143. package/dist/client/el.d.ts +0 -17
  144. package/dist/client/el.d.ts.map +0 -1
  145. package/dist/client/el.js +0 -36
  146. package/dist/client/el.js.map +0 -1
  147. package/dist/code-paths/__tests__/views-registry.test.d.ts +0 -18
  148. package/dist/code-paths/__tests__/views-registry.test.d.ts.map +0 -1
  149. package/dist/code-paths/__tests__/views-registry.test.js +0 -41
  150. package/dist/code-paths/__tests__/views-registry.test.js.map +0 -1
@@ -1,331 +0,0 @@
1
- /**
2
- * View-model projection — `projectCatalogToGraphViewModel`.
3
- *
4
- * The projector aggregates the function call graph up to PACKAGE granularity
5
- * (item 10): one node per package, one edge per directed package→package
6
- * coupling with a call-count weight. These tests lock the schema, the
7
- * package-attribution (mirroring `pkgOf`), the weight accounting, the
8
- * totalCoupling sizing input, the external-target drop, the cross-package SCC
9
- * pass, and the byte budget.
10
- */
11
- import { readFileSync } from 'node:fs';
12
- import { dirname, join } from 'node:path';
13
- import { fileURLToPath } from 'node:url';
14
- import { describe, expect, it } from 'vitest';
15
- import { GraphViewModelError, packageOf, projectCatalogToGraphViewModel, } from '../code-paths/graph-view-model.js';
16
- const HERE = dirname(fileURLToPath(import.meta.url));
17
- function loadFixture() {
18
- const candidates = [
19
- join(HERE, 'fixtures', 'catalog-small.json'),
20
- join(HERE, '..', '..', 'src', '__tests__', 'fixtures', 'catalog-small.json'),
21
- ];
22
- for (const p of candidates) {
23
- try {
24
- return JSON.parse(readFileSync(p, 'utf8'));
25
- }
26
- catch {
27
- // try next candidate
28
- }
29
- }
30
- throw new Error('catalog-small.json fixture not found');
31
- }
32
- function makeOcc(over) {
33
- return {
34
- qualifiedName: over.simpleName,
35
- filePath: 'packages/x/src/x.ts',
36
- line: 1,
37
- column: 0,
38
- endLine: 5,
39
- kind: 'function-declaration',
40
- params: [],
41
- returnType: null,
42
- enclosingClass: null,
43
- decorators: [],
44
- visibility: 'exported',
45
- inTestFile: false,
46
- definedInGenerated: false,
47
- calls: [],
48
- ...over,
49
- };
50
- }
51
- /** A two-package catalog: package "a" (a1→a2 internal, a1→b1 cross) and
52
- * package "b" (b1→a1 cross — forms an a↔b cycle). */
53
- function twoPackageCatalog() {
54
- return {
55
- version: '3.0',
56
- tool: 'graph',
57
- language: 'typescript',
58
- builtAt: 'now',
59
- functions: {
60
- a1: [
61
- makeOcc({
62
- bodyHash: 'a1',
63
- simpleName: 'a1',
64
- package: '@scope/pkg-a',
65
- filePath: 'packages/pkg-a/src/a1.ts',
66
- calls: [
67
- {
68
- to: ['a2', 'b1'],
69
- line: 1,
70
- column: 0,
71
- resolution: 'static',
72
- confidence: 'high',
73
- text: 'c',
74
- },
75
- ],
76
- }),
77
- ],
78
- a2: [
79
- makeOcc({
80
- bodyHash: 'a2',
81
- simpleName: 'a2',
82
- package: '@scope/pkg-a',
83
- filePath: 'packages/pkg-a/src/a2.ts',
84
- calls: [
85
- {
86
- to: ['ext'],
87
- line: 2,
88
- column: 0,
89
- resolution: 'static',
90
- confidence: 'high',
91
- text: 'c',
92
- },
93
- ],
94
- }),
95
- ],
96
- b1: [
97
- makeOcc({
98
- bodyHash: 'b1',
99
- simpleName: 'b1',
100
- package: '@scope/pkg-b',
101
- filePath: 'packages/pkg-b/src/b1.ts',
102
- calls: [
103
- { to: ['a1'], line: 3, column: 0, resolution: 'static', confidence: 'high', text: 'c' },
104
- ],
105
- }),
106
- ],
107
- },
108
- };
109
- }
110
- describe('packageOf', () => {
111
- it('prefers the build-stamped package, scope-stripped', () => {
112
- expect(packageOf(makeOcc({ bodyHash: 'h', simpleName: 'f', package: '@opensip-cli/lang-typescript' }))).toBe('lang-typescript');
113
- });
114
- it('falls back to the path heuristic when package is absent', () => {
115
- expect(packageOf(makeOcc({ bodyHash: 'h', simpleName: 'f', filePath: 'packages/widget/src/x.ts' }))).toBe('widget');
116
- });
117
- it('returns <unknown> for an unattributable path', () => {
118
- expect(packageOf(makeOcc({ bodyHash: 'h', simpleName: 'f', filePath: 'random/x.ts' }))).toBe('<unknown>');
119
- });
120
- it('returns <unknown> when the occurrence is null/undefined or has no usable path', () => {
121
- expect(packageOf(null)).toBe('<unknown>');
122
- expect(packageOf(undefined)).toBe('<unknown>');
123
- expect(packageOf(makeOcc({ bodyHash: 'h', simpleName: 'f', filePath: '' }))).toBe('<unknown>');
124
- });
125
- it('ignores a non-string package value and a non-string path', () => {
126
- // package is the wrong type → fall back to the path heuristic.
127
- expect(packageOf(makeOcc({
128
- bodyHash: 'h',
129
- simpleName: 'f',
130
- package: 42,
131
- filePath: 'packages/widget/src/x.ts',
132
- }))).toBe('widget');
133
- // path is the wrong type → <unknown>.
134
- expect(packageOf(makeOcc({ bodyHash: 'h', simpleName: 'f', filePath: 123 }))).toBe('<unknown>');
135
- });
136
- });
137
- describe('projectCatalogToGraphViewModel (package-level)', () => {
138
- it('throws GraphViewModelError on a missing functions map', () => {
139
- expect(() => projectCatalogToGraphViewModel({})).toThrow(GraphViewModelError);
140
- });
141
- it('projects the real fixture into a stable view-model (snapshot)', () => {
142
- const vm = projectCatalogToGraphViewModel(loadFixture());
143
- expect(vm).toMatchSnapshot();
144
- });
145
- it('carries the catalog language on the root', () => {
146
- const vm = projectCatalogToGraphViewModel(loadFixture());
147
- expect(vm.language).toBe('typescript');
148
- });
149
- it('emits PACKAGE nodes (id = label = package name) — not function nodes', () => {
150
- const vm = projectCatalogToGraphViewModel(twoPackageCatalog());
151
- const ids = vm.nodes.map((n) => n.id).sort();
152
- expect(ids).toEqual(['pkg-a', 'pkg-b']);
153
- for (const node of vm.nodes) {
154
- expect(node.id).toBe(node.label);
155
- // No function-level fields leak into the package node.
156
- expect(node).not.toHaveProperty('kind');
157
- expect(node).not.toHaveProperty('filePath');
158
- expect(node).not.toHaveProperty('bodyHash');
159
- expect(typeof node.totalCoupling).toBe('number');
160
- }
161
- });
162
- it('emits package→package edges with a call-count weight', () => {
163
- const vm = projectCatalogToGraphViewModel(twoPackageCatalog());
164
- const byKey = new Map(vm.edges.map((e) => [e.source + '->' + e.target, e]));
165
- // a1→a2 is an internal package-a call → self-loop weight 1.
166
- expect(byKey.get('pkg-a->pkg-a')?.weight).toBe(1);
167
- // a1→b1 cross edge, weight 1.
168
- expect(byKey.get('pkg-a->pkg-b')?.weight).toBe(1);
169
- // b1→a1 cross edge, weight 1.
170
- expect(byKey.get('pkg-b->pkg-a')?.weight).toBe(1);
171
- });
172
- it('aggregates multiple function calls between the same package pair into one weighted edge', () => {
173
- const catalog = {
174
- version: '3.0',
175
- tool: 'graph',
176
- language: 'typescript',
177
- builtAt: 'now',
178
- functions: {
179
- a: [
180
- makeOcc({
181
- bodyHash: 'a',
182
- simpleName: 'a',
183
- package: '@s/pa',
184
- filePath: 'packages/pa/src/a.ts',
185
- calls: [
186
- {
187
- to: ['x', 'y'],
188
- line: 1,
189
- column: 0,
190
- resolution: 'static',
191
- confidence: 'high',
192
- text: 'c',
193
- },
194
- ],
195
- }),
196
- ],
197
- x: [
198
- makeOcc({
199
- bodyHash: 'x',
200
- simpleName: 'x',
201
- package: '@s/pb',
202
- filePath: 'packages/pb/src/x.ts',
203
- }),
204
- ],
205
- y: [
206
- makeOcc({
207
- bodyHash: 'y',
208
- simpleName: 'y',
209
- package: '@s/pb',
210
- filePath: 'packages/pb/src/y.ts',
211
- }),
212
- ],
213
- },
214
- };
215
- const vm = projectCatalogToGraphViewModel(catalog);
216
- const edge = vm.edges.find((e) => e.source === 'pa' && e.target === 'pb');
217
- expect(edge?.weight).toBe(2);
218
- });
219
- it('drops calls whose target is not an in-project function (external)', () => {
220
- const vm = projectCatalogToGraphViewModel(twoPackageCatalog());
221
- // a2 calls only an external 'ext' — it must NOT create any edge.
222
- expect(vm.edges.some((e) => e.target === '<unknown>' || e.target === 'ext')).toBe(false);
223
- });
224
- it('sets totalCoupling = sum of incident edge weights (fan-in + fan-out)', () => {
225
- const vm = projectCatalogToGraphViewModel(twoPackageCatalog());
226
- for (const node of vm.nodes) {
227
- const incident = vm.edges
228
- .filter((e) => e.source === node.id || e.target === node.id)
229
- // a self-loop contributes its weight to both fan-in and fan-out.
230
- .reduce((sum, e) => sum + (e.source === node.id ? e.weight : 0) + (e.target === node.id ? e.weight : 0), 0);
231
- expect(node.totalCoupling).toBe(incident);
232
- }
233
- });
234
- it('stamps a shared non-null sccId on a cross-package cycle (a↔b)', () => {
235
- const vm = projectCatalogToGraphViewModel(twoPackageCatalog());
236
- const sccIds = new Set(vm.nodes.map((n) => n.sccId));
237
- expect(sccIds.size).toBe(1);
238
- expect([...sccIds][0]).not.toBeNull();
239
- const crossCycleEdges = vm.edges.filter((e) => e.source !== e.target &&
240
- ['pkg-a', 'pkg-b'].includes(e.source) &&
241
- ['pkg-a', 'pkg-b'].includes(e.target));
242
- for (const e of crossCycleEdges)
243
- expect(e.isCycleEdge).toBe(true);
244
- });
245
- it('does NOT flag a package as cyclic just because it has internal (self-loop) calls', () => {
246
- const catalog = {
247
- version: '3.0',
248
- tool: 'graph',
249
- language: 'typescript',
250
- builtAt: 'now',
251
- functions: {
252
- a: [
253
- makeOcc({
254
- bodyHash: 'a',
255
- simpleName: 'a',
256
- package: '@s/solo',
257
- filePath: 'packages/solo/src/a.ts',
258
- calls: [
259
- {
260
- to: ['b'],
261
- line: 1,
262
- column: 0,
263
- resolution: 'static',
264
- confidence: 'high',
265
- text: 'c',
266
- },
267
- ],
268
- }),
269
- ],
270
- b: [
271
- makeOcc({
272
- bodyHash: 'b',
273
- simpleName: 'b',
274
- package: '@s/solo',
275
- filePath: 'packages/solo/src/b.ts',
276
- }),
277
- ],
278
- },
279
- };
280
- const vm = projectCatalogToGraphViewModel(catalog);
281
- expect(vm.nodes).toHaveLength(1);
282
- expect(vm.nodes[0].sccId).toBeNull();
283
- expect(vm.edges[0].isCycleEdge).toBe(false);
284
- });
285
- it('tolerates occurrences with no calls and edges with no targets (empty-array branches)', () => {
286
- const catalog = {
287
- version: '3.0',
288
- tool: 'graph',
289
- language: 'typescript',
290
- builtAt: 'now',
291
- functions: {
292
- // No `calls` at all.
293
- a: [
294
- makeOcc({
295
- bodyHash: 'a',
296
- simpleName: 'a',
297
- package: '@s/pa',
298
- filePath: 'packages/pa/src/a.ts',
299
- }),
300
- ],
301
- // A call edge with an empty `to` array.
302
- b: [
303
- makeOcc({
304
- bodyHash: 'b',
305
- simpleName: 'b',
306
- package: '@s/pa',
307
- filePath: 'packages/pa/src/b.ts',
308
- calls: [
309
- { to: [], line: 1, column: 0, resolution: 'static', confidence: 'high', text: 'c' },
310
- ],
311
- }),
312
- ],
313
- // An empty occurrences list for a function name.
314
- c: [],
315
- },
316
- };
317
- const vm = projectCatalogToGraphViewModel(catalog);
318
- expect(vm.nodes.map((n) => n.id)).toEqual(['pa']);
319
- expect(vm.edges).toHaveLength(0);
320
- expect(vm.nodes[0].totalCoupling).toBe(0);
321
- expect(vm.nodes[0].sccId).toBeNull();
322
- });
323
- it('keeps the JSON within a generous per-node/edge byte budget', () => {
324
- const vm = projectCatalogToGraphViewModel(loadFixture());
325
- const bytes = JSON.stringify(vm).length;
326
- // Package nodes are far slimmer than function nodes were.
327
- const budget = (vm.nodes.length * 120 + vm.edges.length * 80) * 1.5 + 512;
328
- expect(bytes).toBeLessThan(budget);
329
- });
330
- });
331
- //# sourceMappingURL=dashboard-graph-view-model.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dashboard-graph-view-model.test.js","sourceRoot":"","sources":["../../src/__tests__/dashboard-graph-view-model.test.ts"],"names":[],"mappings":"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"}
@@ -1,9 +0,0 @@
1
- /**
2
- * @vitest-environment jsdom
3
- *
4
- * Help drawer — opens with the active view's help content, closes on
5
- * × button, backdrop click, or Escape key. Only one drawer is on the
6
- * page at a time.
7
- */
8
- export {};
9
- //# sourceMappingURL=dashboard-help-drawer.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dashboard-help-drawer.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/dashboard-help-drawer.test.ts"],"names":[],"mappings":"AACA;;;;;;GAMG"}
@@ -1,95 +0,0 @@
1
- /// <reference lib="dom" />
2
- /**
3
- * @vitest-environment jsdom
4
- *
5
- * Help drawer — opens with the active view's help content, closes on
6
- * × button, backdrop click, or Escape key. Only one drawer is on the
7
- * page at a time.
8
- */
9
- import { describe, expect, it, beforeEach } from 'vitest';
10
- import { DASHBOARD_CLIENT_BUNDLE } from '../client-bundle.generated.js';
11
- function loadEnv() {
12
- // The views registry + help drawer (with `el`) now live in the typed client
13
- // bundle (L4) and are exposed as page globals; the bundle's help-drawer also
14
- // attaches its load-time Escape keydown handler. `var sessions = []` satisfies
15
- // checks.ts's load-time `computeCheckStats()` read.
16
- const shim = `
17
- // jsdom does not implement requestAnimationFrame in all configurations;
18
- // inline a synchronous shim so the drawer's open class is applied
19
- // deterministically inside the test.
20
- if (typeof requestAnimationFrame === 'undefined') {
21
- globalThis.requestAnimationFrame = (cb) => { cb(0); return 0; };
22
- }
23
- var sessions = [];
24
- `;
25
- const seed = `
26
- views.length = 0;
27
- views.push({
28
- id: 'hot',
29
- label: 'Hot functions',
30
- help: {
31
- title: 'Hot functions',
32
- sections: [
33
- { heading: 'What this is', body: 'Functions ranked by inbound call count.' },
34
- { heading: 'Why you care', body: 'Hot functions are leverage points.' },
35
- ],
36
- },
37
- render() {},
38
- });
39
- views.push({ id: 'no-help', label: 'No help', render() {} });
40
- return { openHelpDrawer, views };
41
- `;
42
- // eslint-disable-next-line @typescript-eslint/no-implied-eval, sonarjs/code-eval -- Trusted source: our own bundled dashboard JS.
43
- const factory = new Function(shim + DASHBOARD_CLIENT_BUNDLE + seed);
44
- return factory();
45
- }
46
- beforeEach(() => {
47
- document.body.innerHTML = '';
48
- });
49
- describe('help drawer', () => {
50
- it('opens with the view help title and renders every section', () => {
51
- const env = loadEnv();
52
- env.openHelpDrawer('hot');
53
- const drawer = document.querySelector('.help-drawer');
54
- expect(drawer).not.toBeNull();
55
- expect(drawer.querySelector('h3').textContent).toBe('Hot functions');
56
- // eslint-disable-next-line unicorn/prefer-spread -- NodeListOf spread requires lib.dom.iterable.
57
- const headings = Array.from(drawer.querySelectorAll('h4')).map((h) => h.textContent);
58
- expect(headings).toEqual(['What this is', 'Why you care']);
59
- expect(drawer.textContent).toContain('Functions ranked by inbound call count.');
60
- });
61
- it('does nothing for a view without a help block', () => {
62
- const env = loadEnv();
63
- env.openHelpDrawer('no-help');
64
- expect(document.querySelector('.help-drawer-overlay')).toBeNull();
65
- });
66
- it('closes via the × button', () => {
67
- const env = loadEnv();
68
- env.openHelpDrawer('hot');
69
- const closeBtn = document.querySelector('.help-drawer-close');
70
- closeBtn.click();
71
- expect(document.querySelector('.help-drawer-overlay')).toBeNull();
72
- });
73
- it('closes when the Escape key is pressed', () => {
74
- const env = loadEnv();
75
- env.openHelpDrawer('hot');
76
- document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }));
77
- expect(document.querySelector('.help-drawer-overlay')).toBeNull();
78
- });
79
- it('closes when the backdrop is clicked', () => {
80
- const env = loadEnv();
81
- env.openHelpDrawer('hot');
82
- const overlay = document.querySelector('.help-drawer-overlay');
83
- // Dispatch a click whose target is the overlay itself.
84
- const evt = new MouseEvent('click', { bubbles: true });
85
- overlay.dispatchEvent(evt);
86
- expect(document.querySelector('.help-drawer-overlay')).toBeNull();
87
- });
88
- it('only one drawer exists if open is called twice', () => {
89
- const env = loadEnv();
90
- env.openHelpDrawer('hot');
91
- env.openHelpDrawer('hot');
92
- expect(document.querySelectorAll('.help-drawer-overlay').length).toBe(1);
93
- });
94
- });
95
- //# sourceMappingURL=dashboard-help-drawer.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dashboard-help-drawer.test.js","sourceRoot":"","sources":["../../src/__tests__/dashboard-help-drawer.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=dashboard-html.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dashboard-html.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/dashboard-html.test.ts"],"names":[],"mappings":""}
@@ -1,169 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { generateDashboardHtml } from '../generator.js';
3
- // Fitness-shaped detail now lives in the tool-owned opaque `payload`;
4
- // `contracts` no longer carries summary/checks on StoredSession. The
5
- // dashboard inlines the whole session (payload included), so data
6
- // assertions below still hold.
7
- function fitnessPayload() {
8
- return {
9
- summary: { total: 10, passed: 8, failed: 2, errors: 1, warnings: 3 },
10
- checks: [
11
- { checkSlug: 'no-console-log', passed: true, findings: [], durationMs: 42 },
12
- {
13
- checkSlug: 'no-hardcoded-secrets',
14
- passed: false,
15
- findings: [
16
- {
17
- ruleId: 'secret-in-code',
18
- message: 'Found hardcoded secret',
19
- severity: 'error',
20
- filePath: 'src/config.ts',
21
- line: 15,
22
- },
23
- ],
24
- durationMs: 100,
25
- },
26
- ],
27
- };
28
- }
29
- function makeSession(overrides = {}) {
30
- return {
31
- id: 'test-session-1',
32
- tool: 'fit',
33
- startedAt: '2025-06-15T10:30:00.000Z',
34
- completedAt: '2025-06-15T10:30:00.000Z',
35
- // eslint-disable-next-line sonarjs/publicly-writable-directories -- test fixture cwd; not a runtime filesystem operation
36
- cwd: '/tmp/my-project',
37
- score: 85,
38
- passed: true,
39
- durationMs: 1234,
40
- payload: fitnessPayload(),
41
- ...overrides,
42
- };
43
- }
44
- describe('generateDashboardHtml', () => {
45
- it('returns valid HTML with doctype and closing tags', () => {
46
- const html = generateDashboardHtml({ sessions: [makeSession()] });
47
- expect(html).toContain('<!DOCTYPE html>');
48
- expect(html).toContain('<html lang="en">');
49
- expect(html).toContain('</html>');
50
- expect(html).toContain('</body>');
51
- expect(html).toContain('</head>');
52
- });
53
- it('handles empty sessions array', () => {
54
- const html = generateDashboardHtml({ sessions: [] });
55
- expect(html).toContain('<!DOCTYPE html>');
56
- // Title should not have a score
57
- expect(html).toContain('<title>OpenSIP CLI</title>');
58
- // The JS renders the "no sessions" message
59
- expect(html).toContain('No sessions yet');
60
- });
61
- it('includes latest session pass rate in the title', () => {
62
- const html = generateDashboardHtml({ sessions: [makeSession({ score: 92 })] });
63
- expect(html).toContain('Pass Rate: 92%');
64
- });
65
- it('includes session data as JSON in a script tag', () => {
66
- const session = makeSession({ id: 'embedded-data' });
67
- const html = generateDashboardHtml({ sessions: [session] });
68
- expect(html).toContain('embedded-data');
69
- expect(html).toContain('no-console-log');
70
- expect(html).toContain('no-hardcoded-secrets');
71
- });
72
- it('prevents script tag injection by escaping </ sequences', () => {
73
- // If session data contains "</script>", it could break out of the script tag.
74
- // The function replaces </ with <\/ to prevent this.
75
- const session = makeSession({
76
- payload: {
77
- summary: { total: 1, passed: 0, failed: 1, errors: 1, warnings: 0 },
78
- checks: [
79
- {
80
- checkSlug: 'xss-check',
81
- passed: false,
82
- findings: [
83
- {
84
- ruleId: 'xss',
85
- message: 'Contains </script><script>alert(1)</script> payload',
86
- severity: 'error',
87
- },
88
- ],
89
- durationMs: 10,
90
- },
91
- ],
92
- },
93
- });
94
- const html = generateDashboardHtml({ sessions: [session] });
95
- // The raw "</script>" inside the data should be escaped
96
- // It should NOT contain an unescaped </script> inside the data JSON
97
- const scriptStart = html.indexOf('const sessions = ');
98
- const scriptEnd = html.indexOf(';\nconst fitSessions');
99
- const jsonSection = html.slice(scriptStart, scriptEnd);
100
- // All < and > should be escaped as \u003c and \u003e in script context
101
- expect(jsonSection).not.toContain('</script>');
102
- expect(jsonSection).toContain(String.raw `\u003c/script\u003e`);
103
- });
104
- it('includes CSS with score color classes', () => {
105
- const html = generateDashboardHtml({ sessions: [makeSession()] });
106
- expect(html).toContain('.score-good');
107
- expect(html).toContain('.score-warn');
108
- expect(html).toContain('.score-bad');
109
- });
110
- it('includes the correct score class thresholds in JavaScript', () => {
111
- const html = generateDashboardHtml({ sessions: [makeSession()] });
112
- // The JS logic: score >= 90 -> score-good, >= 70 -> score-warn, else -> score-bad
113
- expect(html).toContain('score >= 90');
114
- expect(html).toContain('score >= 70');
115
- });
116
- it('includes check findings data', () => {
117
- const html = generateDashboardHtml({ sessions: [makeSession()] });
118
- expect(html).toContain('Found hardcoded secret');
119
- expect(html).toContain('src/config.ts');
120
- });
121
- it('includes recipe name when present', () => {
122
- const html = generateDashboardHtml({ sessions: [makeSession({ recipe: 'quick-smoke' })] });
123
- expect(html).toContain('quick-smoke');
124
- });
125
- it('includes the footer with opensip.ai link', () => {
126
- const html = generateDashboardHtml({ sessions: [makeSession()] });
127
- expect(html).toContain('opensip.ai');
128
- expect(html).toContain('OpenSIP CLI');
129
- });
130
- it('handles multiple sessions for trend chart', () => {
131
- const sessions = [
132
- makeSession({
133
- id: 's1',
134
- startedAt: '2025-06-15T10:30:00.000Z',
135
- completedAt: '2025-06-15T10:30:00.000Z',
136
- score: 95,
137
- }),
138
- makeSession({
139
- id: 's2',
140
- startedAt: '2025-06-14T10:30:00.000Z',
141
- completedAt: '2025-06-14T10:30:00.000Z',
142
- score: 80,
143
- }),
144
- makeSession({
145
- id: 's3',
146
- startedAt: '2025-06-13T10:30:00.000Z',
147
- completedAt: '2025-06-13T10:30:00.000Z',
148
- score: 65,
149
- }),
150
- ];
151
- const html = generateDashboardHtml({ sessions });
152
- // All session data should be embedded
153
- expect(html).toContain('"s1"');
154
- expect(html).toContain('"s2"');
155
- expect(html).toContain('"s3"');
156
- });
157
- it('does not include raw HTML in session data that could be executed', () => {
158
- const session = makeSession({
159
- cwd: '<img src=x onerror=alert(1)>',
160
- });
161
- const html = generateDashboardHtml({ sessions: [session] });
162
- // The data is consumed via textContent (safe), but the JSON should still be well-formed
163
- // The main concern is the </ escape to prevent script breakout
164
- expect(html).toContain('<!DOCTYPE html>');
165
- // Should still be valid HTML structure
166
- expect(html).toContain('</html>');
167
- });
168
- });
169
- //# sourceMappingURL=dashboard-html.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dashboard-html.test.js","sourceRoot":"","sources":["../../src/__tests__/dashboard-html.test.ts"],"names":[],"mappings":"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"}