@mka-rainmaker/ama 0.1.2 → 0.3.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 +81 -53
- 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 +178 -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 +28 -28
- 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/cli/commands/upgrade.d.ts +27 -0
- package/dist/cli/commands/upgrade.d.ts.map +1 -0
- package/dist/cli/commands/upgrade.js +136 -0
- package/dist/cli/commands/upgrade.js.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/graph/index.d.ts +3 -1
- package/dist/graph/index.d.ts.map +1 -1
- package/dist/graph/index.js +3 -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/route-tests.d.ts +15 -0
- package/dist/graph/route-tests.d.ts.map +1 -0
- package/dist/graph/route-tests.js +67 -0
- package/dist/graph/route-tests.js.map +1 -0
- package/dist/graph/types.d.ts +1 -1
- package/dist/graph/types.d.ts.map +1 -1
- package/dist/indexer/ignore.d.ts.map +1 -1
- package/dist/indexer/ignore.js +13 -1
- package/dist/indexer/ignore.js.map +1 -1
- package/dist/indexer/indexer.d.ts.map +1 -1
- package/dist/indexer/indexer.js +22 -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 +19 -2
- package/dist/query/service.js.map +1 -1
- package/package.json +11 -1
package/README.md
CHANGED
|
@@ -1,43 +1,80 @@
|
|
|
1
1
|
# Ama 🐶
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<p align="center">
|
|
4
|
+
<a href="https://www.npmjs.com/package/@mka-rainmaker/ama"><img alt="npm" src="https://img.shields.io/npm/v/@mka-rainmaker/ama?label=npm&color=007ec6"></a>
|
|
5
|
+
<a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-e0a100"></a>
|
|
6
|
+
<img alt="Node.js 24+" src="https://img.shields.io/badge/Node.js-24%2B-44883e">
|
|
7
|
+
</p>
|
|
8
|
+
<p align="center">
|
|
9
|
+
<img alt="macOS supported" src="https://img.shields.io/badge/macOS-supported-4c8eda">
|
|
10
|
+
<img alt="Linux supported" src="https://img.shields.io/badge/Linux-supported-4c8eda">
|
|
11
|
+
<img alt="Windows supported" src="https://img.shields.io/badge/Windows-supported-4c8eda">
|
|
12
|
+
</p>
|
|
13
|
+
<p align="center">
|
|
14
|
+
<img alt="Claude Code supported" src="https://img.shields.io/badge/Claude_Code-supported-8a3ffc">
|
|
15
|
+
<img alt="Cursor supported" src="https://img.shields.io/badge/Cursor-supported-8a3ffc">
|
|
16
|
+
<img alt="Windsurf supported" src="https://img.shields.io/badge/Windsurf-supported-8a3ffc">
|
|
17
|
+
<img alt="Codex supported" src="https://img.shields.io/badge/Codex-supported-8a3ffc">
|
|
18
|
+
<img alt="any MCP client" src="https://img.shields.io/badge/+_any_MCP_client-via_config-9f9f9f">
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
**Ama** is a local-first **code-intelligence server** that speaks the [Model Context Protocol (MCP)](https://modelcontextprotocol.io). It parses a codebase into a queryable knowledge graph of symbols and their relationships, then hands that graph to AI coding agents — so an agent answers *"who calls this?"*, *"what breaks if I change this?"*, and *"which tests cover this route?"* in a **single tool call** instead of dozens of file reads.
|
|
4
22
|
|
|
5
23
|
Named after a puppy: small, eager, and a little smarter every day.
|
|
6
24
|
|
|
7
|
-
> Status: **0.
|
|
25
|
+
> Status: **0.2** — deep TypeScript analysis; a baseline call graph for Python (incl. FastAPI route→handler→test impact); framework-route detection across TypeScript, Python, Go, PHP, Java, and Rust; syntactic breadth for 13 more languages; an embeddable library API; 27 MCP tools; an `ama` CLI; and persistent, auto-syncing incremental indexing — all able to index Ama's own source cleanly as the built-in regression test.
|
|
26
|
+
|
|
27
|
+
## Get started
|
|
28
|
+
|
|
29
|
+
> Requires **Node.js 24+**.
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install -g @mka-rainmaker/ama # 1. install
|
|
33
|
+
ama install # 2. wire it into your agent (Claude Code / Cursor / Windsurf / Codex)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
3. Point your agent at a repo and ask structural questions — *"who calls `createServer`?"*, *"what breaks if I change `AmaSession`?"* Your agent runs `index_repository` once, then queries the graph; Ama re-indexes automatically as you edit.
|
|
37
|
+
|
|
38
|
+
No global install? Use `npx -y @mka-rainmaker/ama mcp` as the command — see [Configure your coding agent](#configure-your-coding-agent).
|
|
8
39
|
|
|
9
40
|
## Why Ama
|
|
10
41
|
|
|
11
42
|
Most code-graph tools parse every language the same way: one fast, syntactic pass that sees *shapes* but not *meaning*. Ama takes a different bet — **use each language's real compiler when one exists.**
|
|
12
43
|
|
|
13
44
|
- **Deep tier — language-specific semantic analysis.** TypeScript via the TypeScript Compiler API today; .NET via Roslyn and Java via its native tooling next. This resolves types, overloads, generics, imports/re-exports, interface dispatch, and cross-file symbol binding that a purely syntactic parser cannot.
|
|
14
|
-
- **Baseline tier — universal syntactic analysis for breadth.** Every other language
|
|
15
|
-
|
|
16
|
-
Every answer reports **which tier produced it**, so partial coverage never quietly masquerades as complete.
|
|
45
|
+
- **Baseline tier — universal syntactic analysis for breadth.** Every other language gets parsed for structure (and, where it pays off, a heuristic call graph), so the whole repo is navigable from day one.
|
|
17
46
|
|
|
18
|
-
And because it's built for agents:
|
|
47
|
+
Every answer reports **which tier produced it**, so partial coverage never quietly masquerades as complete. And because it's built for agents:
|
|
19
48
|
|
|
20
49
|
- **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
|
|
50
|
+
- **Cheaper and faster.** Fewer tool calls and fewer tokens per question — one graph query replaces a pile of file reads.
|
|
22
51
|
|
|
23
|
-
##
|
|
52
|
+
## Benchmarks
|
|
24
53
|
|
|
25
|
-
|
|
54
|
+
On Ama's own repo (5 representative questions): **~99% fewer tokens and ~96% fewer tool calls** to *obtain* an answer than the grep-then-read an agent falls back to without a graph — one focused, structured result instead of pulling whole files into context. That headline is a **ceiling** (the baseline reads every grep-matching file in full); [`docs/benchmarks`](docs/benchmarks/README.md) has the methodology and honest caveats, and `node scripts/benchmark.mjs` reproduces it.
|
|
26
55
|
|
|
27
|
-
|
|
56
|
+
## How auto-sync works
|
|
28
57
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
58
|
+
Ama keeps the graph current while connected, so you never run a manual sync:
|
|
59
|
+
|
|
60
|
+
- A native **file watcher** debounces bursts of edits, then re-indexes each changed file **in place** (no full rebuild).
|
|
61
|
+
- On reconnect, Ama **reconciles** anything that changed while it was away (size/mtime + content-hash diff).
|
|
62
|
+
- `index_status()` reports what's indexed, per-language coverage + tier, and how many edits are pending.
|
|
63
|
+
|
|
64
|
+
## Framework-aware routes
|
|
32
65
|
|
|
33
|
-
|
|
66
|
+
Ama maps HTTP routes to their handlers across stacks, so *"who handles `POST /reports`?"* is one query:
|
|
34
67
|
|
|
35
|
-
|
|
68
|
+
- **TypeScript** — Express, NestJS, Fastify, Hapi, Koa, Hono, tRPC, GraphQL, plus filename routers (Next.js Pages & App, Nuxt, Astro, SvelteKit).
|
|
69
|
+
- **Python** — Flask, FastAPI, Django (`urls.py`); FastAPI `TestClient` calls link **test → route → handler**, so `impact_analysis` / `affected` reach route tests.
|
|
70
|
+
- **Go** (Gin/chi), **PHP** (Laravel), **Java** (Spring `@GetMapping`), **Rust** (actix attribute macros).
|
|
71
|
+
|
|
72
|
+
## Configure your coding agent
|
|
36
73
|
|
|
37
74
|
**Fastest — let Ama wire itself in:**
|
|
38
75
|
|
|
39
76
|
```bash
|
|
40
|
-
ama install # detects Claude Code / Cursor / Windsurf and writes their MCP config
|
|
77
|
+
ama install # detects Claude Code / Cursor / Windsurf / Codex and writes their MCP config
|
|
41
78
|
ama install --dry-run # preview what it would change, writing nothing
|
|
42
79
|
ama uninstall # remove it again
|
|
43
80
|
```
|
|
@@ -76,24 +113,28 @@ claude mcp add ama -- ama mcp
|
|
|
76
113
|
|
|
77
114
|
### Fewer tools, lower token cost
|
|
78
115
|
|
|
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):
|
|
116
|
+
Ama exposes 27 tools by default. To trade that for a small high-signal set, set `AMA_MCP_TOOLS` on the server — `minimal` (just `explore` + indexing), or a comma-separated list of tool names (the indexing tools are always included):
|
|
82
117
|
|
|
83
118
|
```json
|
|
84
119
|
{ "mcpServers": { "ama": { "command": "ama", "args": ["mcp"], "env": { "AMA_MCP_TOOLS": "minimal" } } } }
|
|
85
120
|
```
|
|
86
121
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
Once connected, point Ama at a repo and start asking graph questions:
|
|
122
|
+
## MCP tools
|
|
90
123
|
|
|
91
|
-
|
|
92
|
-
|
|
124
|
+
| Tool | What it does |
|
|
125
|
+
|---|---|
|
|
126
|
+
| `index_repository(path)` | Build the graph for a directory or project. Run first. |
|
|
127
|
+
| `index_status()` | What's indexed: node/edge counts, per-language coverage + tier, pending edits. |
|
|
128
|
+
| `search_symbol(query)` / `search_code(query)` | Find symbols by name (add `exact: true` for a precise dotted match), or search snippet text. |
|
|
129
|
+
| `find_callers` / `find_callees` | Who calls a function/method, and what it calls. |
|
|
130
|
+
| `find_referrers` / `find_imports` / `find_importers` | Where a symbol is used / what a file imports / who imports it. |
|
|
131
|
+
| `impact_analysis(symbol)` | Transitive blast radius for change/test selection. |
|
|
132
|
+
| `explore(question)` | Relevant symbols, a relationship map, and blast radius in one call. |
|
|
133
|
+
| `get_code_snippet(symbol)` / `file_skeleton(file)` | A symbol's source, or a file's symbol outline. |
|
|
93
134
|
|
|
94
|
-
|
|
135
|
+
…and more (overrides, interfaces, type users, routes → handlers, circular imports). Call `get_graph_schema()` for the full node/edge model, or `ama --help` for the CLI.
|
|
95
136
|
|
|
96
|
-
|
|
137
|
+
## CLI
|
|
97
138
|
|
|
98
139
|
The same package ships an `ama` CLI mirroring the query surface, for one-shot use and scripting (e.g. `git diff --name-only | ama affected`):
|
|
99
140
|
|
|
@@ -102,19 +143,21 @@ ama --help # list commands
|
|
|
102
143
|
ama mcp # run the MCP server over stdio (what coding agents spawn)
|
|
103
144
|
```
|
|
104
145
|
|
|
105
|
-
##
|
|
146
|
+
## Programmatic API
|
|
106
147
|
|
|
107
|
-
|
|
108
|
-
- **Baseline breadth** for 13 more languages via tree-sitter: C, C++, C#, Go, Java, JavaScript, Kotlin, PHP, Python, Rust, Swift, and Vue/Svelte single-file components.
|
|
109
|
-
- **27 MCP tools** — search, call graph, references, type usage, inheritance/overrides, imports/importers, routes → handlers, code snippets, plus higher-order `explore`, `impact_analysis`, and `search_code` — each tagging the tier that produced it.
|
|
110
|
-
- **Persistent indexing** (SQLite + full-text search) with **incremental re-indexing**: edits are picked up automatically while connected.
|
|
111
|
-
- **Cross-project queries** — index several repos in one session and target any of them by path.
|
|
112
|
-
- **An `ama` CLI** for one-shot queries and scripting.
|
|
148
|
+
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):
|
|
113
149
|
|
|
114
|
-
|
|
150
|
+
```ts
|
|
151
|
+
import { index } from "@mka-rainmaker/ama";
|
|
115
152
|
|
|
116
|
-
|
|
117
|
-
|
|
153
|
+
const ama = await index("/path/to/repo");
|
|
154
|
+
ama.searchSymbol("createServer"); // GraphNode[]
|
|
155
|
+
ama.findCallers("createServer"); // who calls it
|
|
156
|
+
ama.impactAnalysis("AmaSession"); // transitive blast radius
|
|
157
|
+
ama.close(); // release resources when done
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
`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.
|
|
118
161
|
|
|
119
162
|
## How it works
|
|
120
163
|
|
|
@@ -122,27 +165,12 @@ ama mcp # run the MCP server over stdio (what coding agents spawn)
|
|
|
122
165
|
source files ──▶ analyzer (deep | baseline) ──▶ graph (nodes + edges) ──▶ store ──▶ query ──▶ MCP tools
|
|
123
166
|
```
|
|
124
167
|
|
|
125
|
-
- **Graph model** — language-agnostic `nodes` (File, Module, Class, Interface, Enum, Function, Method, …) and `edges` (Defines, Calls, Inherits, Implements, UsesType, Imports, References, …). Each symbol gets a stable, location-independent id.
|
|
168
|
+
- **Graph model** — language-agnostic `nodes` (File, Module, Class, Interface, Enum, Function, Method, Route, …) and `edges` (Defines, Calls, Inherits, Implements, UsesType, Imports, References, …). Each symbol gets a stable, location-independent id.
|
|
126
169
|
- **Analyzers** — pluggable per language, each declaring its tier (`deep` or `baseline`). The TypeScript deep analyzer is the reference implementation.
|
|
127
|
-
- **Store** — in-memory, or SQLite with full-text search for persistence.
|
|
170
|
+
- **Store** — in-memory, or SQLite with full-text search (FTS5) for persistence.
|
|
128
171
|
- **Query service** — search, call-graph traversal, code snippets, and impact analysis.
|
|
129
172
|
- **MCP server** — exposes the query surface over stdio.
|
|
130
173
|
|
|
131
|
-
## MCP tools
|
|
132
|
-
|
|
133
|
-
| Tool | What it does |
|
|
134
|
-
|---|---|
|
|
135
|
-
| `index_repository(path)` | Build the graph for a directory or project. Run first. |
|
|
136
|
-
| `index_status()` | What's indexed: node/edge counts, per-language coverage + tier. |
|
|
137
|
-
| `search_symbol(query)` / `search_code(query)` | Find symbols by name, or search snippet text. |
|
|
138
|
-
| `find_callers` / `find_callees` | Who calls a function/method, and what it calls. |
|
|
139
|
-
| `find_referrers` / `find_imports` / `find_importers` | Where a symbol is used / what a file imports / who imports it. |
|
|
140
|
-
| `impact_analysis(symbol)` | Transitive blast radius for change/test selection. |
|
|
141
|
-
| `explore(question)` | Relevant symbols, a relationship map, and blast radius in one call. |
|
|
142
|
-
| `get_code_snippet(symbol)` / `file_skeleton(file)` | A symbol's source, or a file's symbol outline. |
|
|
143
|
-
|
|
144
|
-
…and more (overrides, interfaces, type users, routes → handlers, circular imports). Call `get_graph_schema()` for the full node/edge model, or `ama --help` for the CLI.
|
|
145
|
-
|
|
146
174
|
## How Ama is built
|
|
147
175
|
|
|
148
176
|
Ama improves itself by **dogfooding**: each change is made by using Ama's own tools on Ama's own source, and is only considered done once Ama can **re-index itself cleanly** — that self-index is the project's built-in regression test. Lessons learned along the way are recorded in [`docs/insights/`](docs/insights/README.md) so they compound over time. See [`docs/SELF_IMPROVEMENT_LOOP.md`](docs/SELF_IMPROVEMENT_LOOP.md) for the workflow and [`AGENTS.md`](AGENTS.md) for contributor and agent conventions.
|
|
@@ -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":"AACA,OAAO,EAAkC,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhF,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C;;;;+EAI+E;AAC/E,SAAS,kBAAkB,CAAC,WAAmB,EAAE,IAAY;IAC3D,OAAO,YAAY,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED;;;;;;8BAM8B;AAC9B,SAAS,WAAW,CAAC,IAAuB,EAAE,WAAmB;IAC/D,IAAI,IAAI,CAAC,IAAI,KAAK,oBAAoB;QAAE,OAAO,SAAS,CAAC;IACzD,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC;QAAE,OAAO,EAAE,CAAC,CAAC,kBAAkB;IACxF,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CACpC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,mBAAmB,IAAI,CAAC,CAAC,IAAI,KAAK,YAAY,CACjE,CAAC;IACF,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IACvB,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,IAAI,QAAQ,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC,CAAC,oDAAoD;IACjF,MAAM,IAAI,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;IACjE,OAAO,CAAC,kBAAkB,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,kGAAkG;AAClG,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC;IACjC,CAAC,YAAY,EAAE,KAAK,CAAC;IACrB,CAAC,aAAa,EAAE,MAAM,CAAC;IACvB,CAAC,YAAY,EAAE,KAAK,CAAC;IACrB,CAAC,eAAe,EAAE,QAAQ,CAAC;IAC3B,CAAC,cAAc,EAAE,OAAO,CAAC;CAC1B,CAAC,CAAC;AAEH,SAAS,WAAW,CAAC,IAAuB,EAAE,IAAY;IACxD,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACpC,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACnC,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;IAC1B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,QAAQ,CAAC,CAAC,SAAS,CAAC,IAAuB;IACzC,IAAI,IAAI,CAAC,IAAI,KAAK,mBAAmB;QAAE,MAAM,IAAI,CAAC;IAClD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,aAAa;QAAE,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED,0FAA0F;AAC1F,SAAS,aAAa,CAAC,GAAsB;IAC3C,OAAO,WAAW,CAAC,GAAG,EAAE,iBAAiB,CAAC,EAAE,IAAI,CAAC;AACnD,CAAC;AAED,4FAA4F;AAC5F,SAAS,iBAAiB,CAAC,MAAc,EAAE,GAAW;IACpD,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IAC7D,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACpF,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AAC9B,CAAC;AAED;;wDAEwD;AACxD,SAAS,UAAU,CACjB,IAAuB,EACvB,GAAW;IAEX,MAAM,KAAK,GAAgB,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAgB,EAAE,CAAC;IAC9B,MAAM,aAAa,GAAG,CAAC,IAAuB,EAAE,EAAE,CAChD,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,EAAE,aAAa,IAAI,EAAE,CAAC,CAAC,MAAM,CAClF,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,CAAC,IAAI,KAAK,mBAAmB,CACjE,CAAC;IACJ,KAAK,MAAM,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,GAAG,CAAC,iBAAiB,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC;QACtD,MAAM,MAAM,GACV,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC,EAAE,IAAI,KAAK,gBAAgB,CAAC;YACtF,IAAI,CAAC;QACP,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,GAAG,GAAG,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC3C,KAAK,MAAM,MAAM,IAAI,IAAI,EAAE,aAAa,IAAI,EAAE,EAAE,CAAC;YAC/C,IAAI,MAAM,CAAC,IAAI,KAAK,oBAAoB;gBAAE,SAAS;YACnD,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC;iBAClC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACX,IAAI,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;gBACrE,GAAG,EAAE,CAAC;aACP,CAAC,CAAC;iBACF,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACvB,IAAI,CAAC,OAAO,EAAE,IAAI;gBAAE,SAAS;YAC7B,MAAM,UAAU,GAAG,MAAM,CAAC,iBAAiB,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC;YAC1D,MAAM,IAAI,GAAG,GAAG,OAAO,CAAC,IAAI,IAAI,iBAAiB,CAAC,WAAW,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YACnG,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,MAAM,CAAC,aAAa,CAAC,GAAG,GAAG,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,GAAG,GAAG,CAAC,EAAE;aACxF,CAAC,CAAC;YACH,IAAI,SAAS,IAAI,UAAU,EAAE,CAAC;gBAC5B,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI,EAAE,OAAO;oBACb,EAAE,EAAE,QAAQ,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,aAAa,EAAE,GAAG,SAAS,IAAI,UAAU,EAAE,EAAE,CAAC;oBACxE,IAAI,EAAE,YAAY;oBAClB,UAAU,EAAE,WAAW;iBACxB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC1B,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAiB;IACpC,QAAQ,EAAE,MAAM;IAChB,UAAU,EAAE,CAAC,OAAO,CAAC;IACrB,OAAO,EAAE,MAAM;IACf,OAAO,EAAE;QACP,iBAAiB,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;QACpC,qBAAqB,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE;QAC5C,gBAAgB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;QAClC,kBAAkB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KACvC;IACD,cAAc,EAAE,WAAW;IAC3B,aAAa,EAAE,UAAU;CAC1B,CAAC"}
|
|
@@ -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":"
|
|
1
|
+
{"version":3,"file":"python.d.ts","sourceRoot":"","sources":["../../../src/analyzers/baseline/python.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAuTlD;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,EAAE,YAWxB,CAAC"}
|