next-arch-map 0.1.27 → 0.1.28
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/analyzers/pagesToEndpoints.js +19 -5
- package/dist/model.d.ts +2 -2
- package/dist/utils.d.ts +9 -0
- package/dist/utils.js +11 -0
- package/package.json +1 -1
- package/viewer/src/App.tsx +2 -0
- package/viewer/src/Filters.tsx +1 -0
- package/viewer/src/GraphView.tsx +3 -11
- package/viewer/src/NodeDetails.tsx +5 -6
- package/viewer/src/types.ts +4 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import ts from "typescript";
|
|
3
|
-
import { buildActionNode, buildEdgeKey, buildEndpointNode, buildPageNode, collectStringConstants, ensureNode, getExistingDirectories, getPageRouteFromFile, getSourceFile, getStringLiteralValue, isIgnoredSourceFile, isPageFile, resolveLocalModulePath, resolveProjectRoot, walkDirectory, } from "../utils.js";
|
|
3
|
+
import { buildActionNode, buildEdgeKey, buildEndpointNode, buildPageNode, buildServiceNode, collectStringConstants, ensureNode, getExistingDirectories, getPageRouteFromFile, getSourceFile, getStringLiteralValue, isIgnoredSourceFile, isPageFile, resolveLocalModulePath, resolveProjectRoot, walkDirectory, } from "../utils.js";
|
|
4
4
|
const DEFAULT_APP_DIRS = ["app", "src/app"];
|
|
5
5
|
const DEFAULT_EXTRA_SCAN_DIRS = ["src/features", "src/services", "src/lib", "src/hooks"];
|
|
6
6
|
const DEFAULT_HTTP_CLIENT_IDENTIFIERS = ["fetch", "axios", "apiClient"];
|
|
@@ -48,11 +48,26 @@ export async function analyzePagesToEndpoints(options) {
|
|
|
48
48
|
const route = getPageRouteFromFile(appDir, filePath);
|
|
49
49
|
ensureNode(nodes, nodeIds, buildPageNode(route, filePath));
|
|
50
50
|
for (const call of httpCalls) {
|
|
51
|
+
const pageNode = ensureNode(nodes, nodeIds, buildPageNode(route, filePath));
|
|
52
|
+
// SDK calls create a single service node per client (e.g. "supabase")
|
|
53
|
+
if (call.sdkClient) {
|
|
54
|
+
const serviceNode = ensureNode(nodes, nodeIds, buildServiceNode(call.sdkClient, filePath));
|
|
55
|
+
const edgeKey = buildEdgeKey(pageNode.id, serviceNode.id, "page-service");
|
|
56
|
+
if (!edgeKeys.has(edgeKey)) {
|
|
57
|
+
edgeKeys.add(edgeKey);
|
|
58
|
+
edges.push({
|
|
59
|
+
from: pageNode.id,
|
|
60
|
+
to: serviceNode.id,
|
|
61
|
+
kind: "page-service",
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
// HTTP calls create endpoint nodes with action intermediaries
|
|
51
67
|
const nextCallIndex = (callIndexByRoute.get(route) ?? 0) + 1;
|
|
52
68
|
callIndexByRoute.set(route, nextCallIndex);
|
|
53
69
|
const actionContext = inferActionContext(call.node, sourceFile, nextCallIndex);
|
|
54
70
|
const actionId = allocateActionId(route, actionContext.id, actionIdCountByRoute);
|
|
55
|
-
const pageNode = ensureNode(nodes, nodeIds, buildPageNode(route, filePath));
|
|
56
71
|
const actionNode = ensureNode(nodes, nodeIds, buildActionNode(route, actionId, filePath, actionContext.meta));
|
|
57
72
|
const endpointNode = ensureNode(nodes, nodeIds, buildEndpointNode(call.endpoint, filePath));
|
|
58
73
|
const pageActionKey = buildEdgeKey(pageNode.id, actionNode.id, "page-action");
|
|
@@ -177,7 +192,7 @@ function collectHttpCalls(sourceFile, httpClientIdentifiers, httpClientMethods,
|
|
|
177
192
|
if (sdkCall) {
|
|
178
193
|
calls.push({
|
|
179
194
|
endpoint: sdkCall.endpoint,
|
|
180
|
-
|
|
195
|
+
sdkClient: sdkCall.sdkClient,
|
|
181
196
|
node,
|
|
182
197
|
});
|
|
183
198
|
}
|
|
@@ -233,8 +248,7 @@ function parseSdkCall(node, sdkClientIdentifiers) {
|
|
|
233
248
|
if (segments.length < 2) {
|
|
234
249
|
return null;
|
|
235
250
|
}
|
|
236
|
-
|
|
237
|
-
return { endpoint };
|
|
251
|
+
return { endpoint: current.text, sdkClient: current.text };
|
|
238
252
|
}
|
|
239
253
|
function getEndpointArgument(expression, constMap) {
|
|
240
254
|
if (!expression) {
|
package/dist/model.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export type NodeType = "page" | "endpoint" | "db" | "handler" | "action";
|
|
1
|
+
export type NodeType = "page" | "endpoint" | "db" | "handler" | "action" | "service";
|
|
2
2
|
export type Node = {
|
|
3
3
|
id: string;
|
|
4
4
|
type: NodeType;
|
|
5
5
|
label: string;
|
|
6
6
|
meta?: Record<string, any>;
|
|
7
7
|
};
|
|
8
|
-
export type EdgeKind = "page-endpoint" | "endpoint-db" | "endpoint-handler" | "page-action" | "action-endpoint" | "db-relation";
|
|
8
|
+
export type EdgeKind = "page-endpoint" | "endpoint-db" | "endpoint-handler" | "page-action" | "action-endpoint" | "db-relation" | "page-service";
|
|
9
9
|
export type Edge = {
|
|
10
10
|
from: string;
|
|
11
11
|
to: string;
|
package/dist/utils.d.ts
CHANGED
|
@@ -71,3 +71,12 @@ export declare function buildDbNode(modelName: string, filePath: string): {
|
|
|
71
71
|
model: string;
|
|
72
72
|
};
|
|
73
73
|
};
|
|
74
|
+
export declare function buildServiceNode(serviceName: string, filePath: string): {
|
|
75
|
+
id: string;
|
|
76
|
+
type: "service";
|
|
77
|
+
label: string;
|
|
78
|
+
meta: {
|
|
79
|
+
filePath: string;
|
|
80
|
+
service: string;
|
|
81
|
+
};
|
|
82
|
+
};
|
package/dist/utils.js
CHANGED
|
@@ -292,3 +292,14 @@ export function buildDbNode(modelName, filePath) {
|
|
|
292
292
|
},
|
|
293
293
|
};
|
|
294
294
|
}
|
|
295
|
+
export function buildServiceNode(serviceName, filePath) {
|
|
296
|
+
return {
|
|
297
|
+
id: `service:${serviceName}`,
|
|
298
|
+
type: "service",
|
|
299
|
+
label: serviceName,
|
|
300
|
+
meta: {
|
|
301
|
+
filePath,
|
|
302
|
+
service: serviceName,
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
}
|
package/package.json
CHANGED
package/viewer/src/App.tsx
CHANGED
package/viewer/src/Filters.tsx
CHANGED
package/viewer/src/GraphView.tsx
CHANGED
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
MiniMap,
|
|
8
8
|
Position,
|
|
9
9
|
ReactFlow,
|
|
10
|
-
useReactFlow,
|
|
11
10
|
type Edge as FlowEdge,
|
|
12
11
|
type Node as FlowNode,
|
|
13
12
|
type NodeMouseHandler,
|
|
@@ -31,13 +30,7 @@ const NODE_COLOR: Record<NodeType, string> = {
|
|
|
31
30
|
endpoint: "#059669",
|
|
32
31
|
db: "#dc2626",
|
|
33
32
|
handler: "#14b8a6",
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const NODE_BORDER: Record<NodeType, string> = {
|
|
37
|
-
page: "#2563eb",
|
|
38
|
-
endpoint: "#047857",
|
|
39
|
-
db: "#b91c1c",
|
|
40
|
-
handler: "#0d9488",
|
|
33
|
+
service: "#7c3aed",
|
|
41
34
|
};
|
|
42
35
|
|
|
43
36
|
const EDGE_COLOR: Record<EdgeKind, string> = {
|
|
@@ -47,19 +40,18 @@ const EDGE_COLOR: Record<EdgeKind, string> = {
|
|
|
47
40
|
"page-action": "#8b5cf6",
|
|
48
41
|
"action-endpoint": "#a855f7",
|
|
49
42
|
"db-relation": "#94a3b8",
|
|
43
|
+
"page-service": "#a78bfa",
|
|
50
44
|
};
|
|
51
45
|
|
|
52
46
|
const DIFF_BORDER_COLOR: Record<DiffStatus, string> = {
|
|
53
47
|
added: "#22c55e",
|
|
54
48
|
removed: "#ef4444",
|
|
55
|
-
modified: "#f59e0b",
|
|
56
49
|
unchanged: "rgba(15, 23, 42, 0.12)",
|
|
57
50
|
};
|
|
58
51
|
|
|
59
52
|
const DIFF_EDGE_COLOR: Record<DiffStatus, string> = {
|
|
60
53
|
added: "#22c55e",
|
|
61
54
|
removed: "#ef4444",
|
|
62
|
-
modified: "#f59e0b",
|
|
63
55
|
unchanged: "#000000",
|
|
64
56
|
};
|
|
65
57
|
|
|
@@ -337,7 +329,7 @@ export function GraphView(props: GraphViewProps) {
|
|
|
337
329
|
|
|
338
330
|
// Compute layout without hover state — this is the expensive part
|
|
339
331
|
const { flowNodes: baseFlowNodes, flowEdges: baseFlowEdges } = useMemo(() => {
|
|
340
|
-
const typeOrder: NodeType[] = ["page", "endpoint", "handler", "db"];
|
|
332
|
+
const typeOrder: NodeType[] = ["page", "endpoint", "handler", "db", "service"];
|
|
341
333
|
const visibleNodes = graph.nodes.filter((node) => visibleNodeTypes.has(node.type));
|
|
342
334
|
const visibleNodeIds = new Set(visibleNodes.map((node) => node.id));
|
|
343
335
|
const nodesByType = new Map<NodeType, typeof visibleNodes>(
|
|
@@ -8,9 +8,8 @@ const TYPE_BADGE_COLORS: Record<NodeType, string> = {
|
|
|
8
8
|
page: "bg-blue-100 text-blue-700",
|
|
9
9
|
endpoint: "bg-emerald-100 text-emerald-700",
|
|
10
10
|
handler: "bg-teal-100 text-teal-700",
|
|
11
|
-
action: "bg-amber-100 text-amber-700",
|
|
12
11
|
db: "bg-red-100 text-red-700",
|
|
13
|
-
|
|
12
|
+
service: "bg-violet-100 text-violet-700",
|
|
14
13
|
};
|
|
15
14
|
|
|
16
15
|
export function NodeDetails({ node }: NodeDetailsProps) {
|
|
@@ -46,11 +45,11 @@ export function NodeDetails({ node }: NodeDetailsProps) {
|
|
|
46
45
|
{node.id}
|
|
47
46
|
</div>
|
|
48
47
|
|
|
49
|
-
{(node.meta?.descriptionLong
|
|
48
|
+
{(node.meta?.descriptionLong ?? node.meta?.description) ? (
|
|
50
49
|
<p className="text-xs text-slate-600 leading-relaxed">
|
|
51
50
|
{String(node.meta.descriptionLong ?? node.meta.description)}
|
|
52
51
|
</p>
|
|
53
|
-
)}
|
|
52
|
+
) : null}
|
|
54
53
|
|
|
55
54
|
{filePath !== undefined && filePath !== null && (
|
|
56
55
|
<div className="text-[11px] text-slate-500">
|
|
@@ -59,7 +58,7 @@ export function NodeDetails({ node }: NodeDetailsProps) {
|
|
|
59
58
|
</div>
|
|
60
59
|
)}
|
|
61
60
|
|
|
62
|
-
{node.meta?.screenshot
|
|
61
|
+
{node.meta?.screenshot ? (
|
|
63
62
|
<div className="mt-2">
|
|
64
63
|
<img
|
|
65
64
|
src={String(node.meta.screenshot)}
|
|
@@ -67,7 +66,7 @@ export function NodeDetails({ node }: NodeDetailsProps) {
|
|
|
67
66
|
className="w-full rounded-md border border-slate-200"
|
|
68
67
|
/>
|
|
69
68
|
</div>
|
|
70
|
-
)}
|
|
69
|
+
) : null}
|
|
71
70
|
|
|
72
71
|
{node.meta && (
|
|
73
72
|
<pre className="mt-2 p-2.5 rounded-md bg-slate-50 border border-slate-100 text-[11px] font-mono text-slate-600 max-h-40 overflow-auto whitespace-pre-wrap break-all">
|
package/viewer/src/types.ts
CHANGED
|
@@ -2,7 +2,8 @@ export type NodeType =
|
|
|
2
2
|
| "page"
|
|
3
3
|
| "endpoint"
|
|
4
4
|
| "db"
|
|
5
|
-
| "handler"
|
|
5
|
+
| "handler"
|
|
6
|
+
| "service";
|
|
6
7
|
|
|
7
8
|
export type Node = {
|
|
8
9
|
id: string;
|
|
@@ -17,7 +18,8 @@ export type EdgeKind =
|
|
|
17
18
|
| "endpoint-handler"
|
|
18
19
|
| "page-action"
|
|
19
20
|
| "action-endpoint"
|
|
20
|
-
| "db-relation"
|
|
21
|
+
| "db-relation"
|
|
22
|
+
| "page-service";
|
|
21
23
|
|
|
22
24
|
export type Edge = {
|
|
23
25
|
from: string;
|