@aiready/visualizer 0.2.0 → 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.
- package/dist/cli.js +13 -7
- package/dist/cli.js.map +1 -1
- package/dist/graph/index.js +13 -7
- package/dist/graph/index.js.map +1 -1
- package/dist/index.js +13 -7
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/web/dist/assets/index-DtRHZjJ3.js +10 -0
- package/web/dist/index.html +1 -1
- package/web/src/App.tsx +27 -22
- package/web/src/utils.ts +34 -19
- package/web/dist/assets/index-DDde_9Ig.js +0 -10
package/web/dist/index.html
CHANGED
|
@@ -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-
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
345
|
+
type as keyof typeof GRAPH_CONFIG.edgeOpacities
|
|
331
346
|
] ?? GRAPH_CONFIG.edgeOpacities.dependency
|
|
332
347
|
);
|
|
333
348
|
}
|