@mka-rainmaker/ama 0.1.2 → 0.2.0
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 +18 -2
- package/dist/analyzers/baseline/analyzer.d.ts +9 -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/go.d.ts.map +1 -1
- package/dist/analyzers/baseline/go.js +67 -0
- package/dist/analyzers/baseline/go.js.map +1 -1
- package/dist/analyzers/baseline/java.d.ts.map +1 -1
- package/dist/analyzers/baseline/java.js +84 -0
- package/dist/analyzers/baseline/java.js.map +1 -1
- package/dist/analyzers/baseline/php.d.ts.map +1 -1
- package/dist/analyzers/baseline/php.js +56 -0
- package/dist/analyzers/baseline/php.js.map +1 -1
- package/dist/analyzers/baseline/python.d.ts.map +1 -1
- package/dist/analyzers/baseline/python.js +160 -2
- package/dist/analyzers/baseline/python.js.map +1 -1
- package/dist/analyzers/baseline/rust.d.ts.map +1 -1
- package/dist/analyzers/baseline/rust.js +80 -0
- package/dist/analyzers/baseline/rust.js.map +1 -1
- package/dist/analyzers/sidecar/protocol.d.ts +22 -22
- package/dist/analyzers/typescript/analyzer.d.ts.map +1 -1
- package/dist/analyzers/typescript/analyzer.js +51 -1
- package/dist/analyzers/typescript/analyzer.js.map +1 -1
- package/dist/api.d.ts +34 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +38 -0
- package/dist/api.js.map +1 -0
- package/dist/cli/agents.d.ts +11 -2
- package/dist/cli/agents.d.ts.map +1 -1
- package/dist/cli/agents.js +39 -0
- package/dist/cli/agents.js.map +1 -1
- package/dist/cli/commands/install.d.ts.map +1 -1
- package/dist/cli/commands/install.js +31 -8
- package/dist/cli/commands/install.js.map +1 -1
- package/dist/graph/index.d.ts +2 -1
- package/dist/graph/index.d.ts.map +1 -1
- package/dist/graph/index.js +2 -1
- package/dist/graph/index.js.map +1 -1
- package/dist/graph/prisma-link.d.ts +9 -4
- package/dist/graph/prisma-link.d.ts.map +1 -1
- package/dist/graph/prisma-link.js +25 -10
- package/dist/graph/prisma-link.js.map +1 -1
- package/dist/graph/python-calls.d.ts +14 -0
- package/dist/graph/python-calls.d.ts.map +1 -0
- package/dist/graph/python-calls.js +0 -0
- package/dist/graph/python-calls.js.map +1 -0
- package/dist/graph/types.d.ts +1 -1
- package/dist/graph/types.d.ts.map +1 -1
- package/dist/indexer/indexer.d.ts.map +1 -1
- package/dist/indexer/indexer.js +12 -1
- package/dist/indexer/indexer.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +7 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/query/service.d.ts +3 -0
- package/dist/query/service.d.ts.map +1 -1
- package/dist/query/service.js +18 -2
- package/dist/query/service.js.map +1 -1
- package/package.json +10 -1
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ Every answer reports **which tier produced it**, so partial coverage never quiet
|
|
|
18
18
|
And because it's built for agents:
|
|
19
19
|
|
|
20
20
|
- **100% local.** No external APIs, no API keys, no telemetry. Your code never leaves your machine.
|
|
21
|
-
- **Cheaper and faster.** Fewer tool calls and fewer tokens per question, because one graph query replaces a pile of file reads.
|
|
21
|
+
- **Cheaper and faster.** Fewer tool calls and fewer tokens per question, because one graph query replaces a pile of file reads — see [benchmarks](docs/benchmarks/README.md) (a focused, single-call answer vs. grep-then-read; methodology + honest caveats there).
|
|
22
22
|
|
|
23
23
|
## Install
|
|
24
24
|
|
|
@@ -37,7 +37,7 @@ npm install -g @mka-rainmaker/ama
|
|
|
37
37
|
**Fastest — let Ama wire itself in:**
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
|
-
ama install # detects Claude Code / Cursor / Windsurf and writes their MCP config
|
|
40
|
+
ama install # detects Claude Code / Cursor / Windsurf / Codex and writes their MCP config
|
|
41
41
|
ama install --dry-run # preview what it would change, writing nothing
|
|
42
42
|
ama uninstall # remove it again
|
|
43
43
|
```
|
|
@@ -102,6 +102,22 @@ ama --help # list commands
|
|
|
102
102
|
ama mcp # run the MCP server over stdio (what coding agents spawn)
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
+
### Programmatic API
|
|
106
|
+
|
|
107
|
+
Embed Ama as a library — index a repo and query its graph from your own code (the same surface the MCP server and CLI use):
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { index } from "@mka-rainmaker/ama";
|
|
111
|
+
|
|
112
|
+
const ama = await index("/path/to/repo");
|
|
113
|
+
ama.searchSymbol("createServer"); // GraphNode[]
|
|
114
|
+
ama.findCallers("createServer"); // who calls it
|
|
115
|
+
ama.impactAnalysis("AmaSession"); // transitive blast radius
|
|
116
|
+
ama.close(); // release resources when done
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`index(root)` returns a transport-free `AmaSession` (aliased `Ama`) with the full query surface; `open(root)` reuses a persisted index. See [`src/api.ts`](src/api.ts) for the exported types.
|
|
120
|
+
|
|
105
121
|
## What's in 0.1
|
|
106
122
|
|
|
107
123
|
- **Deep TypeScript analysis** via the TypeScript Compiler API — types, overloads, generics, imports/re-exports, inheritance, interface dispatch, cross-file binding, and call graphs.
|
|
@@ -35,6 +35,15 @@ export interface LanguageSpec {
|
|
|
35
35
|
nodes: GraphNode[];
|
|
36
36
|
edges: GraphEdge[];
|
|
37
37
|
};
|
|
38
|
+
/**
|
|
39
|
+
* Optional call detector: walk the CST for call sites and return heuristic `Calls` edges.
|
|
40
|
+
* Baseline tier — name-based resolution within the file (no types), so callers/callees and
|
|
41
|
+
* blast-radius work for languages without a deep analyzer. (ama-bnj)
|
|
42
|
+
*/
|
|
43
|
+
readonly collectCalls?: (root: Parser.SyntaxNode, rel: string) => {
|
|
44
|
+
nodes: GraphNode[];
|
|
45
|
+
edges: GraphEdge[];
|
|
46
|
+
};
|
|
38
47
|
}
|
|
39
48
|
/**
|
|
40
49
|
* 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;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;
|
|
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;IAEhD;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,CACtB,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;IAwDrE;oFACgF;IAChF,OAAO,CAAC,cAAc;CAkBvB"}
|
|
@@ -56,6 +56,11 @@ export class BaselineAnalyzer {
|
|
|
56
56
|
fileNodes.push(...routes.nodes);
|
|
57
57
|
fileEdges.push(...routes.edges);
|
|
58
58
|
}
|
|
59
|
+
if (this.spec.collectCalls) {
|
|
60
|
+
const calls = this.spec.collectCalls(tree.rootNode, rel);
|
|
61
|
+
fileNodes.push(...calls.nodes);
|
|
62
|
+
fileEdges.push(...calls.edges);
|
|
63
|
+
}
|
|
59
64
|
nodes.push(...fileNodes);
|
|
60
65
|
edges.push(...fileEdges);
|
|
61
66
|
}
|
|
@@ -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":"go.d.ts","sourceRoot":"","sources":["../../../src/analyzers/baseline/go.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"go.d.ts","sourceRoot":"","sources":["../../../src/analyzers/baseline/go.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAgHlD;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM,EAAE,YAcpB,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
+
import { symbolId } from "../../graph/index.js";
|
|
3
4
|
import { nearestConfig, parentDir } from "./config.js";
|
|
4
5
|
/** Cache for the nearest `go.mod`'s declared module path, by importer directory. */
|
|
5
6
|
const goModuleCache = new Map();
|
|
@@ -41,6 +42,71 @@ function goImports(node, importerRel, root) {
|
|
|
41
42
|
.filter((f) => f.endsWith(".go") && !f.endsWith("_test.go"))
|
|
42
43
|
.map((f) => [pkgDir ? `${pkgDir}/${f}` : f]);
|
|
43
44
|
}
|
|
45
|
+
/** Gin/chi/echo HTTP-verb router methods — `r.GET("/x", h)`. (ama-a2r) */
|
|
46
|
+
const GO_ROUTE_METHODS = new Set(["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"]);
|
|
47
|
+
/** Normalize a Go route path: chi/mux `{id}` → `:id` (Gin's `:id` is already the shared form);
|
|
48
|
+
* ensure a leading slash. (ama-a2r) */
|
|
49
|
+
function normalizeGoRoutePath(p) {
|
|
50
|
+
const s = p.replace(/\{([^}]+)\}/g, ":$1");
|
|
51
|
+
return s.startsWith("/") ? s : `/${s}`;
|
|
52
|
+
}
|
|
53
|
+
/** The first string-literal argument (interpreted or raw) of an argument_list, unquoted. */
|
|
54
|
+
function goStringArg(args) {
|
|
55
|
+
if (!args)
|
|
56
|
+
return undefined;
|
|
57
|
+
for (const a of args.namedChildren) {
|
|
58
|
+
if (a.type === "interpreted_string_literal" || a.type === "raw_string_literal") {
|
|
59
|
+
return a.text.replace(/^[`"]|[`"]$/g, "");
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
function* eachCall(node) {
|
|
65
|
+
if (node.type === "call_expression")
|
|
66
|
+
yield node;
|
|
67
|
+
for (const c of node.namedChildren)
|
|
68
|
+
yield* eachCall(c);
|
|
69
|
+
}
|
|
70
|
+
/** Detect Gin/chi/echo-style routes: `r.GET("/path", handler)` — a call whose function is a
|
|
71
|
+
* selector with an HTTP-verb field and a string first arg — becomes a `METHOD /path` Route,
|
|
72
|
+
* referencing the handler when it's a plain identifier in the same file. (ama-a2r) */
|
|
73
|
+
function goRoutes(root, rel) {
|
|
74
|
+
const nodes = [];
|
|
75
|
+
const edges = [];
|
|
76
|
+
for (const call of eachCall(root)) {
|
|
77
|
+
const fn = call.childForFieldName("function");
|
|
78
|
+
if (fn?.type !== "selector_expression")
|
|
79
|
+
continue;
|
|
80
|
+
const verb = fn.childForFieldName("field")?.text?.toUpperCase();
|
|
81
|
+
if (!verb || !GO_ROUTE_METHODS.has(verb))
|
|
82
|
+
continue;
|
|
83
|
+
const args = call.childForFieldName("arguments");
|
|
84
|
+
const raw = goStringArg(args);
|
|
85
|
+
if (raw === undefined)
|
|
86
|
+
continue;
|
|
87
|
+
const name = `${verb} ${normalizeGoRoutePath(raw)}`;
|
|
88
|
+
const routeId = symbolId({ file: rel, qualifiedName: name });
|
|
89
|
+
nodes.push({
|
|
90
|
+
id: routeId,
|
|
91
|
+
kind: "Route",
|
|
92
|
+
name,
|
|
93
|
+
file: rel,
|
|
94
|
+
qualifiedName: name,
|
|
95
|
+
tier: "baseline",
|
|
96
|
+
range: { startLine: call.startPosition.row + 1, endLine: call.endPosition.row + 1 },
|
|
97
|
+
});
|
|
98
|
+
const handler = args?.namedChildren.find((a, i) => i > 0 && a.type === "identifier");
|
|
99
|
+
if (handler) {
|
|
100
|
+
edges.push({
|
|
101
|
+
from: routeId,
|
|
102
|
+
to: symbolId({ file: rel, qualifiedName: handler.text }),
|
|
103
|
+
kind: "References",
|
|
104
|
+
provenance: "heuristic",
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return { nodes, edges };
|
|
109
|
+
}
|
|
44
110
|
/**
|
|
45
111
|
* Baseline (syntactic) spec for Go. Go declares named types with a single
|
|
46
112
|
* `type_spec` node regardless of whether the body is a struct, interface, or
|
|
@@ -62,5 +128,6 @@ export const goSpec = {
|
|
|
62
128
|
},
|
|
63
129
|
},
|
|
64
130
|
resolveImports: goImports,
|
|
131
|
+
collectRoutes: goRoutes,
|
|
65
132
|
};
|
|
66
133
|
//# sourceMappingURL=go.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"go.js","sourceRoot":"","sources":["../../../src/analyzers/baseline/go.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"go.js","sourceRoot":"","sources":["../../../src/analyzers/baseline/go.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"java.d.ts","sourceRoot":"","sources":["../../../src/analyzers/baseline/java.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"java.d.ts","sourceRoot":"","sources":["../../../src/analyzers/baseline/java.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AA0HlD;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,EAAE,YAYtB,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { symbolId } from "../../graph/index.js";
|
|
1
2
|
import { ancestorDirs } from "./paths.js";
|
|
2
3
|
/** Try a repo-relative file under every ancestor directory of the importer. A
|
|
3
4
|
* package import gives a *source-root-relative* path (`com/example/Foo.java`)
|
|
@@ -29,6 +30,88 @@ function javaImports(node, importerRel) {
|
|
|
29
30
|
const file = `${segments.slice(0, classEnd + 1).join("/")}.java`;
|
|
30
31
|
return [ancestorCandidates(importerRel, file)];
|
|
31
32
|
}
|
|
33
|
+
/** Spring method-mapping annotations → HTTP verb. `@RequestMapping` is the class-level prefix. */
|
|
34
|
+
const JAVA_MAPPING_VERBS = new Map([
|
|
35
|
+
["GetMapping", "GET"],
|
|
36
|
+
["PostMapping", "POST"],
|
|
37
|
+
["PutMapping", "PUT"],
|
|
38
|
+
["DeleteMapping", "DELETE"],
|
|
39
|
+
["PatchMapping", "PATCH"],
|
|
40
|
+
]);
|
|
41
|
+
function firstOfType(node, type) {
|
|
42
|
+
if (node.type === type)
|
|
43
|
+
return node;
|
|
44
|
+
for (const c of node.namedChildren) {
|
|
45
|
+
const found = firstOfType(c, type);
|
|
46
|
+
if (found)
|
|
47
|
+
return found;
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
function* eachClass(node) {
|
|
52
|
+
if (node.type === "class_declaration")
|
|
53
|
+
yield node;
|
|
54
|
+
for (const c of node.namedChildren)
|
|
55
|
+
yield* eachClass(c);
|
|
56
|
+
}
|
|
57
|
+
/** The string argument of an `@Annotation("x")`, or undefined for a marker annotation. */
|
|
58
|
+
function annotationArg(ann) {
|
|
59
|
+
return firstOfType(ann, "string_fragment")?.text;
|
|
60
|
+
}
|
|
61
|
+
/** Combine a Spring class prefix and a method sub-path into a normalized `:param` route. */
|
|
62
|
+
function joinJavaRoutePath(prefix, sub) {
|
|
63
|
+
const norm = (s) => s.replace(/\{([^}]+)\}/g, ":$1");
|
|
64
|
+
const segs = [norm(prefix), norm(sub)].flatMap((s) => s.split("/")).filter(Boolean);
|
|
65
|
+
return `/${segs.join("/")}`;
|
|
66
|
+
}
|
|
67
|
+
/** Detect Spring MVC routes: a class `@RequestMapping("/prefix")` prefixes each method's
|
|
68
|
+
* `@GetMapping`/`@PostMapping`/… (path or marker) to form a `METHOD /prefix/path` Route that
|
|
69
|
+
* references the method (`Class.method`). (ama-a2r) */
|
|
70
|
+
function javaRoutes(root, rel) {
|
|
71
|
+
const nodes = [];
|
|
72
|
+
const edges = [];
|
|
73
|
+
const annotationsOf = (node) => (node.namedChildren.find((c) => c.type === "modifiers")?.namedChildren ?? []).filter((a) => a.type === "annotation" || a.type === "marker_annotation");
|
|
74
|
+
for (const cls of eachClass(root)) {
|
|
75
|
+
const className = cls.childForFieldName("name")?.text;
|
|
76
|
+
const prefix = annotationsOf(cls).find((a) => a.childForFieldName("name")?.text === "RequestMapping") ??
|
|
77
|
+
null;
|
|
78
|
+
const classPrefix = prefix ? (annotationArg(prefix) ?? "") : "";
|
|
79
|
+
const body = cls.childForFieldName("body");
|
|
80
|
+
for (const member of body?.namedChildren ?? []) {
|
|
81
|
+
if (member.type !== "method_declaration")
|
|
82
|
+
continue;
|
|
83
|
+
const mapping = annotationsOf(member)
|
|
84
|
+
.map((a) => ({
|
|
85
|
+
verb: JAVA_MAPPING_VERBS.get(a.childForFieldName("name")?.text ?? ""),
|
|
86
|
+
ann: a,
|
|
87
|
+
}))
|
|
88
|
+
.find((m) => m.verb);
|
|
89
|
+
if (!mapping?.verb)
|
|
90
|
+
continue;
|
|
91
|
+
const methodName = member.childForFieldName("name")?.text;
|
|
92
|
+
const name = `${mapping.verb} ${joinJavaRoutePath(classPrefix, annotationArg(mapping.ann) ?? "")}`;
|
|
93
|
+
const routeId = symbolId({ file: rel, qualifiedName: name });
|
|
94
|
+
nodes.push({
|
|
95
|
+
id: routeId,
|
|
96
|
+
kind: "Route",
|
|
97
|
+
name,
|
|
98
|
+
file: rel,
|
|
99
|
+
qualifiedName: name,
|
|
100
|
+
tier: "baseline",
|
|
101
|
+
range: { startLine: member.startPosition.row + 1, endLine: member.endPosition.row + 1 },
|
|
102
|
+
});
|
|
103
|
+
if (className && methodName) {
|
|
104
|
+
edges.push({
|
|
105
|
+
from: routeId,
|
|
106
|
+
to: symbolId({ file: rel, qualifiedName: `${className}.${methodName}` }),
|
|
107
|
+
kind: "References",
|
|
108
|
+
provenance: "heuristic",
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return { nodes, edges };
|
|
114
|
+
}
|
|
32
115
|
/**
|
|
33
116
|
* Baseline (syntactic) spec for Java. Java gives every kind its own CST node
|
|
34
117
|
* type — class/interface/enum declarations and methods — so each maps directly
|
|
@@ -46,5 +129,6 @@ export const javaSpec = {
|
|
|
46
129
|
method_declaration: { kind: "Method" },
|
|
47
130
|
},
|
|
48
131
|
resolveImports: javaImports,
|
|
132
|
+
collectRoutes: javaRoutes,
|
|
49
133
|
};
|
|
50
134
|
//# sourceMappingURL=java.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"java.js","sourceRoot":"","sources":["../../../src/analyzers/baseline/java.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"java.js","sourceRoot":"","sources":["../../../src/analyzers/baseline/java.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"php.d.ts","sourceRoot":"","sources":["../../../src/analyzers/baseline/php.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"php.d.ts","sourceRoot":"","sources":["../../../src/analyzers/baseline/php.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AA6GlD;;;;;;;GAOG;AACH,eAAO,MAAM,OAAO,EAAE,YAcrB,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
+
import { symbolId } from "../../graph/index.js";
|
|
3
4
|
import { nearestConfig, parentDir } from "./config.js";
|
|
4
5
|
/** Cache for the nearest composer.json's PSR-4 `[prefix, baseDir]` map, by directory. */
|
|
5
6
|
const composerCache = new Map();
|
|
@@ -51,6 +52,60 @@ function phpImports(node, importerRel, root) {
|
|
|
51
52
|
const file = [composer.dir, best.base, `${relPath}.php`].filter(Boolean).join("/");
|
|
52
53
|
return [[file]];
|
|
53
54
|
}
|
|
55
|
+
/** Laravel `Route` facade HTTP-verb methods — `Route::get('/x', ...)`. (ama-a2r) */
|
|
56
|
+
const PHP_ROUTE_METHODS = new Set(["get", "post", "put", "delete", "patch", "options", "head"]);
|
|
57
|
+
/** Normalize a Laravel route path: `{id}` → `:id`; ensure a leading slash. (ama-a2r) */
|
|
58
|
+
function normalizePhpRoutePath(p) {
|
|
59
|
+
const s = p.replace(/\{([^}]+)\}/g, ":$1");
|
|
60
|
+
return s.startsWith("/") ? s : `/${s}`;
|
|
61
|
+
}
|
|
62
|
+
function firstOfType(node, type) {
|
|
63
|
+
if (node.type === type)
|
|
64
|
+
return node;
|
|
65
|
+
for (const c of node.namedChildren) {
|
|
66
|
+
const found = firstOfType(c, type);
|
|
67
|
+
if (found)
|
|
68
|
+
return found;
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
function* eachScopedCall(node) {
|
|
73
|
+
if (node.type === "scoped_call_expression")
|
|
74
|
+
yield node;
|
|
75
|
+
for (const c of node.namedChildren)
|
|
76
|
+
yield* eachScopedCall(c);
|
|
77
|
+
}
|
|
78
|
+
/** Detect Laravel routes: `Route::<verb>('/path', handler)` — a static call on the `Route`
|
|
79
|
+
* facade with an HTTP-verb method and a string first arg — becomes a `METHOD /path` Route.
|
|
80
|
+
* Scoped to the `Route` facade so unrelated static calls (`Cache::get`) don't match. The
|
|
81
|
+
* handler is usually a controller reference (array/string), not a same-file function, so no
|
|
82
|
+
* handler edge is emitted. (ama-a2r) */
|
|
83
|
+
function phpRoutes(root, rel) {
|
|
84
|
+
const nodes = [];
|
|
85
|
+
for (const call of eachScopedCall(root)) {
|
|
86
|
+
const scope = call.childForFieldName("scope")?.text ?? call.namedChild(0)?.text;
|
|
87
|
+
const method = call.childForFieldName("name")?.text?.toLowerCase();
|
|
88
|
+
if (scope !== "Route" || !method || !PHP_ROUTE_METHODS.has(method))
|
|
89
|
+
continue;
|
|
90
|
+
const firstArg = call
|
|
91
|
+
.childForFieldName("arguments")
|
|
92
|
+
?.namedChildren.find((c) => c.type === "argument");
|
|
93
|
+
const raw = firstArg && firstOfType(firstArg, "string_content")?.text;
|
|
94
|
+
if (!raw)
|
|
95
|
+
continue;
|
|
96
|
+
const name = `${method.toUpperCase()} ${normalizePhpRoutePath(raw)}`;
|
|
97
|
+
nodes.push({
|
|
98
|
+
id: symbolId({ file: rel, qualifiedName: name }),
|
|
99
|
+
kind: "Route",
|
|
100
|
+
name,
|
|
101
|
+
file: rel,
|
|
102
|
+
qualifiedName: name,
|
|
103
|
+
tier: "baseline",
|
|
104
|
+
range: { startLine: call.startPosition.row + 1, endLine: call.endPosition.row + 1 },
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return { nodes, edges: [] };
|
|
108
|
+
}
|
|
54
109
|
/**
|
|
55
110
|
* Baseline (syntactic) spec for PHP. Each top-level construct has its own CST
|
|
56
111
|
* node type — class/interface/trait/enum declarations, free functions, and
|
|
@@ -72,5 +127,6 @@ export const phpSpec = {
|
|
|
72
127
|
method_declaration: { kind: "Method" },
|
|
73
128
|
},
|
|
74
129
|
resolveImports: phpImports,
|
|
130
|
+
collectRoutes: phpRoutes,
|
|
75
131
|
};
|
|
76
132
|
//# sourceMappingURL=php.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"php.js","sourceRoot":"","sources":["../../../src/analyzers/baseline/php.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"php.js","sourceRoot":"","sources":["../../../src/analyzers/baseline/php.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":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;
|
|
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;AAqSlD;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,EAAE,YAWxB,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
|
-
import { symbolId } from "../../graph/index.js";
|
|
2
|
+
import { CALL_REF_PREFIX, symbolId } from "../../graph/index.js";
|
|
3
3
|
/**
|
|
4
4
|
* Resolve a Python relative import (`from .x import y`, `from . import m`,
|
|
5
5
|
* `from ..pkg import z`) to candidate repo-relative module files. The leading
|
|
@@ -141,6 +141,163 @@ function pythonRoutes(root, rel) {
|
|
|
141
141
|
}
|
|
142
142
|
return { nodes, edges };
|
|
143
143
|
}
|
|
144
|
+
/** Django URL-pattern functions in `urls.py`. */
|
|
145
|
+
const DJANGO_URL_FUNCS = new Set(["path", "re_path"]);
|
|
146
|
+
function* eachCall(node) {
|
|
147
|
+
if (node.type === "call")
|
|
148
|
+
yield node;
|
|
149
|
+
for (const c of node.namedChildren)
|
|
150
|
+
yield* eachCall(c);
|
|
151
|
+
}
|
|
152
|
+
/** Detect Django URL patterns: `path("users/<int:pk>/", view)` / `re_path(...)` in urls.py —
|
|
153
|
+
* method-agnostic (the view handles every verb), so each forms an `ANY /path` Route. The view
|
|
154
|
+
* is a cross-module reference (`views.foo`), not a same-file symbol, so no handler edge. (ama-a2r) */
|
|
155
|
+
function djangoUrlRoutes(root, rel) {
|
|
156
|
+
const nodes = [];
|
|
157
|
+
for (const call of eachCall(root)) {
|
|
158
|
+
const fn = call.childForFieldName("function");
|
|
159
|
+
if (fn?.type !== "identifier" || !DJANGO_URL_FUNCS.has(fn.text))
|
|
160
|
+
continue;
|
|
161
|
+
const raw = firstStringArg(call.childForFieldName("arguments"));
|
|
162
|
+
if (raw === undefined)
|
|
163
|
+
continue;
|
|
164
|
+
const name = `ANY ${normalizeRoutePath(raw)}`;
|
|
165
|
+
nodes.push({
|
|
166
|
+
id: symbolId({ file: rel, qualifiedName: name }),
|
|
167
|
+
kind: "Route",
|
|
168
|
+
name,
|
|
169
|
+
file: rel,
|
|
170
|
+
qualifiedName: name,
|
|
171
|
+
tier: "baseline",
|
|
172
|
+
range: { startLine: call.startPosition.row + 1, endLine: call.endPosition.row + 1 },
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
return { nodes, edges: [] };
|
|
176
|
+
}
|
|
177
|
+
/** Python route detection across shapes: Flask/FastAPI decorators + Django urls.py `path()`. */
|
|
178
|
+
function pythonRoutesAll(root, rel) {
|
|
179
|
+
const decorated = pythonRoutes(root, rel);
|
|
180
|
+
const django = djangoUrlRoutes(root, rel);
|
|
181
|
+
return {
|
|
182
|
+
nodes: [...decorated.nodes, ...django.nodes],
|
|
183
|
+
edges: [...decorated.edges, ...django.edges],
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
/** The nearest enclosing `function_definition` of a node, or undefined (module-level). */
|
|
187
|
+
function enclosingFunction(node) {
|
|
188
|
+
for (let p = node.parent; p; p = p.parent) {
|
|
189
|
+
if (p.type === "function_definition")
|
|
190
|
+
return p;
|
|
191
|
+
}
|
|
192
|
+
return undefined;
|
|
193
|
+
}
|
|
194
|
+
function* eachFunction(node) {
|
|
195
|
+
if (node.type === "function_definition")
|
|
196
|
+
yield node;
|
|
197
|
+
for (const c of node.namedChildren)
|
|
198
|
+
yield* eachFunction(c);
|
|
199
|
+
}
|
|
200
|
+
/** The simple (last-segment) name a call targets: `foo()` → "foo", `obj.bar()` → "bar". */
|
|
201
|
+
function calleeName(call) {
|
|
202
|
+
const fn = call.childForFieldName("function");
|
|
203
|
+
if (fn?.type === "identifier")
|
|
204
|
+
return fn.text;
|
|
205
|
+
if (fn?.type === "attribute")
|
|
206
|
+
return fn.childForFieldName("attribute")?.text;
|
|
207
|
+
return undefined;
|
|
208
|
+
}
|
|
209
|
+
/** Common Python builtins — not emitted as cross-file call candidates (they resolve to no
|
|
210
|
+
* project function, so they'd only add dangling candidates). (ama-bnj) */
|
|
211
|
+
const PYTHON_BUILTINS = new Set([
|
|
212
|
+
"print",
|
|
213
|
+
"len",
|
|
214
|
+
"range",
|
|
215
|
+
"str",
|
|
216
|
+
"int",
|
|
217
|
+
"float",
|
|
218
|
+
"bool",
|
|
219
|
+
"list",
|
|
220
|
+
"dict",
|
|
221
|
+
"set",
|
|
222
|
+
"tuple",
|
|
223
|
+
"isinstance",
|
|
224
|
+
"issubclass",
|
|
225
|
+
"super",
|
|
226
|
+
"open",
|
|
227
|
+
"enumerate",
|
|
228
|
+
"zip",
|
|
229
|
+
"map",
|
|
230
|
+
"filter",
|
|
231
|
+
"sorted",
|
|
232
|
+
"reversed",
|
|
233
|
+
"sum",
|
|
234
|
+
"min",
|
|
235
|
+
"max",
|
|
236
|
+
"abs",
|
|
237
|
+
"round",
|
|
238
|
+
"getattr",
|
|
239
|
+
"setattr",
|
|
240
|
+
"hasattr",
|
|
241
|
+
"type",
|
|
242
|
+
"repr",
|
|
243
|
+
"format",
|
|
244
|
+
"iter",
|
|
245
|
+
"next",
|
|
246
|
+
"any",
|
|
247
|
+
"all",
|
|
248
|
+
]);
|
|
249
|
+
/** Heuristic baseline call edges. A call to a function/method defined in the SAME file resolves
|
|
250
|
+
* straight to a `Calls` edge (name-based; an ambiguous name defined more than once, and
|
|
251
|
+
* module-level calls with no enclosing function, are skipped). A call to a name NOT defined
|
|
252
|
+
* locally (and not a builtin) becomes a `call:<name>` candidate that {@link deriveCallEdges}
|
|
253
|
+
* resolves cross-file via the import graph. (ama-bnj) */
|
|
254
|
+
function pythonCalls(root, rel) {
|
|
255
|
+
const byName = new Map(); // simple name → id, or null when ambiguous
|
|
256
|
+
for (const fn of eachFunction(root)) {
|
|
257
|
+
const qn = qualifiedNameOf(fn);
|
|
258
|
+
if (!qn)
|
|
259
|
+
continue;
|
|
260
|
+
const simple = qn.slice(qn.lastIndexOf(".") + 1);
|
|
261
|
+
byName.set(simple, byName.has(simple) ? null : symbolId({ file: rel, qualifiedName: qn }));
|
|
262
|
+
}
|
|
263
|
+
const edges = [];
|
|
264
|
+
const seen = new Set();
|
|
265
|
+
for (const call of eachCall(root)) {
|
|
266
|
+
const enc = enclosingFunction(call);
|
|
267
|
+
const name = calleeName(call);
|
|
268
|
+
if (!enc || !name)
|
|
269
|
+
continue;
|
|
270
|
+
const callerQn = qualifiedNameOf(enc);
|
|
271
|
+
if (!callerQn)
|
|
272
|
+
continue;
|
|
273
|
+
const from = symbolId({ file: rel, qualifiedName: callerQn });
|
|
274
|
+
const local = byName.get(name);
|
|
275
|
+
if (local === null)
|
|
276
|
+
continue; // a name defined more than once locally — don't guess
|
|
277
|
+
if (local) {
|
|
278
|
+
// resolved within this file (slice 1)
|
|
279
|
+
const key = `c ${from} ${local}`;
|
|
280
|
+
if (from === local || seen.has(key))
|
|
281
|
+
continue; // skip self-recursion + duplicate sites
|
|
282
|
+
seen.add(key);
|
|
283
|
+
edges.push({ from, to: local, kind: "Calls", provenance: "heuristic" });
|
|
284
|
+
}
|
|
285
|
+
else if (!PYTHON_BUILTINS.has(name)) {
|
|
286
|
+
// not local — a cross-file candidate deriveCallEdges resolves via the import graph (slice 2)
|
|
287
|
+
const key = `r ${from} ${name}`;
|
|
288
|
+
if (seen.has(key))
|
|
289
|
+
continue;
|
|
290
|
+
seen.add(key);
|
|
291
|
+
edges.push({
|
|
292
|
+
from,
|
|
293
|
+
to: `${CALL_REF_PREFIX}${name}`,
|
|
294
|
+
kind: "References",
|
|
295
|
+
provenance: "call-ref",
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return { nodes: [], edges };
|
|
300
|
+
}
|
|
144
301
|
/**
|
|
145
302
|
* Baseline (syntactic) spec for Python. Functions and classes are the symbols
|
|
146
303
|
* worth a node; methods are `function_definition` too (Python doesn't
|
|
@@ -157,6 +314,7 @@ export const pythonSpec = {
|
|
|
157
314
|
class_definition: { kind: "Class" },
|
|
158
315
|
},
|
|
159
316
|
resolveImports: pythonImports,
|
|
160
|
-
collectRoutes:
|
|
317
|
+
collectRoutes: pythonRoutesAll,
|
|
318
|
+
collectCalls: pythonCalls,
|
|
161
319
|
};
|
|
162
320
|
//# sourceMappingURL=python.js.map
|