@aiready/visualizer 0.2.2 → 0.2.3

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.
@@ -4,7 +4,7 @@
4
4
  <meta charset="utf-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>AIReady Visualizer (Dev)</title>
7
- <script type="module" crossorigin src="/assets/index-DDde_9Ig.js"></script>
7
+ <script type="module" crossorigin src="/assets/index-DtRHZjJ3.js"></script>
8
8
  <link rel="stylesheet" crossorigin href="/assets/index-CV7175vq.css">
9
9
  </head>
10
10
  <body>
package/web/src/App.tsx CHANGED
@@ -45,30 +45,35 @@ function App() {
45
45
  // Load report data
46
46
  useEffect(() => {
47
47
  const loadData = async () => {
48
- const reportData = await loadReportData();
49
-
50
- if (!reportData) {
51
- setError(
52
- 'No scan data found. Run "pnpm aiready scan ." then copy to public/report-data.json'
53
- );
48
+ try {
49
+ const reportData = await loadReportData();
50
+
51
+ if (!reportData) {
52
+ setError(
53
+ 'No scan data found. Run "pnpm aiready scan ." then copy to public/report-data.json'
54
+ );
55
+ setLoading(false);
56
+ return;
57
+ }
58
+
59
+ // Extract optional visualizer config from report (injected by CLI)
60
+ const visualizerConfig = (reportData as any).visualizerConfig;
61
+ const graphData = transformReportToGraph(reportData, visualizerConfig);
62
+ setData(graphData);
63
+
64
+ // Show warning if graph was truncated
65
+ if (graphData.truncated?.nodes || graphData.truncated?.edges) {
66
+ setTruncatedWarning({
67
+ nodes: graphData.truncated.nodes,
68
+ edges: graphData.truncated.edges,
69
+ });
70
+ }
71
+ } catch (err: any) {
72
+ console.error('Failed to load or transform report data:', err);
73
+ setError(`Failed to load visualization: ${err.message || 'Unknown error'}`);
74
+ } finally {
54
75
  setLoading(false);
55
- return;
56
- }
57
-
58
- // Extract optional visualizer config from report (injected by CLI)
59
- const visualizerConfig = (reportData as any).visualizerConfig;
60
- const graphData = transformReportToGraph(reportData, visualizerConfig);
61
- setData(graphData);
62
-
63
- // Show warning if graph was truncated
64
- if (graphData.truncated?.nodes || graphData.truncated?.edges) {
65
- setTruncatedWarning({
66
- nodes: graphData.truncated.nodes,
67
- edges: graphData.truncated.edges,
68
- });
69
76
  }
70
-
71
- setLoading(false);
72
77
  };
73
78
 
74
79
  loadData();
package/web/src/utils.ts CHANGED
@@ -52,7 +52,7 @@ function extractBusinessMetrics(report: ReportData): BusinessMetrics {
52
52
  }
53
53
 
54
54
  export function transformReportToGraph(
55
- report: ReportData,
55
+ report: any,
56
56
  runtimeGraphConfig?: { maxNodes?: number; maxEdges?: number }
57
57
  ): GraphData {
58
58
  // Use runtime config if available (from aiready.json), else use defaults from constants
@@ -60,6 +60,12 @@ export function transformReportToGraph(
60
60
  maxNodes: runtimeGraphConfig?.maxNodes ?? GRAPH_CONFIG.maxNodes,
61
61
  maxEdges: runtimeGraphConfig?.maxEdges ?? GRAPH_CONFIG.maxEdges,
62
62
  };
63
+
64
+ // Support both legacy and unified report formats
65
+ const patterns = report.patternDetect?.results || report.patterns || [];
66
+ const duplicates = report.patternDetect?.duplicates || report.duplicates || [];
67
+ const context = report.contextAnalyzer?.results || report.context || [];
68
+
63
69
  const nodes: FileNode[] = [];
64
70
  const edges: GraphEdge[] = [];
65
71
  const nodeMap = new Map<string, FileNode>();
@@ -69,16 +75,18 @@ export function transformReportToGraph(
69
75
  { count: number; severities: Set<string>; maxSeverity: string }
70
76
  >();
71
77
 
72
- for (const pattern of report.patterns) {
78
+ const severityPriority: Record<string, number> = {
79
+ critical: 4,
80
+ major: 3,
81
+ minor: 2,
82
+ info: 1,
83
+ default: 0,
84
+ };
85
+
86
+ for (const pattern of patterns) {
73
87
  const issueCount = pattern.issues?.length || 0;
74
88
  if (issueCount > 0) {
75
89
  let maxSeverity = 'info';
76
- const severityPriority: Record<string, number> = {
77
- critical: 4,
78
- major: 3,
79
- minor: 2,
80
- info: 1,
81
- };
82
90
  for (const issue of pattern.issues) {
83
91
  if (
84
92
  (severityPriority[issue.severity] || 0) >
@@ -95,7 +103,7 @@ export function transformReportToGraph(
95
103
  }
96
104
  }
97
105
 
98
- for (const ctx of report.context) {
106
+ for (const ctx of context) {
99
107
  // Try direct match first. If not found, try basename fallback so that
100
108
  // pattern entries with different path styles still associate their
101
109
  // severity with the context file in consumer reports.
@@ -114,8 +122,8 @@ export function transformReportToGraph(
114
122
 
115
123
  const titleLines = [
116
124
  `Token Cost: ${tokenCost}`,
117
- `Lines of Code: ${ctx.linesOfCode}`,
118
- `Dependencies: ${ctx.dependencyCount}`,
125
+ `Lines of Code: ${ctx.linesOfCode ?? 'n/a'}`,
126
+ `Dependencies: ${ctx.dependencyCount ?? 0}`,
119
127
  ];
120
128
 
121
129
  if (issues) {
@@ -142,7 +150,10 @@ export function transformReportToGraph(
142
150
  nodeMap.set(ctx.file, node);
143
151
  }
144
152
 
145
- for (const ctx of report.context) {
153
+ // Pre-calculate node keys for faster matching
154
+ const nodeKeys = Array.from(nodeMap.keys());
155
+
156
+ for (const ctx of context) {
146
157
  const sourceDir = ctx.file.substring(0, ctx.file.lastIndexOf('/'));
147
158
  for (const dep of ctx.dependencyList || []) {
148
159
  if (dep.startsWith('.') || dep.startsWith('/')) {
@@ -171,7 +182,7 @@ export function transformReportToGraph(
171
182
  // Strategy 2: Fall back to loose endsWith matching
172
183
  if (!targetFile) {
173
184
  const depBase = normalizedDep.split('/').pop() || normalizedDep;
174
- targetFile = [...nodeMap.keys()].find(
185
+ targetFile = nodeKeys.find(
175
186
  (k) =>
176
187
  k.endsWith(`/${depBase}.ts`) ||
177
188
  k.endsWith(`/${depBase}.tsx`) ||
@@ -221,7 +232,7 @@ export function transformReportToGraph(
221
232
  /\.(ts|tsx|js|jsx)$/,
222
233
  ''
223
234
  );
224
- relatedId = [...nodeMap.keys()].find(
235
+ relatedId = nodeKeys.find(
225
236
  (k) =>
226
237
  k.endsWith(`/${relBase}.ts`) ||
227
238
  k.endsWith(`/${relBase}.tsx`) ||
@@ -243,7 +254,7 @@ export function transformReportToGraph(
243
254
  }
244
255
  }
245
256
 
246
- for (const dup of report.duplicates || []) {
257
+ for (const dup of duplicates) {
247
258
  if (nodeMap.has(dup.file1) && nodeMap.has(dup.file2)) {
248
259
  const exists = edges.some(
249
260
  (e) =>
@@ -290,6 +301,7 @@ export function transformReportToGraph(
290
301
  export async function loadReportData(): Promise<ReportData | null> {
291
302
  const possiblePaths = [
292
303
  '/report-data.json',
304
+ './report-data.json',
293
305
  '../report-data.json',
294
306
  '../../report-data.json',
295
307
  ];
@@ -298,7 +310,10 @@ export async function loadReportData(): Promise<ReportData | null> {
298
310
  try {
299
311
  const response = await fetch(path);
300
312
  if (response.ok) {
301
- return await response.json();
313
+ const data = await response.json();
314
+ // If it's a unified report, it might be nested under 'results' if it was a deep clone
315
+ // but typically unified report IS the data.
316
+ return data;
302
317
  }
303
318
  } catch {
304
319
  continue;
@@ -311,7 +326,7 @@ export async function loadReportData(): Promise<ReportData | null> {
311
326
  export function getEdgeDistance(type: string): number {
312
327
  return (
313
328
  GRAPH_CONFIG.edgeDistances[
314
- type as keyof typeof GRAPH_CONFIG.edgeDistances
329
+ type as keyof typeof GRAPH_CONFIG.edgeDistances
315
330
  ] ?? GRAPH_CONFIG.edgeDistances.dependency
316
331
  );
317
332
  }
@@ -319,7 +334,7 @@ export function getEdgeDistance(type: string): number {
319
334
  export function getEdgeStrength(type: string): number {
320
335
  return (
321
336
  GRAPH_CONFIG.edgeStrengths[
322
- type as keyof typeof GRAPH_CONFIG.edgeStrengths
337
+ type as keyof typeof GRAPH_CONFIG.edgeStrengths
323
338
  ] ?? GRAPH_CONFIG.edgeStrengths.dependency
324
339
  );
325
340
  }
@@ -327,7 +342,7 @@ export function getEdgeStrength(type: string): number {
327
342
  export function getEdgeOpacity(type: string): number {
328
343
  return (
329
344
  GRAPH_CONFIG.edgeOpacities[
330
- type as keyof typeof GRAPH_CONFIG.edgeOpacities
345
+ type as keyof typeof GRAPH_CONFIG.edgeOpacities
331
346
  ] ?? GRAPH_CONFIG.edgeOpacities.dependency
332
347
  );
333
348
  }