@mka-rainmaker/ama 0.1.0 → 0.1.2
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/README.md +19 -1
- package/dist/analyzers/baseline/analyzer.d.ts +10 -0
- package/dist/analyzers/baseline/analyzer.d.ts.map +1 -1
- package/dist/analyzers/baseline/analyzer.js +5 -0
- package/dist/analyzers/baseline/analyzer.js.map +1 -1
- package/dist/analyzers/baseline/python.d.ts.map +1 -1
- package/dist/analyzers/baseline/python.js +99 -0
- package/dist/analyzers/baseline/python.js.map +1 -1
- package/dist/analyzers/prisma/analyzer.d.ts +19 -0
- package/dist/analyzers/prisma/analyzer.d.ts.map +1 -0
- package/dist/analyzers/prisma/analyzer.js +141 -0
- package/dist/analyzers/prisma/analyzer.js.map +1 -0
- package/dist/analyzers/typescript/analyzer.d.ts.map +1 -1
- package/dist/analyzers/typescript/analyzer.js +41 -5
- package/dist/analyzers/typescript/analyzer.js.map +1 -1
- package/dist/cli/agents.d.ts +28 -0
- package/dist/cli/agents.d.ts.map +1 -0
- package/dist/cli/agents.js +47 -0
- package/dist/cli/agents.js.map +1 -0
- package/dist/cli/commands/install.d.ts +20 -0
- package/dist/cli/commands/install.d.ts.map +1 -0
- package/dist/cli/commands/install.js +94 -0
- package/dist/cli/commands/install.js.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +3 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/graph/index.d.ts +1 -0
- package/dist/graph/index.d.ts.map +1 -1
- package/dist/graph/index.js +1 -0
- package/dist/graph/index.js.map +1 -1
- package/dist/graph/prisma-link.d.ts +15 -0
- package/dist/graph/prisma-link.d.ts.map +1 -0
- package/dist/graph/prisma-link.js +33 -0
- package/dist/graph/prisma-link.js.map +1 -0
- package/dist/graph/types.d.ts +6 -1
- package/dist/graph/types.d.ts.map +1 -1
- package/dist/indexer/indexer.d.ts.map +1 -1
- package/dist/indexer/indexer.js +17 -1
- package/dist/indexer/indexer.js.map +1 -1
- package/dist/mcp/server.d.ts +7 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +59 -28
- package/dist/mcp/server.js.map +1 -1
- package/dist/query/service.js +1 -1
- package/dist/query/service.js.map +1 -1
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -34,7 +34,15 @@ npm install -g @mka-rainmaker/ama
|
|
|
34
34
|
|
|
35
35
|
### Configure your coding agent
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
**Fastest — let Ama wire itself in:**
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
ama install # detects Claude Code / Cursor / Windsurf and writes their MCP config
|
|
41
|
+
ama install --dry-run # preview what it would change, writing nothing
|
|
42
|
+
ama uninstall # remove it again
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Or configure manually — every MCP client spawns the same stdio command (`ama mcp`), only the config location differs.
|
|
38
46
|
|
|
39
47
|
**Claude Code** — add it with one command:
|
|
40
48
|
|
|
@@ -66,6 +74,16 @@ claude mcp add ama -- ama mcp
|
|
|
66
74
|
{ "mcpServers": { "ama": { "command": "npx", "args": ["-y", "@mka-rainmaker/ama", "mcp"] } } }
|
|
67
75
|
```
|
|
68
76
|
|
|
77
|
+
### Fewer tools, lower token cost
|
|
78
|
+
|
|
79
|
+
Ama exposes 27 tools by default. To trade that for a small high-signal set, set
|
|
80
|
+
`AMA_MCP_TOOLS` on the server — `minimal` (just `explore` + indexing), or a comma-separated
|
|
81
|
+
list of tool names (the indexing tools are always included):
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{ "mcpServers": { "ama": { "command": "ama", "args": ["mcp"], "env": { "AMA_MCP_TOOLS": "minimal" } } } }
|
|
85
|
+
```
|
|
86
|
+
|
|
69
87
|
### Quick start
|
|
70
88
|
|
|
71
89
|
Once connected, point Ama at a repo and start asking graph questions:
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type Parser from "web-tree-sitter";
|
|
2
|
+
import { type GraphEdge, type GraphNode } from "../../graph/index.js";
|
|
2
3
|
import type { AnalysisResult, Analyzer } from "../types.js";
|
|
3
4
|
import { type SymbolRule } from "./walk.js";
|
|
4
5
|
export type { SymbolRule };
|
|
@@ -25,6 +26,15 @@ export interface LanguageSpec {
|
|
|
25
26
|
* module-qualified path; path-based languages can ignore it. (ama-8nr, ama-9yu)
|
|
26
27
|
*/
|
|
27
28
|
readonly resolveImports?: (node: Parser.SyntaxNode, importerRel: string, root: string) => string[][] | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* Optional route detector: walk the CST for framework route registrations and return Route
|
|
31
|
+
* nodes plus their handler `References` edges. Baseline tier — a heuristic, syntactic match
|
|
32
|
+
* on decorator/call patterns (e.g. Python's `@app.get("/x")`). (ama-bvg)
|
|
33
|
+
*/
|
|
34
|
+
readonly collectRoutes?: (root: Parser.SyntaxNode, rel: string) => {
|
|
35
|
+
nodes: GraphNode[];
|
|
36
|
+
edges: GraphEdge[];
|
|
37
|
+
};
|
|
28
38
|
}
|
|
29
39
|
/**
|
|
30
40
|
* A language-agnostic, syntactic (tier `baseline`) analyzer driven by a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../../../src/analyzers/baseline/analyzer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../../../src/analyzers/baseline/analyzer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAU,MAAM,sBAAsB,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5D,OAAO,EAAE,KAAK,UAAU,EAAe,MAAM,WAAW,CAAC;AAEzD,YAAY,EAAE,UAAU,EAAE,CAAC;AAE3B;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,iEAAiE;IACjE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,mDAAmD;IACnD,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IACvD;;;;;;;;OAQG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,CACxB,IAAI,EAAE,MAAM,CAAC,UAAU,EACvB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,KACT,MAAM,EAAE,EAAE,GAAG,SAAS,CAAC;IAE5B;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CACvB,IAAI,EAAE,MAAM,CAAC,UAAU,EACvB,GAAG,EAAE,MAAM,KACR;QAAE,KAAK,EAAE,SAAS,EAAE,CAAC;QAAC,KAAK,EAAE,SAAS,EAAE,CAAA;KAAE,CAAC;CACjD;AAED;;;;;;GAMG;AACH,qBAAa,gBAAiB,YAAW,QAAQ;IAKnC,OAAO,CAAC,QAAQ,CAAC,IAAI;IAJjC,QAAQ,CAAC,IAAI,cAAc;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;gBAEV,IAAI,EAAE,YAAY;IAKzC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC;IAmDrE;oFACgF;IAChF,OAAO,CAAC,cAAc;CAkBvB"}
|
|
@@ -51,6 +51,11 @@ export class BaselineAnalyzer {
|
|
|
51
51
|
walkSymbols(tree.rootNode, this.spec.symbols, rel, id, "", fileNodes, fileEdges);
|
|
52
52
|
if (this.spec.resolveImports)
|
|
53
53
|
this.collectImports(tree.rootNode, rel, root, id, fileEdges);
|
|
54
|
+
if (this.spec.collectRoutes) {
|
|
55
|
+
const routes = this.spec.collectRoutes(tree.rootNode, rel);
|
|
56
|
+
fileNodes.push(...routes.nodes);
|
|
57
|
+
fileEdges.push(...routes.edges);
|
|
58
|
+
}
|
|
54
59
|
nodes.push(...fileNodes);
|
|
55
60
|
edges.push(...fileEdges);
|
|
56
61
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../../../src/analyzers/baseline/analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAkC,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAE9E,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EAAmB,WAAW,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../../../src/analyzers/baseline/analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"python.d.ts","sourceRoot":"","sources":["../../../src/analyzers/baseline/python.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"python.d.ts","sourceRoot":"","sources":["../../../src/analyzers/baseline/python.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAsIlD;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,EAAE,YAUxB,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
|
+
import { symbolId } from "../../graph/index.js";
|
|
2
3
|
/**
|
|
3
4
|
* Resolve a Python relative import (`from .x import y`, `from . import m`,
|
|
4
5
|
* `from ..pkg import z`) to candidate repo-relative module files. The leading
|
|
@@ -43,6 +44,103 @@ function pythonImports(node, importerRel) {
|
|
|
43
44
|
}
|
|
44
45
|
return groups;
|
|
45
46
|
}
|
|
47
|
+
/** Flask/FastAPI HTTP-verb decorator attributes (`@app.get(...)`); `route` is handled
|
|
48
|
+
* separately as Flask's any-/default-GET form. (ama-bvg) */
|
|
49
|
+
const ROUTE_METHOD_ATTRS = new Set(["get", "post", "put", "delete", "patch", "options", "head"]);
|
|
50
|
+
/** Normalize a framework route path to the `:param` form — Flask `<id>`/`<int:id>` and
|
|
51
|
+
* FastAPI `{id}` both become `:id` — and ensure a leading slash. (ama-bvg) */
|
|
52
|
+
function normalizeRoutePath(p) {
|
|
53
|
+
const s = p.replace(/<(?:[^:>]+:)?([^>]+)>/g, ":$1").replace(/\{([^}]+)\}/g, ":$1");
|
|
54
|
+
return s.startsWith("/") ? s : `/${s}`;
|
|
55
|
+
}
|
|
56
|
+
/** The first string-literal argument of a call's `arguments`, unquoted. */
|
|
57
|
+
function firstStringArg(args) {
|
|
58
|
+
if (!args)
|
|
59
|
+
return undefined;
|
|
60
|
+
for (const a of args.namedChildren) {
|
|
61
|
+
if (a.type === "string")
|
|
62
|
+
return a.namedChildren.find((c) => c.type === "string_content")?.text;
|
|
63
|
+
}
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
/** Method + normalized path for a Flask/FastAPI route decorator, else undefined. `@x.route(p)`
|
|
67
|
+
* → GET (Flask default; the `methods=` kwarg is a later refinement); `@x.get(p)` etc. take the
|
|
68
|
+
* verb from the attribute name. (ama-bvg) */
|
|
69
|
+
function routeFromDecorator(dec) {
|
|
70
|
+
const call = dec.namedChildren.find((c) => c.type === "call");
|
|
71
|
+
const fn = call?.childForFieldName("function");
|
|
72
|
+
if (!call || fn?.type !== "attribute")
|
|
73
|
+
return undefined;
|
|
74
|
+
const attr = fn.childForFieldName("attribute")?.text?.toLowerCase();
|
|
75
|
+
if (!attr || (attr !== "route" && !ROUTE_METHOD_ATTRS.has(attr)))
|
|
76
|
+
return undefined;
|
|
77
|
+
const raw = firstStringArg(call.childForFieldName("arguments"));
|
|
78
|
+
if (raw === undefined)
|
|
79
|
+
return undefined;
|
|
80
|
+
return { method: attr === "route" ? "GET" : attr.toUpperCase(), path: normalizeRoutePath(raw) };
|
|
81
|
+
}
|
|
82
|
+
/** The handler's qualified name, matching walkSymbols' nesting: prepend each enclosing
|
|
83
|
+
* class/function name (a class method is `Class.method`; a top-level def is just its name). */
|
|
84
|
+
function qualifiedNameOf(fn) {
|
|
85
|
+
const own = fn.childForFieldName("name")?.text;
|
|
86
|
+
if (!own)
|
|
87
|
+
return undefined;
|
|
88
|
+
const parts = [];
|
|
89
|
+
for (let p = fn.parent; p; p = p.parent) {
|
|
90
|
+
if (p.type === "class_definition" || p.type === "function_definition") {
|
|
91
|
+
const n = p.childForFieldName("name")?.text;
|
|
92
|
+
if (n)
|
|
93
|
+
parts.unshift(n);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
parts.push(own);
|
|
97
|
+
return parts.join(".");
|
|
98
|
+
}
|
|
99
|
+
function* eachDecorated(node) {
|
|
100
|
+
if (node.type === "decorated_definition")
|
|
101
|
+
yield node;
|
|
102
|
+
for (const c of node.namedChildren)
|
|
103
|
+
yield* eachDecorated(c);
|
|
104
|
+
}
|
|
105
|
+
/** Detect Flask/FastAPI routes: a decorated function whose decorator is `@<obj>.route(path)`
|
|
106
|
+
* or `@<obj>.<verb>(path)` becomes a `METHOD /path` Route referencing the function. (ama-bvg) */
|
|
107
|
+
function pythonRoutes(root, rel) {
|
|
108
|
+
const nodes = [];
|
|
109
|
+
const edges = [];
|
|
110
|
+
for (const dd of eachDecorated(root)) {
|
|
111
|
+
const fn = dd.childForFieldName("definition");
|
|
112
|
+
if (fn?.type !== "function_definition")
|
|
113
|
+
continue;
|
|
114
|
+
const handler = qualifiedNameOf(fn);
|
|
115
|
+
if (!handler)
|
|
116
|
+
continue;
|
|
117
|
+
for (const dec of dd.namedChildren) {
|
|
118
|
+
if (dec.type !== "decorator")
|
|
119
|
+
continue;
|
|
120
|
+
const route = routeFromDecorator(dec);
|
|
121
|
+
if (!route)
|
|
122
|
+
continue;
|
|
123
|
+
const name = `${route.method} ${route.path}`;
|
|
124
|
+
const routeId = symbolId({ file: rel, qualifiedName: name });
|
|
125
|
+
nodes.push({
|
|
126
|
+
id: routeId,
|
|
127
|
+
kind: "Route",
|
|
128
|
+
name,
|
|
129
|
+
file: rel,
|
|
130
|
+
qualifiedName: name,
|
|
131
|
+
tier: "baseline",
|
|
132
|
+
range: { startLine: fn.startPosition.row + 1, endLine: fn.endPosition.row + 1 },
|
|
133
|
+
});
|
|
134
|
+
edges.push({
|
|
135
|
+
from: routeId,
|
|
136
|
+
to: symbolId({ file: rel, qualifiedName: handler }),
|
|
137
|
+
kind: "References",
|
|
138
|
+
provenance: "heuristic",
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return { nodes, edges };
|
|
143
|
+
}
|
|
46
144
|
/**
|
|
47
145
|
* Baseline (syntactic) spec for Python. Functions and classes are the symbols
|
|
48
146
|
* worth a node; methods are `function_definition` too (Python doesn't
|
|
@@ -59,5 +157,6 @@ export const pythonSpec = {
|
|
|
59
157
|
class_definition: { kind: "Class" },
|
|
60
158
|
},
|
|
61
159
|
resolveImports: pythonImports,
|
|
160
|
+
collectRoutes: pythonRoutes,
|
|
62
161
|
};
|
|
63
162
|
//# sourceMappingURL=python.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"python.js","sourceRoot":"","sources":["../../../src/analyzers/baseline/python.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"python.js","sourceRoot":"","sources":["../../../src/analyzers/baseline/python.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAkC,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGhF;;;;;;GAMG;AACH,SAAS,aAAa,CAAC,IAAuB,EAAE,WAAmB;IACjE,IAAI,IAAI,CAAC,IAAI,KAAK,uBAAuB;QAAE,OAAO,SAAS,CAAC;IAC5D,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,iBAAiB,CAAC,CAAC;IAC9E,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,CAAC,CAAC,oDAAoD;IAC9E,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,eAAe,CAAC,CAAC;IAC9E,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,gFAAgF;IAChF,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE;QAAE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,IAAI,IAAI,KAAK,GAAG;QAAE,IAAI,GAAG,EAAE,CAAC;IAC5B,MAAM,UAAU,GAAG,CAAC,QAAkB,EAAY,EAAE;QAClD,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxD,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;IACzC,CAAC,CAAC;IACF,MAAM,MAAM,GAAG,CAAC,MAAyB,EAAY,EAAE,CACrD,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACjF,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,aAAa,CAAC,CAAC;IAC5E,IAAI,MAAM;QAAE,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,qCAAqC;IACtF,gFAAgF;IAChF,MAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACvC,IAAI,KAAK,KAAK,QAAQ;YAAE,SAAS;QACjC,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa;YAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;aACpE,IAAI,KAAK,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;YACzC,MAAM,EAAE,GAAG,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,aAAa,CAAC,CAAC;YACrE,IAAI,EAAE;gBAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;6DAC6D;AAC7D,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;AAEjG;+EAC+E;AAC/E,SAAS,kBAAkB,CAAC,CAAS;IACnC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACpF,OAAO,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;AACzC,CAAC;AAED,2EAA2E;AAC3E,SAAS,cAAc,CAAC,IAA8B;IACpD,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACnC,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,gBAAgB,CAAC,EAAE,IAAI,CAAC;IACjG,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;8CAE8C;AAC9C,SAAS,kBAAkB,CAAC,GAAsB;IAChD,MAAM,IAAI,GAAG,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;IAC9D,MAAM,EAAE,GAAG,IAAI,EAAE,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAC/C,IAAI,CAAC,IAAI,IAAI,EAAE,EAAE,IAAI,KAAK,WAAW;QAAE,OAAO,SAAS,CAAC;IACxD,MAAM,IAAI,GAAG,EAAE,CAAC,iBAAiB,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IACpE,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACnF,MAAM,GAAG,GAAG,cAAc,CAAC,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC,CAAC;IAChE,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACxC,OAAO,EAAE,MAAM,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;AAClG,CAAC;AAED;gGACgG;AAChG,SAAS,eAAe,CAAC,EAAqB;IAC5C,MAAM,GAAG,GAAG,EAAE,CAAC,iBAAiB,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC;IAC/C,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC;QACxC,IAAI,CAAC,CAAC,IAAI,KAAK,kBAAkB,IAAI,CAAC,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;YACtE,MAAM,CAAC,GAAG,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC;YAC5C,IAAI,CAAC;gBAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChB,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED,QAAQ,CAAC,CAAC,aAAa,CAAC,IAAuB;IAC7C,IAAI,IAAI,CAAC,IAAI,KAAK,sBAAsB;QAAE,MAAM,IAAI,CAAC;IACrD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,aAAa;QAAE,KAAK,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AAC9D,CAAC;AAED;kGACkG;AAClG,SAAS,YAAY,CACnB,IAAuB,EACvB,GAAW;IAEX,MAAM,KAAK,GAAgB,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAgB,EAAE,CAAC;IAC9B,KAAK,MAAM,EAAE,IAAI,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;QACrC,MAAM,EAAE,GAAG,EAAE,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC;QAC9C,IAAI,EAAE,EAAE,IAAI,KAAK,qBAAqB;YAAE,SAAS;QACjD,MAAM,OAAO,GAAG,eAAe,CAAC,EAAE,CAAC,CAAC;QACpC,IAAI,CAAC,OAAO;YAAE,SAAS;QACvB,KAAK,MAAM,GAAG,IAAI,EAAE,CAAC,aAAa,EAAE,CAAC;YACnC,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW;gBAAE,SAAS;YACvC,MAAM,KAAK,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;YACtC,IAAI,CAAC,KAAK;gBAAE,SAAS;YACrB,MAAM,IAAI,GAAG,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;YAC7C,MAAM,OAAO,GAAG,QAAQ,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YAC7D,KAAK,CAAC,IAAI,CAAC;gBACT,EAAE,EAAE,OAAO;gBACX,IAAI,EAAE,OAAO;gBACb,IAAI;gBACJ,IAAI,EAAE,GAAG;gBACT,aAAa,EAAE,IAAI;gBACnB,IAAI,EAAE,UAAU;gBAChB,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,GAAG,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,GAAG,CAAC,EAAE;aAChF,CAAC,CAAC;YACH,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,OAAO;gBACb,EAAE,EAAE,QAAQ,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC;gBACnD,IAAI,EAAE,YAAY;gBAClB,UAAU,EAAE,WAAW;aACxB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC1B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,UAAU,GAAiB;IACtC,QAAQ,EAAE,QAAQ;IAClB,UAAU,EAAE,CAAC,KAAK,CAAC;IACnB,OAAO,EAAE,QAAQ;IACjB,OAAO,EAAE;QACP,mBAAmB,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE;QACzC,gBAAgB,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;KACpC;IACD,cAAc,EAAE,aAAa;IAC7B,aAAa,EAAE,YAAY;CAC5B,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type Tier } from "../../graph/index.js";
|
|
2
|
+
import type { AnalysisResult, Analyzer } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Deep-tier analyzer for Prisma schemas. Parses `schema.prisma` into a queryable graph:
|
|
5
|
+
* each `model`/`type` becomes a Class node and each `enum` an Enum node; fields are
|
|
6
|
+
* Property nodes qualified by their model; and a field typed by another model/enum/type
|
|
7
|
+
* emits a `UsesType` edge — the relation graph. `datasource`/`generator` blocks are
|
|
8
|
+
* ignored. The schema is a simple declarative grammar, so a line parser suffices (no
|
|
9
|
+
* tree-sitter wasm). Cross-code linkage (prisma client usage → model) is the deep TS
|
|
10
|
+
* analyzer's job. (ama-cdg)
|
|
11
|
+
*/
|
|
12
|
+
export declare class PrismaAnalyzer implements Analyzer {
|
|
13
|
+
readonly language = "prisma";
|
|
14
|
+
readonly tier: Tier;
|
|
15
|
+
readonly extensions: readonly string[];
|
|
16
|
+
analyze(root: string, files: string[]): AnalysisResult;
|
|
17
|
+
private analyzeFile;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=analyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../../../src/analyzers/prisma/analyzer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAkC,KAAK,IAAI,EAAoB,MAAM,sBAAsB,CAAC;AACnG,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAe5D;;;;;;;;GAQG;AACH,qBAAa,cAAe,YAAW,QAAQ;IAC7C,QAAQ,CAAC,QAAQ,YAAY;IAC7B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAU;IAC7B,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAe;IAErD,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,cAAc;IAiCtD,OAAO,CAAC,WAAW;CA2FpB"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { fileId, symbolId } from "../../graph/index.js";
|
|
4
|
+
/** A Prisma block opener: `model User {`, `enum Role {`, `datasource db {`, … */
|
|
5
|
+
const BLOCK_OPEN = /^(model|enum|type|datasource|generator)\s+(\w+)\b/;
|
|
6
|
+
/** A field line: `<name> <Type> …` — the type is the second token; `?`/`[]` modifiers
|
|
7
|
+
* follow it, so `\w+` captures the base type name. */
|
|
8
|
+
const FIELD = /^(\w+)\s+(\w+)/;
|
|
9
|
+
const braceDelta = (line) => (line.match(/\{/g)?.length ?? 0) - (line.match(/\}/g)?.length ?? 0);
|
|
10
|
+
/** Strip a `//` line comment (Prisma uses `//` and `///`). A `//` inside a default value
|
|
11
|
+
* is never read — only a field's first two tokens are — so this is safe here. */
|
|
12
|
+
const stripComment = (line) => line.replace(/\/\/.*$/, "");
|
|
13
|
+
/**
|
|
14
|
+
* Deep-tier analyzer for Prisma schemas. Parses `schema.prisma` into a queryable graph:
|
|
15
|
+
* each `model`/`type` becomes a Class node and each `enum` an Enum node; fields are
|
|
16
|
+
* Property nodes qualified by their model; and a field typed by another model/enum/type
|
|
17
|
+
* emits a `UsesType` edge — the relation graph. `datasource`/`generator` blocks are
|
|
18
|
+
* ignored. The schema is a simple declarative grammar, so a line parser suffices (no
|
|
19
|
+
* tree-sitter wasm). Cross-code linkage (prisma client usage → model) is the deep TS
|
|
20
|
+
* analyzer's job. (ama-cdg)
|
|
21
|
+
*/
|
|
22
|
+
export class PrismaAnalyzer {
|
|
23
|
+
language = "prisma";
|
|
24
|
+
tier = "deep";
|
|
25
|
+
extensions = [".prisma"];
|
|
26
|
+
analyze(root, files) {
|
|
27
|
+
// Pass 1 — every declared type name and the file it lives in, so a relation field can
|
|
28
|
+
// link across a multi-file schema (Prisma's `schema/` dir), not just within one file.
|
|
29
|
+
const typeFile = new Map();
|
|
30
|
+
const sources = new Map();
|
|
31
|
+
for (const rel of files) {
|
|
32
|
+
try {
|
|
33
|
+
const code = fs.readFileSync(path.join(root, rel), "utf8");
|
|
34
|
+
sources.set(rel, code);
|
|
35
|
+
for (const m of code.matchAll(/^\s*(?:model|enum|type)\s+(\w+)\s*\{/gm)) {
|
|
36
|
+
typeFile.set(m[1], rel);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// Unreadable file — skip; it simply contributes no nodes/links.
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const nodes = [];
|
|
44
|
+
const edges = [];
|
|
45
|
+
for (const [rel, code] of sources) {
|
|
46
|
+
try {
|
|
47
|
+
this.analyzeFile(rel, code, typeFile, nodes, edges);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
console.error(`[ama] prisma analyzer failed on ${rel}; skipping it. ${err instanceof Error ? err.message : String(err)}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return { nodes, edges };
|
|
54
|
+
}
|
|
55
|
+
analyzeFile(rel, code, typeFile, nodes, edges) {
|
|
56
|
+
const lines = code.split("\n");
|
|
57
|
+
const fid = fileId(rel);
|
|
58
|
+
nodes.push({
|
|
59
|
+
id: fid,
|
|
60
|
+
kind: "File",
|
|
61
|
+
name: path.basename(rel),
|
|
62
|
+
file: rel,
|
|
63
|
+
qualifiedName: "",
|
|
64
|
+
tier: "deep",
|
|
65
|
+
range: { startLine: 1, endLine: lines.length },
|
|
66
|
+
});
|
|
67
|
+
let current = null;
|
|
68
|
+
let skipDepth = 0; // >0 while inside an ignored datasource/generator block
|
|
69
|
+
for (let i = 0; i < lines.length; i++) {
|
|
70
|
+
const ln = i + 1;
|
|
71
|
+
const line = stripComment(lines[i] ?? "").trim();
|
|
72
|
+
if (!line)
|
|
73
|
+
continue;
|
|
74
|
+
if (skipDepth > 0) {
|
|
75
|
+
skipDepth += braceDelta(line); // back to 0 at the block's closing `}`
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (current === null) {
|
|
79
|
+
const open = line.match(BLOCK_OPEN);
|
|
80
|
+
if (!open)
|
|
81
|
+
continue;
|
|
82
|
+
const kw = open[1];
|
|
83
|
+
const name = open[2];
|
|
84
|
+
if (kw === "datasource" || kw === "generator") {
|
|
85
|
+
skipDepth = braceDelta(line); // +1 on the opener line
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const node = {
|
|
89
|
+
id: symbolId({ file: rel, qualifiedName: name }),
|
|
90
|
+
kind: kw === "enum" ? "Enum" : "Class",
|
|
91
|
+
name,
|
|
92
|
+
file: rel,
|
|
93
|
+
qualifiedName: name,
|
|
94
|
+
tier: "deep",
|
|
95
|
+
range: { startLine: ln, endLine: ln },
|
|
96
|
+
};
|
|
97
|
+
nodes.push(node);
|
|
98
|
+
edges.push({ from: fid, to: node.id, kind: "Defines" });
|
|
99
|
+
current = { name, node, emitFields: kw !== "enum" };
|
|
100
|
+
if (line.includes("}"))
|
|
101
|
+
current = null; // single-line block (rare)
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (line.includes("}")) {
|
|
105
|
+
if (current.node.range)
|
|
106
|
+
current.node.range.endLine = ln;
|
|
107
|
+
current = null;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (!current.emitFields || line.startsWith("@@"))
|
|
111
|
+
continue;
|
|
112
|
+
const field = line.match(FIELD);
|
|
113
|
+
if (!field)
|
|
114
|
+
continue;
|
|
115
|
+
const fieldName = field[1];
|
|
116
|
+
const typeName = field[2];
|
|
117
|
+
const fieldQn = `${current.name}.${fieldName}`;
|
|
118
|
+
const fieldNodeId = symbolId({ file: rel, qualifiedName: fieldQn });
|
|
119
|
+
nodes.push({
|
|
120
|
+
id: fieldNodeId,
|
|
121
|
+
kind: "Property",
|
|
122
|
+
name: fieldName,
|
|
123
|
+
file: rel,
|
|
124
|
+
qualifiedName: fieldQn,
|
|
125
|
+
tier: "deep",
|
|
126
|
+
range: { startLine: ln, endLine: ln },
|
|
127
|
+
});
|
|
128
|
+
edges.push({ from: current.node.id, to: fieldNodeId, kind: "Defines" });
|
|
129
|
+
// A field typed by another declared model/enum/type is a relation → UsesType.
|
|
130
|
+
const targetFile = typeFile.get(typeName);
|
|
131
|
+
if (targetFile) {
|
|
132
|
+
edges.push({
|
|
133
|
+
from: current.node.id,
|
|
134
|
+
to: symbolId({ file: targetFile, qualifiedName: typeName }),
|
|
135
|
+
kind: "UsesType",
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../../../src/analyzers/prisma/analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../../../src/analyzers/typescript/analyzer.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAmB,MAAM,aAAa,CAAC;AAkB7E;;;;;;;;;;;;;;GAcG;AACH,qBAAa,kBAAmB,YAAW,QAAQ;IACjD,QAAQ,CAAC,QAAQ,gBAAgB;IACjC,QAAQ,CAAC,IAAI,EAAG,MAAM,CAAU;IAChC,QAAQ,CAAC,UAAU,2CAA4C;IAE/D,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,cAAc;IA+FtD,OAAO,CAAC,QAAQ;IAyBhB,OAAO,CAAC,KAAK;IAqHb;;;oBAGgB;IAChB,OAAO,CAAC,YAAY;IAoGpB;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,oBAAoB;
|
|
1
|
+
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../../../src/analyzers/typescript/analyzer.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAmB,MAAM,aAAa,CAAC;AAkB7E;;;;;;;;;;;;;;GAcG;AACH,qBAAa,kBAAmB,YAAW,QAAQ;IACjD,QAAQ,CAAC,QAAQ,gBAAgB;IACjC,QAAQ,CAAC,IAAI,EAAG,MAAM,CAAU;IAChC,QAAQ,CAAC,UAAU,2CAA4C;IAE/D,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,cAAc;IA+FtD,OAAO,CAAC,QAAQ;IAyBhB,OAAO,CAAC,KAAK;IAqHb;;;oBAGgB;IAChB,OAAO,CAAC,YAAY;IAoGpB;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,oBAAoB;IAwE5B,oFAAoF;IACpF,OAAO,CAAC,eAAe;IAqBvB;;;;;OAKG;IACH,OAAO,CAAC,cAAc;IAkDtB;;;;;;;;OAQG;IACH,OAAO,CAAC,iBAAiB;IAkEzB;;;;;;;;OAQG;IACH,OAAO,CAAC,aAAa;IAoOrB;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IAsCzB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,OAAO,CAAC,uBAAuB;IA6D/B;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IA8FzB;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;IA0ErB;;;;OAIG;IACH,OAAO,CAAC,aAAa;CA0BtB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import ts from "typescript";
|
|
3
|
-
import { deriveDispatchEdges, fileId, symbolId } from "../../graph/index.js";
|
|
3
|
+
import { PRISMA_REF_PREFIX, deriveDispatchEdges, fileId, symbolId } from "../../graph/index.js";
|
|
4
4
|
/**
|
|
5
5
|
* Log a per-file analyzer failure to stderr and carry on. The deep TypeScript
|
|
6
6
|
* analyzer shares one ts.Program across the whole batch for cross-file
|
|
@@ -348,7 +348,19 @@ export class TypeScriptAnalyzer {
|
|
|
348
348
|
// resolveValueRef → nodeIdForDecl already filters targets to in-project
|
|
349
349
|
// top-level + class/interface members, so external reads (`console.log`)
|
|
350
350
|
// and locals add no edge — only the `X.m()` call form is excluded here.
|
|
351
|
-
if (
|
|
351
|
+
if (isPrismaClientExpr(parent.expression)) {
|
|
352
|
+
// `prisma.<model>` (also `db.`/`tx.`/`this.prisma.`) — a Prisma client model
|
|
353
|
+
// access. Emit a raw candidate the indexer resolves to the schema model node;
|
|
354
|
+
// the name-based check is intentionally loose because a candidate matching no
|
|
355
|
+
// model is dropped at resolution (derivePrismaReferences). (ama-kvv)
|
|
356
|
+
edges.push({
|
|
357
|
+
from: enclosingId,
|
|
358
|
+
to: PRISMA_REF_PREFIX + child.text.toLowerCase(),
|
|
359
|
+
kind: "References",
|
|
360
|
+
provenance: "prisma-ref",
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
else if (!(ts.isCallExpression(parent.parent) && parent.parent.expression === parent)) {
|
|
352
364
|
const to = resolveValueRef(child, checker, declToId, root);
|
|
353
365
|
if (to && to !== enclosingId) {
|
|
354
366
|
edges.push({ from: enclosingId, to, kind: "References" });
|
|
@@ -1269,13 +1281,28 @@ function fileRoutePath(rel) {
|
|
|
1269
1281
|
return `/${segs.join("/")}`;
|
|
1270
1282
|
}
|
|
1271
1283
|
/** Module extensions a filename-routed endpoint can use. (ama-w7g) */
|
|
1284
|
+
/** Conventional names for a Prisma client instance, so `prisma.<model>` / `db.<model>` /
|
|
1285
|
+
* `tx.<model>` / `this.prisma.<model>` reads as a schema model access. (ama-kvv) */
|
|
1286
|
+
const PRISMA_CLIENT_NAMES = new Set(["prisma", "db", "tx", "trx", "prismaclient", "dbclient"]);
|
|
1287
|
+
/** Whether `expr` is a Prisma client — a bare `prisma`/`db`/… identifier or a
|
|
1288
|
+
* `this.prisma`-style member — so a `.member` off it names a model. (ama-kvv) */
|
|
1289
|
+
function isPrismaClientExpr(expr) {
|
|
1290
|
+
if (ts.isIdentifier(expr))
|
|
1291
|
+
return PRISMA_CLIENT_NAMES.has(expr.text.toLowerCase());
|
|
1292
|
+
if (ts.isPropertyAccessExpression(expr)) {
|
|
1293
|
+
return PRISMA_CLIENT_NAMES.has(expr.name.text.toLowerCase());
|
|
1294
|
+
}
|
|
1295
|
+
return false;
|
|
1296
|
+
}
|
|
1272
1297
|
const FILE_ROUTE_EXTS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs"]);
|
|
1273
1298
|
/** The URL path for a *filename*-routed module (the route includes the filename),
|
|
1274
1299
|
* plus whether a default export should count as a handler. Next.js Pages Router
|
|
1275
1300
|
* & Astro live under `pages/`/`src/pages/`; Nuxt under `server/api/` (keeps the
|
|
1276
1301
|
* `/api` prefix) or `server/routes/` (stripped). `index` maps to its directory.
|
|
1277
1302
|
* `allowDefault` is true only in an API context — a `pages/about.tsx` default
|
|
1278
|
-
* export is a page component, not a route.
|
|
1303
|
+
* export is a page component, not a route. Next.js App Router `app/**/page.tsx` maps to
|
|
1304
|
+
* its directory (the `page` filename drops, like `index`) and its default export is the
|
|
1305
|
+
* page handler. (ama-w7g, ama-vzq) */
|
|
1279
1306
|
function filenameRoutePath(rel) {
|
|
1280
1307
|
const parts = rel.split("/");
|
|
1281
1308
|
const file = parts[parts.length - 1] ?? "";
|
|
@@ -1285,11 +1312,20 @@ function filenameRoutePath(rel) {
|
|
|
1285
1312
|
const base = file.slice(0, dot);
|
|
1286
1313
|
if (base.startsWith("_"))
|
|
1287
1314
|
return undefined; // Next.js specials: _app, _document
|
|
1315
|
+
const appIdx = parts.lastIndexOf("app");
|
|
1288
1316
|
const pagesIdx = parts.lastIndexOf("pages");
|
|
1289
1317
|
const serverIdx = parts.lastIndexOf("server");
|
|
1290
1318
|
let rootIdx;
|
|
1291
1319
|
let allowDefault;
|
|
1292
|
-
|
|
1320
|
+
// Next.js App Router: app/**/page.tsx — the `page` filename is the route for its
|
|
1321
|
+
// directory (it drops like `index`), and its default export is the page handler. (ama-vzq)
|
|
1322
|
+
let dropFilename = false;
|
|
1323
|
+
if (appIdx >= 0 && base === "page") {
|
|
1324
|
+
rootIdx = appIdx;
|
|
1325
|
+
allowDefault = true;
|
|
1326
|
+
dropFilename = true;
|
|
1327
|
+
}
|
|
1328
|
+
else if (pagesIdx >= 0) {
|
|
1293
1329
|
rootIdx = pagesIdx;
|
|
1294
1330
|
allowDefault = parts[pagesIdx + 1] === "api"; // Next API routes live under pages/api
|
|
1295
1331
|
}
|
|
@@ -1305,7 +1341,7 @@ function filenameRoutePath(rel) {
|
|
|
1305
1341
|
return undefined;
|
|
1306
1342
|
}
|
|
1307
1343
|
const dirs = parts.slice(rootIdx + 1, parts.length - 1);
|
|
1308
|
-
const leaf = base === "index" ? [] : [base];
|
|
1344
|
+
const leaf = base === "index" || dropFilename ? [] : [base];
|
|
1309
1345
|
const segs = [...dirs, ...leaf].map(routeSegment).filter((s) => s !== undefined);
|
|
1310
1346
|
return { path: `/${segs.join("/")}`, allowDefault };
|
|
1311
1347
|
}
|