@mka-rainmaker/ama 0.1.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.
Files changed (211) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +149 -0
  3. package/dist/analyzers/baseline/analyzer.d.ts +47 -0
  4. package/dist/analyzers/baseline/analyzer.d.ts.map +1 -0
  5. package/dist/analyzers/baseline/analyzer.js +84 -0
  6. package/dist/analyzers/baseline/analyzer.js.map +1 -0
  7. package/dist/analyzers/baseline/c.d.ts +12 -0
  8. package/dist/analyzers/baseline/c.d.ts.map +1 -0
  9. package/dist/analyzers/baseline/c.js +56 -0
  10. package/dist/analyzers/baseline/c.js.map +1 -0
  11. package/dist/analyzers/baseline/config.d.ts +21 -0
  12. package/dist/analyzers/baseline/config.d.ts.map +1 -0
  13. package/dist/analyzers/baseline/config.js +32 -0
  14. package/dist/analyzers/baseline/config.js.map +1 -0
  15. package/dist/analyzers/baseline/csharp.d.ts +9 -0
  16. package/dist/analyzers/baseline/csharp.d.ts.map +1 -0
  17. package/dist/analyzers/baseline/csharp.js +107 -0
  18. package/dist/analyzers/baseline/csharp.js.map +1 -0
  19. package/dist/analyzers/baseline/go.d.ts +11 -0
  20. package/dist/analyzers/baseline/go.d.ts.map +1 -0
  21. package/dist/analyzers/baseline/go.js +66 -0
  22. package/dist/analyzers/baseline/go.js.map +1 -0
  23. package/dist/analyzers/baseline/java.d.ts +9 -0
  24. package/dist/analyzers/baseline/java.d.ts.map +1 -0
  25. package/dist/analyzers/baseline/java.js +50 -0
  26. package/dist/analyzers/baseline/java.js.map +1 -0
  27. package/dist/analyzers/baseline/javascript.d.ts +10 -0
  28. package/dist/analyzers/baseline/javascript.d.ts.map +1 -0
  29. package/dist/analyzers/baseline/javascript.js +55 -0
  30. package/dist/analyzers/baseline/javascript.js.map +1 -0
  31. package/dist/analyzers/baseline/kotlin.d.ts +11 -0
  32. package/dist/analyzers/baseline/kotlin.d.ts.map +1 -0
  33. package/dist/analyzers/baseline/kotlin.js +67 -0
  34. package/dist/analyzers/baseline/kotlin.js.map +1 -0
  35. package/dist/analyzers/baseline/paths.d.ts +6 -0
  36. package/dist/analyzers/baseline/paths.d.ts.map +1 -0
  37. package/dist/analyzers/baseline/paths.js +17 -0
  38. package/dist/analyzers/baseline/paths.js.map +1 -0
  39. package/dist/analyzers/baseline/php.d.ts +11 -0
  40. package/dist/analyzers/baseline/php.d.ts.map +1 -0
  41. package/dist/analyzers/baseline/php.js +76 -0
  42. package/dist/analyzers/baseline/php.js.map +1 -0
  43. package/dist/analyzers/baseline/python.d.ts +10 -0
  44. package/dist/analyzers/baseline/python.d.ts.map +1 -0
  45. package/dist/analyzers/baseline/python.js +63 -0
  46. package/dist/analyzers/baseline/python.js.map +1 -0
  47. package/dist/analyzers/baseline/rust.d.ts +10 -0
  48. package/dist/analyzers/baseline/rust.d.ts.map +1 -0
  49. package/dist/analyzers/baseline/rust.js +45 -0
  50. package/dist/analyzers/baseline/rust.js.map +1 -0
  51. package/dist/analyzers/baseline/swift.d.ts +11 -0
  52. package/dist/analyzers/baseline/swift.d.ts.map +1 -0
  53. package/dist/analyzers/baseline/swift.js +19 -0
  54. package/dist/analyzers/baseline/swift.js.map +1 -0
  55. package/dist/analyzers/baseline/treesitter.d.ts +11 -0
  56. package/dist/analyzers/baseline/treesitter.d.ts.map +1 -0
  57. package/dist/analyzers/baseline/treesitter.js +87 -0
  58. package/dist/analyzers/baseline/treesitter.js.map +1 -0
  59. package/dist/analyzers/baseline/walk.d.ts +26 -0
  60. package/dist/analyzers/baseline/walk.d.ts.map +1 -0
  61. package/dist/analyzers/baseline/walk.js +76 -0
  62. package/dist/analyzers/baseline/walk.js.map +1 -0
  63. package/dist/analyzers/registry.d.ts +19 -0
  64. package/dist/analyzers/registry.d.ts.map +1 -0
  65. package/dist/analyzers/registry.js +43 -0
  66. package/dist/analyzers/registry.js.map +1 -0
  67. package/dist/analyzers/sfc/analyzer.d.ts +17 -0
  68. package/dist/analyzers/sfc/analyzer.d.ts.map +1 -0
  69. package/dist/analyzers/sfc/analyzer.js +141 -0
  70. package/dist/analyzers/sfc/analyzer.js.map +1 -0
  71. package/dist/analyzers/sidecar/analyzer.d.ts +29 -0
  72. package/dist/analyzers/sidecar/analyzer.d.ts.map +1 -0
  73. package/dist/analyzers/sidecar/analyzer.js +114 -0
  74. package/dist/analyzers/sidecar/analyzer.js.map +1 -0
  75. package/dist/analyzers/sidecar/protocol.d.ts +508 -0
  76. package/dist/analyzers/sidecar/protocol.d.ts.map +1 -0
  77. package/dist/analyzers/sidecar/protocol.js +102 -0
  78. package/dist/analyzers/sidecar/protocol.js.map +1 -0
  79. package/dist/analyzers/types.d.ts +46 -0
  80. package/dist/analyzers/types.d.ts.map +1 -0
  81. package/dist/analyzers/types.js +2 -0
  82. package/dist/analyzers/types.js.map +1 -0
  83. package/dist/analyzers/typescript/analyzer.d.ts +126 -0
  84. package/dist/analyzers/typescript/analyzer.d.ts.map +1 -0
  85. package/dist/analyzers/typescript/analyzer.js +1600 -0
  86. package/dist/analyzers/typescript/analyzer.js.map +1 -0
  87. package/dist/cli/commands/cycles.d.ts +6 -0
  88. package/dist/cli/commands/cycles.d.ts.map +1 -0
  89. package/dist/cli/commands/cycles.js +27 -0
  90. package/dist/cli/commands/cycles.js.map +1 -0
  91. package/dist/cli/commands/files.d.ts +6 -0
  92. package/dist/cli/commands/files.d.ts.map +1 -0
  93. package/dist/cli/commands/files.js +33 -0
  94. package/dist/cli/commands/files.js.map +1 -0
  95. package/dist/cli/commands/impact.d.ts +18 -0
  96. package/dist/cli/commands/impact.d.ts.map +1 -0
  97. package/dist/cli/commands/impact.js +113 -0
  98. package/dist/cli/commands/impact.js.map +1 -0
  99. package/dist/cli/commands/lifecycle.d.ts +5 -0
  100. package/dist/cli/commands/lifecycle.d.ts.map +1 -0
  101. package/dist/cli/commands/lifecycle.js +83 -0
  102. package/dist/cli/commands/lifecycle.js.map +1 -0
  103. package/dist/cli/commands/query.d.ts +31 -0
  104. package/dist/cli/commands/query.d.ts.map +1 -0
  105. package/dist/cli/commands/query.js +187 -0
  106. package/dist/cli/commands/query.js.map +1 -0
  107. package/dist/cli/commands/search.d.ts +21 -0
  108. package/dist/cli/commands/search.d.ts.map +1 -0
  109. package/dist/cli/commands/search.js +160 -0
  110. package/dist/cli/commands/search.js.map +1 -0
  111. package/dist/cli/commands/status.d.ts +6 -0
  112. package/dist/cli/commands/status.d.ts.map +1 -0
  113. package/dist/cli/commands/status.js +63 -0
  114. package/dist/cli/commands/status.js.map +1 -0
  115. package/dist/cli/commands/sync.d.ts +6 -0
  116. package/dist/cli/commands/sync.d.ts.map +1 -0
  117. package/dist/cli/commands/sync.js +57 -0
  118. package/dist/cli/commands/sync.js.map +1 -0
  119. package/dist/cli/emit.d.ts +9 -0
  120. package/dist/cli/emit.d.ts.map +1 -0
  121. package/dist/cli/emit.js +10 -0
  122. package/dist/cli/emit.js.map +1 -0
  123. package/dist/cli/index.d.ts +37 -0
  124. package/dist/cli/index.d.ts.map +1 -0
  125. package/dist/cli/index.js +128 -0
  126. package/dist/cli/index.js.map +1 -0
  127. package/dist/cli/paths.d.ts +7 -0
  128. package/dist/cli/paths.d.ts.map +1 -0
  129. package/dist/cli/paths.js +10 -0
  130. package/dist/cli/paths.js.map +1 -0
  131. package/dist/cli/query-runner.d.ts +13 -0
  132. package/dist/cli/query-runner.d.ts.map +1 -0
  133. package/dist/cli/query-runner.js +33 -0
  134. package/dist/cli/query-runner.js.map +1 -0
  135. package/dist/graph/dispatch.d.ts +17 -0
  136. package/dist/graph/dispatch.d.ts.map +1 -0
  137. package/dist/graph/dispatch.js +82 -0
  138. package/dist/graph/dispatch.js.map +1 -0
  139. package/dist/graph/id.d.ts +19 -0
  140. package/dist/graph/id.d.ts.map +1 -0
  141. package/dist/graph/id.js +17 -0
  142. package/dist/graph/id.js.map +1 -0
  143. package/dist/graph/index.d.ts +6 -0
  144. package/dist/graph/index.d.ts.map +1 -0
  145. package/dist/graph/index.js +4 -0
  146. package/dist/graph/index.js.map +1 -0
  147. package/dist/graph/types.d.ts +71 -0
  148. package/dist/graph/types.d.ts.map +1 -0
  149. package/dist/graph/types.js +52 -0
  150. package/dist/graph/types.js.map +1 -0
  151. package/dist/indexer/debouncer.d.ts +32 -0
  152. package/dist/indexer/debouncer.d.ts.map +1 -0
  153. package/dist/indexer/debouncer.js +81 -0
  154. package/dist/indexer/debouncer.js.map +1 -0
  155. package/dist/indexer/ignore.d.ts +55 -0
  156. package/dist/indexer/ignore.d.ts.map +1 -0
  157. package/dist/indexer/ignore.js +170 -0
  158. package/dist/indexer/ignore.js.map +1 -0
  159. package/dist/indexer/indexer.d.ts +112 -0
  160. package/dist/indexer/indexer.d.ts.map +1 -0
  161. package/dist/indexer/indexer.js +392 -0
  162. package/dist/indexer/indexer.js.map +1 -0
  163. package/dist/indexer/watcher.d.ts +50 -0
  164. package/dist/indexer/watcher.d.ts.map +1 -0
  165. package/dist/indexer/watcher.js +86 -0
  166. package/dist/indexer/watcher.js.map +1 -0
  167. package/dist/mcp/build-info.d.ts +16 -0
  168. package/dist/mcp/build-info.d.ts.map +1 -0
  169. package/dist/mcp/build-info.js +54 -0
  170. package/dist/mcp/build-info.js.map +1 -0
  171. package/dist/mcp/http.d.ts +18 -0
  172. package/dist/mcp/http.d.ts.map +1 -0
  173. package/dist/mcp/http.js +145 -0
  174. package/dist/mcp/http.js.map +1 -0
  175. package/dist/mcp/server.d.ts +22 -0
  176. package/dist/mcp/server.d.ts.map +1 -0
  177. package/dist/mcp/server.js +401 -0
  178. package/dist/mcp/server.js.map +1 -0
  179. package/dist/mcp/session.d.ts +155 -0
  180. package/dist/mcp/session.d.ts.map +1 -0
  181. package/dist/mcp/session.js +319 -0
  182. package/dist/mcp/session.js.map +1 -0
  183. package/dist/query/service.d.ts +329 -0
  184. package/dist/query/service.d.ts.map +1 -0
  185. package/dist/query/service.js +959 -0
  186. package/dist/query/service.js.map +1 -0
  187. package/dist/runtime/entrypoint.d.ts +11 -0
  188. package/dist/runtime/entrypoint.d.ts.map +1 -0
  189. package/dist/runtime/entrypoint.js +22 -0
  190. package/dist/runtime/entrypoint.js.map +1 -0
  191. package/dist/runtime/quiet-sqlite-warning.d.ts +14 -0
  192. package/dist/runtime/quiet-sqlite-warning.d.ts.map +1 -0
  193. package/dist/runtime/quiet-sqlite-warning.js +26 -0
  194. package/dist/runtime/quiet-sqlite-warning.js.map +1 -0
  195. package/dist/runtime/wasm-tier.d.ts +2 -0
  196. package/dist/runtime/wasm-tier.d.ts.map +1 -0
  197. package/dist/runtime/wasm-tier.js +54 -0
  198. package/dist/runtime/wasm-tier.js.map +1 -0
  199. package/dist/store/memory.d.ts +54 -0
  200. package/dist/store/memory.d.ts.map +1 -0
  201. package/dist/store/memory.js +210 -0
  202. package/dist/store/memory.js.map +1 -0
  203. package/dist/store/sqlite.d.ts +38 -0
  204. package/dist/store/sqlite.d.ts.map +1 -0
  205. package/dist/store/sqlite.js +298 -0
  206. package/dist/store/sqlite.js.map +1 -0
  207. package/dist/store/types.d.ts +76 -0
  208. package/dist/store/types.d.ts.map +1 -0
  209. package/dist/store/types.js +2 -0
  210. package/dist/store/types.js.map +1 -0
  211. package/package.json +59 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mykhaylo Katruk
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,149 @@
1
+ # Ama 🐶
2
+
3
+ **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 can answer *"who calls this?"*, *"what breaks if I change this?"*, and *"show me this function and its callers"* in a **single tool call** instead of dozens of file reads.
4
+
5
+ Named after a puppy: small, eager, and a little smarter every day.
6
+
7
+ > Status: **0.1.** Deep TypeScript analysis plus syntactic baseline coverage for 13 more languages, 27 MCP tools, an `ama` CLI, and persistent incremental indexing — all able to index Ama's own source cleanly as the built-in regression test. Deep-tier .NET/Java analyzers (behind the sidecar protocol) are next.
8
+
9
+ ## Why Ama
10
+
11
+ 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
+
13
+ - **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 still gets parsed for structure, so the whole repo is navigable from day one.
15
+
16
+ Every answer reports **which tier produced it**, so partial coverage never quietly masquerades as complete.
17
+
18
+ And because it's built for agents:
19
+
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.
22
+
23
+ ## Install
24
+
25
+ > Requires **Node.js 24+**.
26
+
27
+ Ama runs as a local MCP server your coding agent launches over stdio. Install it once, then point your agent at `ama mcp`:
28
+
29
+ ```bash
30
+ npm install -g @mka-rainmaker/ama
31
+ ```
32
+
33
+ (Or skip the global install and use `npx -y @mka-rainmaker/ama mcp` as the command below.)
34
+
35
+ ### Configure your coding agent
36
+
37
+ Every MCP client spawns the same stdio command — `ama mcp` — only the config location differs.
38
+
39
+ **Claude Code** — add it with one command:
40
+
41
+ ```bash
42
+ claude mcp add ama -- ama mcp
43
+ ```
44
+
45
+ …or add it to a project `.mcp.json`:
46
+
47
+ ```json
48
+ { "mcpServers": { "ama": { "command": "ama", "args": ["mcp"] } } }
49
+ ```
50
+
51
+ **Cursor** — `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (global):
52
+
53
+ ```json
54
+ { "mcpServers": { "ama": { "command": "ama", "args": ["mcp"] } } }
55
+ ```
56
+
57
+ **Windsurf** — `~/.codeium/windsurf/mcp_config.json`:
58
+
59
+ ```json
60
+ { "mcpServers": { "ama": { "command": "ama", "args": ["mcp"] } } }
61
+ ```
62
+
63
+ **Any other MCP client** — spawn `ama mcp` over stdio. If you didn't install globally, run it via `npx`:
64
+
65
+ ```json
66
+ { "mcpServers": { "ama": { "command": "npx", "args": ["-y", "@mka-rainmaker/ama", "mcp"] } } }
67
+ ```
68
+
69
+ ### Quick start
70
+
71
+ Once connected, point Ama at a repo and start asking graph questions:
72
+
73
+ 1. **`index_repository("/path/to/your/project")`** — builds the graph (run this first).
74
+ 2. **`search_symbol`**, **`find_callers`**, **`find_callees`**, **`get_code_snippet`**, **`impact_analysis`**, … — query it.
75
+
76
+ Ama re-indexes changed files automatically while connected. Call `index_status()` to see what's indexed and the per-language coverage + tier.
77
+
78
+ ### CLI
79
+
80
+ 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`):
81
+
82
+ ```bash
83
+ ama --help # list commands
84
+ ama mcp # run the MCP server over stdio (what coding agents spawn)
85
+ ```
86
+
87
+ ## What's in 0.1
88
+
89
+ - **Deep TypeScript analysis** via the TypeScript Compiler API — types, overloads, generics, imports/re-exports, inheritance, interface dispatch, cross-file binding, and call graphs.
90
+ - **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.
91
+ - **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.
92
+ - **Persistent indexing** (SQLite + full-text search) with **incremental re-indexing**: edits are picked up automatically while connected.
93
+ - **Cross-project queries** — index several repos in one session and target any of them by path.
94
+ - **An `ama` CLI** for one-shot queries and scripting.
95
+
96
+ ## Next
97
+
98
+ - **Deep-tier .NET (Roslyn) and Java analyzers** behind the sidecar protocol (the protocol + harness ship in 0.1; the analyzers need their language toolchains).
99
+ - More baseline languages and richer framework awareness.
100
+
101
+ ## How it works
102
+
103
+ ```
104
+ source files ──▶ analyzer (deep | baseline) ──▶ graph (nodes + edges) ──▶ store ──▶ query ──▶ MCP tools
105
+ ```
106
+
107
+ - **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.
108
+ - **Analyzers** — pluggable per language, each declaring its tier (`deep` or `baseline`). The TypeScript deep analyzer is the reference implementation.
109
+ - **Store** — in-memory, or SQLite with full-text search for persistence.
110
+ - **Query service** — search, call-graph traversal, code snippets, and impact analysis.
111
+ - **MCP server** — exposes the query surface over stdio.
112
+
113
+ ## MCP tools
114
+
115
+ | Tool | What it does |
116
+ |---|---|
117
+ | `index_repository(path)` | Build the graph for a directory or project. Run first. |
118
+ | `index_status()` | What's indexed: node/edge counts, per-language coverage + tier. |
119
+ | `search_symbol(query)` / `search_code(query)` | Find symbols by name, or search snippet text. |
120
+ | `find_callers` / `find_callees` | Who calls a function/method, and what it calls. |
121
+ | `find_referrers` / `find_imports` / `find_importers` | Where a symbol is used / what a file imports / who imports it. |
122
+ | `impact_analysis(symbol)` | Transitive blast radius for change/test selection. |
123
+ | `explore(question)` | Relevant symbols, a relationship map, and blast radius in one call. |
124
+ | `get_code_snippet(symbol)` / `file_skeleton(file)` | A symbol's source, or a file's symbol outline. |
125
+
126
+ …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.
127
+
128
+ ## How Ama is built
129
+
130
+ 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.
131
+
132
+ ## Development
133
+
134
+ > Requires **Node.js 24+**.
135
+
136
+ ```bash
137
+ git clone https://github.com/mka-rainmaker/ama.git
138
+ cd ama
139
+ npm install
140
+ npm run build # compile TypeScript to dist/
141
+ npm test # run the test suite (vitest)
142
+ npm run typecheck # type-check without emitting
143
+ ```
144
+
145
+ The backlog is tracked with [beads](https://github.com/steveyegge/beads) (`bd ready` to see what's actionable).
146
+
147
+ ## License
148
+
149
+ [MIT](LICENSE) © 2026 Mykhaylo Katruk
@@ -0,0 +1,47 @@
1
+ import type Parser from "web-tree-sitter";
2
+ import type { AnalysisResult, Analyzer } from "../types.js";
3
+ import { type SymbolRule } from "./walk.js";
4
+ export type { SymbolRule };
5
+ /**
6
+ * Describes a language for the {@link BaselineAnalyzer}: which extensions it
7
+ * owns, which bundled tree-sitter grammar to parse with, and which CST node
8
+ * types are symbols. Deep semantics (calls, types) are out of scope — baseline
9
+ * is syntactic breadth: files and the symbols they define.
10
+ */
11
+ export interface LanguageSpec {
12
+ readonly language: string;
13
+ readonly extensions: readonly string[];
14
+ /** Key into the bundled grammar registry (see {@link parse}). */
15
+ readonly grammar: string;
16
+ /** CST node type → how to emit a symbol for it. */
17
+ readonly symbols: Readonly<Record<string, SymbolRule>>;
18
+ /**
19
+ * Optional import resolver: given an import CST node, the importing file's
20
+ * repo-relative path, and the index root, return each imported module as an
21
+ * ordered list of candidate repo-relative file paths — the analyzer emits a
22
+ * File→File `Imports` edge to the first candidate that exists on disk. Returns
23
+ * `undefined` for a non-import node, `[]` for an unresolvable (stdlib/third-party)
24
+ * import. `root` lets a config-aware language (Go's `go.mod`) resolve a
25
+ * module-qualified path; path-based languages can ignore it. (ama-8nr, ama-9yu)
26
+ */
27
+ readonly resolveImports?: (node: Parser.SyntaxNode, importerRel: string, root: string) => string[][] | undefined;
28
+ }
29
+ /**
30
+ * A language-agnostic, syntactic (tier `baseline`) analyzer driven by a
31
+ * {@link LanguageSpec}. It parses each file with tree-sitter and walks the CST,
32
+ * emitting a File node plus a node for every symbol the spec recognizes, with a
33
+ * `Defines` edge from the enclosing symbol (or the file) and a dotted
34
+ * qualified name for nested symbols. One instance handles one language.
35
+ */
36
+ export declare class BaselineAnalyzer implements Analyzer {
37
+ private readonly spec;
38
+ readonly tier = "baseline";
39
+ readonly language: string;
40
+ readonly extensions: readonly string[];
41
+ constructor(spec: LanguageSpec);
42
+ analyze(root: string, files: string[]): Promise<AnalysisResult>;
43
+ /** Walk the CST for import statements and emit a File→File `Imports` edge to
44
+ * each imported module that resolves (by path) to a file on disk. (ama-8nr) */
45
+ private collectImports;
46
+ }
47
+ //# sourceMappingURL=analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../../../src/analyzers/baseline/analyzer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,MAAM,iBAAiB,CAAC;AAE1C,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;CAC7B;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;IA8CrE;oFACgF;IAChF,OAAO,CAAC,cAAc;CAkBvB"}
@@ -0,0 +1,84 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { fileId } from "../../graph/index.js";
4
+ import { parse } from "./treesitter.js";
5
+ import { walkSymbols } from "./walk.js";
6
+ /**
7
+ * A language-agnostic, syntactic (tier `baseline`) analyzer driven by a
8
+ * {@link LanguageSpec}. It parses each file with tree-sitter and walks the CST,
9
+ * emitting a File node plus a node for every symbol the spec recognizes, with a
10
+ * `Defines` edge from the enclosing symbol (or the file) and a dotted
11
+ * qualified name for nested symbols. One instance handles one language.
12
+ */
13
+ export class BaselineAnalyzer {
14
+ spec;
15
+ tier = "baseline";
16
+ language;
17
+ extensions;
18
+ constructor(spec) {
19
+ this.spec = spec;
20
+ this.language = spec.language;
21
+ this.extensions = spec.extensions;
22
+ }
23
+ async analyze(root, files) {
24
+ const nodes = [];
25
+ const edges = [];
26
+ for (const rel of files) {
27
+ // Per-file isolation: a single unreadable or unparseable file must not lose
28
+ // the whole language's batch — finer than the indexer's per-analyzer catch
29
+ // (ama-m8k.9). Build into local arrays and merge only on success, so a
30
+ // mid-walk throw leaves no partial nodes behind. (ama-eww)
31
+ try {
32
+ const code = fs.readFileSync(path.join(root, rel), "utf8");
33
+ const tree = await parse(this.spec.grammar, code);
34
+ // A web-tree-sitter Tree holds WASM memory; free it once walked so a large
35
+ // index doesn't accumulate one tree per file. `finally` covers a throw in
36
+ // walk. The extracted GraphNodes are plain copies, valid after delete. (ama-5o1)
37
+ try {
38
+ const id = fileId(rel);
39
+ const fileNodes = [
40
+ {
41
+ id,
42
+ kind: "File",
43
+ name: path.basename(rel),
44
+ file: rel,
45
+ qualifiedName: "",
46
+ tier: "baseline",
47
+ range: { startLine: 1, endLine: tree.rootNode.endPosition.row + 1 },
48
+ },
49
+ ];
50
+ const fileEdges = [];
51
+ walkSymbols(tree.rootNode, this.spec.symbols, rel, id, "", fileNodes, fileEdges);
52
+ if (this.spec.resolveImports)
53
+ this.collectImports(tree.rootNode, rel, root, id, fileEdges);
54
+ nodes.push(...fileNodes);
55
+ edges.push(...fileEdges);
56
+ }
57
+ finally {
58
+ tree.delete();
59
+ }
60
+ }
61
+ catch (err) {
62
+ console.error(`[ama] ${this.spec.language} analyzer failed on ${rel}; skipping it. ` +
63
+ `${err instanceof Error ? err.message : String(err)}`);
64
+ }
65
+ }
66
+ return { nodes, edges };
67
+ }
68
+ /** Walk the CST for import statements and emit a File→File `Imports` edge to
69
+ * each imported module that resolves (by path) to a file on disk. (ama-8nr) */
70
+ collectImports(node, importerRel, root, fileNodeId, edges) {
71
+ const groups = this.spec.resolveImports?.(node, importerRel, root);
72
+ if (groups) {
73
+ for (const candidates of groups) {
74
+ const target = candidates.find((c) => fs.existsSync(path.join(root, c)));
75
+ if (target)
76
+ edges.push({ from: fileNodeId, to: fileId(target), kind: "Imports" });
77
+ }
78
+ }
79
+ for (const child of node.namedChildren) {
80
+ this.collectImports(child, importerRel, root, fileNodeId, edges);
81
+ }
82
+ }
83
+ }
84
+ //# sourceMappingURL=analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../../../src/analyzers/baseline/analyzer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { LanguageSpec } from "./analyzer.js";
2
+ /**
3
+ * Baseline (syntactic) specs for C and C++. Both share a grammar family: structs,
4
+ * unions, enums, and typedefs carry a `name` field, while a `function_definition`
5
+ * nests its name in a `declarator` chain — the analyzer's `symbolName` drills that
6
+ * for us. C++ adds classes and namespaces; a method defined inline is a
7
+ * `function_definition` inside the class body, so it surfaces as a Function
8
+ * qualified under its class (e.g. `Sample.square`). (ama-s8q.9)
9
+ */
10
+ export declare const cSpec: LanguageSpec;
11
+ export declare const cppSpec: LanguageSpec;
12
+ //# sourceMappingURL=c.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"c.d.ts","sourceRoot":"","sources":["../../../src/analyzers/baseline/c.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAiBlD;;;;;;;GAOG;AACH,eAAO,MAAM,KAAK,EAAE,YAYnB,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,YAerB,CAAC"}
@@ -0,0 +1,56 @@
1
+ import * as path from "node:path";
2
+ /** Resolve a C/C++ `#include "foo.h"` to its header file. The quoted form is
3
+ * relative to the including file's directory (and resolved on disk, like JS/Python
4
+ * relative imports), so it's single-file-reindex-safe; the angle form `#include <…>`
5
+ * is a system/include-path header (external) and resolves to nothing. (ama-ftg) */
6
+ function includeImports(node, importerRel) {
7
+ if (node.type !== "preproc_include")
8
+ return undefined;
9
+ const lit = node.namedChildren.find((c) => c.type === "string_literal");
10
+ if (!lit)
11
+ return []; // `#include <…>` (system_lib_string) — external
12
+ const content = lit.namedChildren.find((c) => c.type === "string_content");
13
+ const includePath = (content?.text ?? lit.text.replace(/^"|"$/g, "")).trim();
14
+ if (!includePath)
15
+ return [];
16
+ // join() normalizes `..`, so `#include "../inc/x.h"` from `src/a.c` → `inc/x.h`.
17
+ return [[path.posix.join(path.posix.dirname(importerRel), includePath)]];
18
+ }
19
+ /**
20
+ * Baseline (syntactic) specs for C and C++. Both share a grammar family: structs,
21
+ * unions, enums, and typedefs carry a `name` field, while a `function_definition`
22
+ * nests its name in a `declarator` chain — the analyzer's `symbolName` drills that
23
+ * for us. C++ adds classes and namespaces; a method defined inline is a
24
+ * `function_definition` inside the class body, so it surfaces as a Function
25
+ * qualified under its class (e.g. `Sample.square`). (ama-s8q.9)
26
+ */
27
+ export const cSpec = {
28
+ language: "c",
29
+ extensions: [".c"],
30
+ grammar: "c",
31
+ symbols: {
32
+ function_definition: { kind: "Function" },
33
+ struct_specifier: { kind: "Class" },
34
+ union_specifier: { kind: "Class" },
35
+ enum_specifier: { kind: "Enum" },
36
+ type_definition: { kind: "TypeAlias" },
37
+ },
38
+ resolveImports: includeImports,
39
+ };
40
+ export const cppSpec = {
41
+ language: "cpp",
42
+ // `.h` routes here: the C++ grammar is a superset, so it parses C headers too.
43
+ extensions: [".cpp", ".cc", ".cxx", ".hpp", ".hh", ".h"],
44
+ grammar: "cpp",
45
+ symbols: {
46
+ function_definition: { kind: "Function" },
47
+ struct_specifier: { kind: "Class" },
48
+ union_specifier: { kind: "Class" },
49
+ enum_specifier: { kind: "Enum" },
50
+ type_definition: { kind: "TypeAlias" },
51
+ class_specifier: { kind: "Class" },
52
+ namespace_definition: { kind: "Module" },
53
+ },
54
+ resolveImports: includeImports,
55
+ };
56
+ //# sourceMappingURL=c.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"c.js","sourceRoot":"","sources":["../../../src/analyzers/baseline/c.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAIlC;;;oFAGoF;AACpF,SAAS,cAAc,CAAC,IAAuB,EAAE,WAAmB;IAClE,IAAI,IAAI,CAAC,IAAI,KAAK,iBAAiB;QAAE,OAAO,SAAS,CAAC;IACtD,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,gBAAgB,CAAC,CAAC;IACxE,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC,CAAC,gDAAgD;IACrE,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,gBAAgB,CAAC,CAAC;IAC3E,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7E,IAAI,CAAC,WAAW;QAAE,OAAO,EAAE,CAAC;IAC5B,iFAAiF;IACjF,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,KAAK,GAAiB;IACjC,QAAQ,EAAE,GAAG;IACb,UAAU,EAAE,CAAC,IAAI,CAAC;IAClB,OAAO,EAAE,GAAG;IACZ,OAAO,EAAE;QACP,mBAAmB,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE;QACzC,gBAAgB,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;QACnC,eAAe,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;QAClC,cAAc,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;QAChC,eAAe,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE;KACvC;IACD,cAAc,EAAE,cAAc;CAC/B,CAAC;AAEF,MAAM,CAAC,MAAM,OAAO,GAAiB;IACnC,QAAQ,EAAE,KAAK;IACf,+EAA+E;IAC/E,UAAU,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC;IACxD,OAAO,EAAE,KAAK;IACd,OAAO,EAAE;QACP,mBAAmB,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE;QACzC,gBAAgB,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;QACnC,eAAe,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;QAClC,cAAc,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;QAChC,eAAe,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE;QACtC,eAAe,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;QAClC,oBAAoB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KACzC;IACD,cAAc,EAAE,cAAc;CAC/B,CAAC"}
@@ -0,0 +1,21 @@
1
+ /** The repo-relative parent directory of a repo-relative path, with the repo root as
2
+ * `""` (not `"."`). */
3
+ export declare function parentDir(rel: string): string;
4
+ /**
5
+ * The nearest project-config file at or above `dirRel` (walking up to the index root),
6
+ * parsed by `read` into a value, paired with the repo-relative directory it was found in
7
+ * — so a baseline analyzer resolves imports whether the index root *is* the package or
8
+ * merely contains it (a monorepo / Ama's own fixtures). `read(absDir)` returns the parsed
9
+ * config for that directory or `undefined` if there's none there. Results (including
10
+ * "none found") are memoized in `cache` per absolute directory, so a package isn't
11
+ * re-walked once per import. Shared by Go (`go.mod`), PHP (`composer.json`), and C#
12
+ * (`.csproj`). (ama-9yu, ama-x96, ama-66z)
13
+ */
14
+ export declare function nearestConfig<T>(root: string, dirRel: string, read: (absDir: string) => T | undefined, cache: Map<string, {
15
+ dir: string;
16
+ value: T;
17
+ } | null>): {
18
+ dir: string;
19
+ value: T;
20
+ } | null;
21
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/analyzers/baseline/config.ts"],"names":[],"mappings":"AAEA;wBACwB;AACxB,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG7C;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAC7B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,CAAC,GAAG,SAAS,EACvC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GAAG,IAAI,CAAC,GACnD;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GAAG,IAAI,CAWlC"}
@@ -0,0 +1,32 @@
1
+ import * as path from "node:path";
2
+ /** The repo-relative parent directory of a repo-relative path, with the repo root as
3
+ * `""` (not `"."`). */
4
+ export function parentDir(rel) {
5
+ const p = path.posix.dirname(rel);
6
+ return p === "." ? "" : p;
7
+ }
8
+ /**
9
+ * The nearest project-config file at or above `dirRel` (walking up to the index root),
10
+ * parsed by `read` into a value, paired with the repo-relative directory it was found in
11
+ * — so a baseline analyzer resolves imports whether the index root *is* the package or
12
+ * merely contains it (a monorepo / Ama's own fixtures). `read(absDir)` returns the parsed
13
+ * config for that directory or `undefined` if there's none there. Results (including
14
+ * "none found") are memoized in `cache` per absolute directory, so a package isn't
15
+ * re-walked once per import. Shared by Go (`go.mod`), PHP (`composer.json`), and C#
16
+ * (`.csproj`). (ama-9yu, ama-x96, ama-66z)
17
+ */
18
+ export function nearestConfig(root, dirRel, read, cache) {
19
+ const absDir = path.join(root, dirRel);
20
+ const cached = cache.get(absDir);
21
+ if (cached !== undefined)
22
+ return cached;
23
+ let result = null;
24
+ const value = read(absDir);
25
+ if (value !== undefined)
26
+ result = { dir: dirRel, value };
27
+ else if (dirRel !== "" && dirRel !== ".")
28
+ result = nearestConfig(root, parentDir(dirRel), read, cache);
29
+ cache.set(absDir, result);
30
+ return result;
31
+ }
32
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/analyzers/baseline/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC;wBACwB;AACxB,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAY,EACZ,MAAc,EACd,IAAuC,EACvC,KAAoD;IAEpD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACxC,IAAI,MAAM,GAAqC,IAAI,CAAC;IACpD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3B,IAAI,KAAK,KAAK,SAAS;QAAE,MAAM,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;SACpD,IAAI,MAAM,KAAK,EAAE,IAAI,MAAM,KAAK,GAAG;QACtC,MAAM,GAAG,aAAa,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IAC/D,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1B,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { LanguageSpec } from "./analyzer.js";
2
+ /**
3
+ * Baseline (syntactic) spec for C#. Like Java, every kind has its own CST node
4
+ * type. Structs and records are value/data types with members, mapped to Class
5
+ * (the graph has no dedicated struct/record kind); methods nest under their
6
+ * type's body (e.g. `Sample.Square`).
7
+ */
8
+ export declare const csharpSpec: LanguageSpec;
9
+ //# sourceMappingURL=csharp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csharp.d.ts","sourceRoot":"","sources":["../../../src/analyzers/baseline/csharp.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AA2FlD;;;;;GAKG;AACH,eAAO,MAAM,UAAU,EAAE,YAaxB,CAAC"}
@@ -0,0 +1,107 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { nearestConfig, parentDir } from "./config.js";
4
+ import { ancestorDirs } from "./paths.js";
5
+ /** Cache for the nearest `.csproj`'s root namespace, by importer directory. */
6
+ const csprojCache = new Map();
7
+ /** The C# root namespace declared by a `.csproj` in `absDir` — its `<RootNamespace>`, or
8
+ * (the C# default) the project file's base name. Undefined when `absDir` holds no
9
+ * `.csproj`, so the walk-up continues. (ama-66z) */
10
+ function readCsprojRootNamespace(absDir) {
11
+ let entries;
12
+ try {
13
+ entries = fs.readdirSync(absDir, { withFileTypes: true });
14
+ }
15
+ catch {
16
+ return undefined;
17
+ }
18
+ const proj = entries.find((e) => e.isFile() && e.name.endsWith(".csproj"));
19
+ if (!proj)
20
+ return undefined;
21
+ try {
22
+ const content = fs.readFileSync(path.join(absDir, proj.name), "utf8");
23
+ return (content.match(/<RootNamespace>\s*([^<\s]+)\s*<\/RootNamespace>/)?.[1] ??
24
+ proj.name.replace(/\.csproj$/i, ""));
25
+ }
26
+ catch {
27
+ return proj.name.replace(/\.csproj$/i, ""); // unreadable body — default to the file name
28
+ }
29
+ }
30
+ /** The `.cs` files directly in repo-relative `rel` (excluding the importer), one
31
+ * File→File candidate group each — or undefined if `rel` isn't a directory or holds no
32
+ * `.cs` files. */
33
+ function csFilesIn(root, rel, importerRel) {
34
+ let entries;
35
+ try {
36
+ entries = fs.readdirSync(path.join(root, rel), { withFileTypes: true });
37
+ }
38
+ catch {
39
+ return undefined; // not a directory on disk
40
+ }
41
+ const files = entries
42
+ .filter((e) => e.isFile() && e.name.endsWith(".cs"))
43
+ .map((e) => (rel ? `${rel}/${e.name}` : e.name))
44
+ .filter((f) => f !== importerRel);
45
+ return files.length > 0 ? files.map((f) => [f]) : undefined;
46
+ }
47
+ /** Resolve a C# `using A.B.C;` to the source files of that namespace. C# has no 1:1
48
+ * namespace→file mapping: a namespace is a *set* of files, conventionally a directory,
49
+ * so a `using` links to every `.cs` file in the matching directory — the "package =
50
+ * directory" shape Go has. Two strategies, precise first: (1) if the namespace is under
51
+ * the nearest `.csproj`'s root namespace (`<RootNamespace>`, else the project file
52
+ * name), map it *exactly* to that project's directory tree — avoiding a coincidental
53
+ * match at a closer ancestor. (2) Otherwise (a namespace from another project, or no
54
+ * `.csproj`), ancestor-scan from the importer's own directory upward, trying
55
+ * progressively shorter suffixes of the dotted name — longest (most specific) first —
56
+ * and take the first directory holding `.cs` files; this favors recall. `using Alias =
57
+ * …` and framework namespaces resolve to nothing. (ama-7e3, ama-66z) */
58
+ function csharpImports(node, importerRel, root) {
59
+ if (node.type !== "using_directive")
60
+ return undefined;
61
+ if (node.namedChildren.some((c) => c.type === "name_equals"))
62
+ return []; // `using Alias = …;`
63
+ const name = node.namedChildren.find((c) => c.type === "qualified_name" || c.type === "identifier");
64
+ if (!name)
65
+ return [];
66
+ // (1) Precise: a namespace under this project's root namespace maps to an exact dir.
67
+ const proj = nearestConfig(root, parentDir(importerRel), readCsprojRootNamespace, csprojCache);
68
+ if (proj && (name.text === proj.value || name.text.startsWith(`${proj.value}.`))) {
69
+ const sub = name.text === proj.value ? "" : name.text.slice(proj.value.length + 1);
70
+ const exact = [proj.dir, sub.replace(/\./g, "/")].filter(Boolean).join("/");
71
+ const files = csFilesIn(root, exact, importerRel);
72
+ if (files)
73
+ return files;
74
+ }
75
+ // (2) Heuristic fallback: ancestor-scan + progressively shorter suffixes (recall).
76
+ const segments = name.text.split(".");
77
+ for (const ancestor of ancestorDirs(importerRel)) {
78
+ for (let len = segments.length; len >= 1; len--) {
79
+ const rel = [ancestor, ...segments.slice(segments.length - len)].filter(Boolean).join("/");
80
+ const files = csFilesIn(root, rel, importerRel);
81
+ if (files)
82
+ return files;
83
+ }
84
+ }
85
+ return []; // a framework/NuGet namespace, or none on disk
86
+ }
87
+ /**
88
+ * Baseline (syntactic) spec for C#. Like Java, every kind has its own CST node
89
+ * type. Structs and records are value/data types with members, mapped to Class
90
+ * (the graph has no dedicated struct/record kind); methods nest under their
91
+ * type's body (e.g. `Sample.Square`).
92
+ */
93
+ export const csharpSpec = {
94
+ language: "csharp",
95
+ extensions: [".cs"],
96
+ grammar: "csharp",
97
+ symbols: {
98
+ class_declaration: { kind: "Class" },
99
+ interface_declaration: { kind: "Interface" },
100
+ struct_declaration: { kind: "Class" },
101
+ record_declaration: { kind: "Class" },
102
+ enum_declaration: { kind: "Enum" },
103
+ method_declaration: { kind: "Method" },
104
+ },
105
+ resolveImports: csharpImports,
106
+ };
107
+ //# sourceMappingURL=csharp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csharp.js","sourceRoot":"","sources":["../../../src/analyzers/baseline/csharp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { LanguageSpec } from "./analyzer.js";
2
+ /**
3
+ * Baseline (syntactic) spec for Go. Go declares named types with a single
4
+ * `type_spec` node regardless of whether the body is a struct, interface, or
5
+ * alias — so it uses {@link SymbolRule.kindByChild} to refine: a `struct_type`
6
+ * child → Class, an `interface_type` child → Interface, else a TypeAlias.
7
+ * Methods are top-level `method_declaration`s (the receiver isn't a container),
8
+ * so they surface as Methods named for the function, not qualified by the type.
9
+ */
10
+ export declare const goSpec: LanguageSpec;
11
+ //# sourceMappingURL=go.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"go.d.ts","sourceRoot":"","sources":["../../../src/analyzers/baseline/go.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AA6ClD;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM,EAAE,YAapB,CAAC"}