seer-mcp 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 (371) hide show
  1. package/.vscode/settings.json +3 -0
  2. package/LICENSE +176 -0
  3. package/README.md +272 -0
  4. package/README_dev.md +199 -0
  5. package/dist/bundle/ci.d.ts +47 -0
  6. package/dist/bundle/ci.d.ts.map +1 -0
  7. package/dist/bundle/ci.js +113 -0
  8. package/dist/bundle/ci.js.map +1 -0
  9. package/dist/bundle/contract.d.ts +111 -0
  10. package/dist/bundle/contract.d.ts.map +1 -0
  11. package/dist/bundle/contract.js +352 -0
  12. package/dist/bundle/contract.js.map +1 -0
  13. package/dist/bundle/export.d.ts +36 -0
  14. package/dist/bundle/export.d.ts.map +1 -0
  15. package/dist/bundle/export.js +152 -0
  16. package/dist/bundle/export.js.map +1 -0
  17. package/dist/bundle/external.d.ts +66 -0
  18. package/dist/bundle/external.d.ts.map +1 -0
  19. package/dist/bundle/external.js +238 -0
  20. package/dist/bundle/external.js.map +1 -0
  21. package/dist/bundle/format.d.ts +94 -0
  22. package/dist/bundle/format.d.ts.map +1 -0
  23. package/dist/bundle/format.js +42 -0
  24. package/dist/bundle/format.js.map +1 -0
  25. package/dist/bundle/import.d.ts +49 -0
  26. package/dist/bundle/import.d.ts.map +1 -0
  27. package/dist/bundle/import.js +116 -0
  28. package/dist/bundle/import.js.map +1 -0
  29. package/dist/cli/index.d.ts +3 -0
  30. package/dist/cli/index.d.ts.map +1 -0
  31. package/dist/cli/index.js +1402 -0
  32. package/dist/cli/index.js.map +1 -0
  33. package/dist/cli/init.d.ts +48 -0
  34. package/dist/cli/init.d.ts.map +1 -0
  35. package/dist/cli/init.js +284 -0
  36. package/dist/cli/init.js.map +1 -0
  37. package/dist/db/schema.d.ts +3 -0
  38. package/dist/db/schema.d.ts.map +1 -0
  39. package/dist/db/schema.js +616 -0
  40. package/dist/db/schema.js.map +1 -0
  41. package/dist/db/store.d.ts +1011 -0
  42. package/dist/db/store.d.ts.map +1 -0
  43. package/dist/db/store.js +3888 -0
  44. package/dist/db/store.js.map +1 -0
  45. package/dist/graph/pagerank.d.ts +9 -0
  46. package/dist/graph/pagerank.d.ts.map +1 -0
  47. package/dist/graph/pagerank.js +47 -0
  48. package/dist/graph/pagerank.js.map +1 -0
  49. package/dist/indexer/architecture.d.ts +72 -0
  50. package/dist/indexer/architecture.d.ts.map +1 -0
  51. package/dist/indexer/architecture.js +112 -0
  52. package/dist/indexer/architecture.js.map +1 -0
  53. package/dist/indexer/behavior.d.ts +75 -0
  54. package/dist/indexer/behavior.d.ts.map +1 -0
  55. package/dist/indexer/behavior.js +395 -0
  56. package/dist/indexer/behavior.js.map +1 -0
  57. package/dist/indexer/boundaries.d.ts +60 -0
  58. package/dist/indexer/boundaries.d.ts.map +1 -0
  59. package/dist/indexer/boundaries.js +366 -0
  60. package/dist/indexer/boundaries.js.map +1 -0
  61. package/dist/indexer/churn.d.ts +15 -0
  62. package/dist/indexer/churn.d.ts.map +1 -0
  63. package/dist/indexer/churn.js +49 -0
  64. package/dist/indexer/churn.js.map +1 -0
  65. package/dist/indexer/classify.d.ts +9 -0
  66. package/dist/indexer/classify.d.ts.map +1 -0
  67. package/dist/indexer/classify.js +90 -0
  68. package/dist/indexer/classify.js.map +1 -0
  69. package/dist/indexer/context.d.ts +176 -0
  70. package/dist/indexer/context.d.ts.map +1 -0
  71. package/dist/indexer/context.js +193 -0
  72. package/dist/indexer/context.js.map +1 -0
  73. package/dist/indexer/continuity.d.ts +67 -0
  74. package/dist/indexer/continuity.d.ts.map +1 -0
  75. package/dist/indexer/continuity.js +288 -0
  76. package/dist/indexer/continuity.js.map +1 -0
  77. package/dist/indexer/detectchanges.d.ts +32 -0
  78. package/dist/indexer/detectchanges.d.ts.map +1 -0
  79. package/dist/indexer/detectchanges.js +74 -0
  80. package/dist/indexer/detectchanges.js.map +1 -0
  81. package/dist/indexer/discovery.d.ts +37 -0
  82. package/dist/indexer/discovery.d.ts.map +1 -0
  83. package/dist/indexer/discovery.js +136 -0
  84. package/dist/indexer/discovery.js.map +1 -0
  85. package/dist/indexer/externaldeps.d.ts +18 -0
  86. package/dist/indexer/externaldeps.d.ts.map +1 -0
  87. package/dist/indexer/externaldeps.js +288 -0
  88. package/dist/indexer/externaldeps.js.map +1 -0
  89. package/dist/indexer/freshness.d.ts +48 -0
  90. package/dist/indexer/freshness.d.ts.map +1 -0
  91. package/dist/indexer/freshness.js +128 -0
  92. package/dist/indexer/freshness.js.map +1 -0
  93. package/dist/indexer/git.d.ts +144 -0
  94. package/dist/indexer/git.d.ts.map +1 -0
  95. package/dist/indexer/git.js +444 -0
  96. package/dist/indexer/git.js.map +1 -0
  97. package/dist/indexer/index.d.ts +145 -0
  98. package/dist/indexer/index.d.ts.map +1 -0
  99. package/dist/indexer/index.js +930 -0
  100. package/dist/indexer/index.js.map +1 -0
  101. package/dist/indexer/modules.d.ts +62 -0
  102. package/dist/indexer/modules.d.ts.map +1 -0
  103. package/dist/indexer/modules.js +293 -0
  104. package/dist/indexer/modules.js.map +1 -0
  105. package/dist/indexer/preflight.d.ts +154 -0
  106. package/dist/indexer/preflight.d.ts.map +1 -0
  107. package/dist/indexer/preflight.js +399 -0
  108. package/dist/indexer/preflight.js.map +1 -0
  109. package/dist/indexer/protoScanner.d.ts +34 -0
  110. package/dist/indexer/protoScanner.d.ts.map +1 -0
  111. package/dist/indexer/protoScanner.js +133 -0
  112. package/dist/indexer/protoScanner.js.map +1 -0
  113. package/dist/indexer/risk.d.ts +115 -0
  114. package/dist/indexer/risk.d.ts.map +1 -0
  115. package/dist/indexer/risk.js +194 -0
  116. package/dist/indexer/risk.js.map +1 -0
  117. package/dist/indexer/serviceHostScanner.d.ts +25 -0
  118. package/dist/indexer/serviceHostScanner.d.ts.map +1 -0
  119. package/dist/indexer/serviceHostScanner.js +95 -0
  120. package/dist/indexer/serviceHostScanner.js.map +1 -0
  121. package/dist/indexer/serviceLinks.d.ts +105 -0
  122. package/dist/indexer/serviceLinks.d.ts.map +1 -0
  123. package/dist/indexer/serviceLinks.js +509 -0
  124. package/dist/indexer/serviceLinks.js.map +1 -0
  125. package/dist/indexer/shapehash.d.ts +98 -0
  126. package/dist/indexer/shapehash.d.ts.map +1 -0
  127. package/dist/indexer/shapehash.js +354 -0
  128. package/dist/indexer/shapehash.js.map +1 -0
  129. package/dist/indexer/skeleton.d.ts +15 -0
  130. package/dist/indexer/skeleton.d.ts.map +1 -0
  131. package/dist/indexer/skeleton.js +136 -0
  132. package/dist/indexer/skeleton.js.map +1 -0
  133. package/dist/indexer/symbolhistory.d.ts +41 -0
  134. package/dist/indexer/symbolhistory.d.ts.map +1 -0
  135. package/dist/indexer/symbolhistory.js +124 -0
  136. package/dist/indexer/symbolhistory.js.map +1 -0
  137. package/dist/indexer/watcher.d.ts +68 -0
  138. package/dist/indexer/watcher.d.ts.map +1 -0
  139. package/dist/indexer/watcher.js +179 -0
  140. package/dist/indexer/watcher.js.map +1 -0
  141. package/dist/mcp/server.d.ts +80 -0
  142. package/dist/mcp/server.d.ts.map +1 -0
  143. package/dist/mcp/server.js +1610 -0
  144. package/dist/mcp/server.js.map +1 -0
  145. package/dist/parser/index.d.ts +8 -0
  146. package/dist/parser/index.d.ts.map +1 -0
  147. package/dist/parser/index.js +33 -0
  148. package/dist/parser/index.js.map +1 -0
  149. package/dist/parser/languages/cpp.d.ts +3 -0
  150. package/dist/parser/languages/cpp.d.ts.map +1 -0
  151. package/dist/parser/languages/cpp.js +350 -0
  152. package/dist/parser/languages/cpp.js.map +1 -0
  153. package/dist/parser/languages/csharp.d.ts +3 -0
  154. package/dist/parser/languages/csharp.d.ts.map +1 -0
  155. package/dist/parser/languages/csharp.js +239 -0
  156. package/dist/parser/languages/csharp.js.map +1 -0
  157. package/dist/parser/languages/go.d.ts +3 -0
  158. package/dist/parser/languages/go.d.ts.map +1 -0
  159. package/dist/parser/languages/go.js +259 -0
  160. package/dist/parser/languages/go.js.map +1 -0
  161. package/dist/parser/languages/java.d.ts +3 -0
  162. package/dist/parser/languages/java.d.ts.map +1 -0
  163. package/dist/parser/languages/java.js +391 -0
  164. package/dist/parser/languages/java.js.map +1 -0
  165. package/dist/parser/languages/python.d.ts +3 -0
  166. package/dist/parser/languages/python.d.ts.map +1 -0
  167. package/dist/parser/languages/python.js +396 -0
  168. package/dist/parser/languages/python.js.map +1 -0
  169. package/dist/parser/languages/rust.d.ts +3 -0
  170. package/dist/parser/languages/rust.d.ts.map +1 -0
  171. package/dist/parser/languages/rust.js +159 -0
  172. package/dist/parser/languages/rust.js.map +1 -0
  173. package/dist/parser/languages/typescript.d.ts +3 -0
  174. package/dist/parser/languages/typescript.d.ts.map +1 -0
  175. package/dist/parser/languages/typescript.js +1442 -0
  176. package/dist/parser/languages/typescript.js.map +1 -0
  177. package/dist/parser/parserContext.d.ts +77 -0
  178. package/dist/parser/parserContext.d.ts.map +1 -0
  179. package/dist/parser/parserContext.js +354 -0
  180. package/dist/parser/parserContext.js.map +1 -0
  181. package/dist/parser/walker.d.ts +81 -0
  182. package/dist/parser/walker.d.ts.map +1 -0
  183. package/dist/parser/walker.js +217 -0
  184. package/dist/parser/walker.js.map +1 -0
  185. package/dist/parser/worker.d.ts +66 -0
  186. package/dist/parser/worker.d.ts.map +1 -0
  187. package/dist/parser/worker.js +129 -0
  188. package/dist/parser/worker.js.map +1 -0
  189. package/dist/parser/workerpool.d.ts +107 -0
  190. package/dist/parser/workerpool.d.ts.map +1 -0
  191. package/dist/parser/workerpool.js +383 -0
  192. package/dist/parser/workerpool.js.map +1 -0
  193. package/dist/scip/format.d.ts +87 -0
  194. package/dist/scip/format.d.ts.map +1 -0
  195. package/dist/scip/format.js +31 -0
  196. package/dist/scip/format.js.map +1 -0
  197. package/dist/scip/import.d.ts +37 -0
  198. package/dist/scip/import.d.ts.map +1 -0
  199. package/dist/scip/import.js +180 -0
  200. package/dist/scip/import.js.map +1 -0
  201. package/dist/types.d.ts +392 -0
  202. package/dist/types.d.ts.map +1 -0
  203. package/dist/types.js +4 -0
  204. package/dist/types.js.map +1 -0
  205. package/docs/architecture.md +105 -0
  206. package/docs/benchmarks/methodology.md +134 -0
  207. package/docs/benchmarks/raw-results.md +71 -0
  208. package/docs/benchmarks.md +74 -0
  209. package/docs/cli.md +148 -0
  210. package/docs/examples/behavior-tests.md +70 -0
  211. package/docs/examples/change-history.md +85 -0
  212. package/docs/examples/pre-edit-context.md +81 -0
  213. package/docs/examples/service-links.md +88 -0
  214. package/docs/examples.md +80 -0
  215. package/docs/faq.md +70 -0
  216. package/docs/internals.md +104 -0
  217. package/docs/languages.md +70 -0
  218. package/docs/limits.md +52 -0
  219. package/docs/mcp.md +199 -0
  220. package/docs/quickstart.md +119 -0
  221. package/docs/testing.md +123 -0
  222. package/docs/tools.md +115 -0
  223. package/package.json +52 -0
  224. package/research-codebase.md +578 -0
  225. package/seer-cli-docs.md +326 -0
  226. package/seer-master-guide.md +246 -0
  227. package/src/bundle/ci.ts +141 -0
  228. package/src/bundle/contract.ts +387 -0
  229. package/src/bundle/export.ts +175 -0
  230. package/src/bundle/external.ts +285 -0
  231. package/src/bundle/format.ts +92 -0
  232. package/src/bundle/import.ts +157 -0
  233. package/src/cli/index.ts +1249 -0
  234. package/src/cli/init.ts +389 -0
  235. package/src/db/schema.ts +614 -0
  236. package/src/db/store.ts +4306 -0
  237. package/src/graph/pagerank.ts +53 -0
  238. package/src/indexer/architecture.ts +148 -0
  239. package/src/indexer/behavior.ts +466 -0
  240. package/src/indexer/boundaries.ts +374 -0
  241. package/src/indexer/churn.ts +58 -0
  242. package/src/indexer/classify.ts +96 -0
  243. package/src/indexer/context.ts +340 -0
  244. package/src/indexer/continuity.ts +322 -0
  245. package/src/indexer/detectchanges.ts +94 -0
  246. package/src/indexer/discovery.ts +176 -0
  247. package/src/indexer/externaldeps.ts +243 -0
  248. package/src/indexer/freshness.ts +166 -0
  249. package/src/indexer/git.ts +453 -0
  250. package/src/indexer/index.ts +1092 -0
  251. package/src/indexer/modules.ts +358 -0
  252. package/src/indexer/preflight.ts +548 -0
  253. package/src/indexer/protoScanner.ts +147 -0
  254. package/src/indexer/risk.ts +304 -0
  255. package/src/indexer/serviceHostScanner.ts +92 -0
  256. package/src/indexer/serviceLinks.ts +543 -0
  257. package/src/indexer/shapehash.ts +370 -0
  258. package/src/indexer/skeleton.ts +169 -0
  259. package/src/indexer/symbolhistory.ts +172 -0
  260. package/src/indexer/watcher.ts +206 -0
  261. package/src/mcp/server.ts +1659 -0
  262. package/src/parser/index.ts +37 -0
  263. package/src/parser/languages/cpp.ts +361 -0
  264. package/src/parser/languages/csharp.ts +235 -0
  265. package/src/parser/languages/go.ts +259 -0
  266. package/src/parser/languages/java.ts +382 -0
  267. package/src/parser/languages/python.ts +370 -0
  268. package/src/parser/languages/rust.ts +164 -0
  269. package/src/parser/languages/typescript.ts +1435 -0
  270. package/src/parser/parserContext.ts +392 -0
  271. package/src/parser/walker.ts +306 -0
  272. package/src/parser/worker.ts +181 -0
  273. package/src/parser/workerpool.ts +448 -0
  274. package/src/scip/format.ts +83 -0
  275. package/src/scip/import.ts +216 -0
  276. package/src/types.ts +457 -0
  277. package/tests/benchmark-service-links.ts +244 -0
  278. package/tests/bug-regressions.ts +626 -0
  279. package/tests/filters.ts +264 -0
  280. package/tests/fixtures/Counter.tsx +38 -0
  281. package/tests/fixtures/caller.ts +7 -0
  282. package/tests/fixtures/collisions.ts +23 -0
  283. package/tests/fixtures/local_helper.ts +5 -0
  284. package/tests/fixtures/overloads.java +17 -0
  285. package/tests/fixtures/remote_helper.ts +4 -0
  286. package/tests/fixtures/sample.c +15 -0
  287. package/tests/fixtures/sample.cpp +47 -0
  288. package/tests/fixtures/sample.cs +62 -0
  289. package/tests/fixtures/sample.go +68 -0
  290. package/tests/fixtures/sample.h +30 -0
  291. package/tests/fixtures/sample.java +85 -0
  292. package/tests/fixtures/sample.py +46 -0
  293. package/tests/fixtures/sample.rs +78 -0
  294. package/tests/fixtures/sample.ts +76 -0
  295. package/tests/fixtures-service/HttpClients.cs +30 -0
  296. package/tests/fixtures-service/HttpClients.java +24 -0
  297. package/tests/fixtures-service/billing.ts +15 -0
  298. package/tests/fixtures-service/docker-compose.yml +15 -0
  299. package/tests/fixtures-service/gateway.ts +10 -0
  300. package/tests/fixtures-service/get_user.ts +11 -0
  301. package/tests/fixtures-service/graphql_client.ts +63 -0
  302. package/tests/fixtures-service/graphql_server.ts +30 -0
  303. package/tests/fixtures-service/grpc_client.go +30 -0
  304. package/tests/fixtures-service/http_clients.go +23 -0
  305. package/tests/fixtures-service/http_clients.py +38 -0
  306. package/tests/fixtures-service/http_clients.ts +49 -0
  307. package/tests/fixtures-service/k8s/payment-service.yaml +22 -0
  308. package/tests/fixtures-service/k8s_calls.ts +20 -0
  309. package/tests/fixtures-service/messaging.ts +87 -0
  310. package/tests/fixtures-service/trpc_client.ts +39 -0
  311. package/tests/fixtures-service/trpc_server.ts +39 -0
  312. package/tests/fixtures-service/user_service.proto +33 -0
  313. package/tests/fixtures-trackcd/Cargo.toml +11 -0
  314. package/tests/fixtures-trackcd/SpringController.java +36 -0
  315. package/tests/fixtures-trackcd/auth_service.ts +19 -0
  316. package/tests/fixtures-trackcd/complex_module.py +50 -0
  317. package/tests/fixtures-trackcd/express_app.js +30 -0
  318. package/tests/fixtures-trackcd/fastapi_app.py +49 -0
  319. package/tests/fixtures-trackcd/fastify_object_routes.js +32 -0
  320. package/tests/fixtures-trackcd/go.mod +8 -0
  321. package/tests/fixtures-trackcd/package.json +15 -0
  322. package/tests/fixtures-trackcd/requirements.txt +4 -0
  323. package/tests/fixtures-trackcd/tests/auth_service.test.ts +13 -0
  324. package/tests/fixtures-tracke/auth/AuthService.ts +23 -0
  325. package/tests/fixtures-tracke/auth/crypto.ts +7 -0
  326. package/tests/fixtures-tracke/billing/Billing.ts +20 -0
  327. package/tests/fixtures-tracke/billing/Invoice.ts +10 -0
  328. package/tests/fixtures-tracke/billing/server.ts +17 -0
  329. package/tests/fixtures-tracke/package.json +7 -0
  330. package/tests/fixtures-tracke/tests/auth.test.ts +23 -0
  331. package/tests/fixtures-tracke/tests/billing.test.ts +14 -0
  332. package/tests/fixtures-trackf/package.json +5 -0
  333. package/tests/fixtures-trackf/src/auth.ts +26 -0
  334. package/tests/fixtures-trackf/src/handlers.ts +35 -0
  335. package/tests/fixtures-tracki/billing/routes.ts +12 -0
  336. package/tests/fixtures-tracki/gateway/client.ts +13 -0
  337. package/tests/git-features.ts +267 -0
  338. package/tests/init.ts +141 -0
  339. package/tests/mcp-jit.ts +130 -0
  340. package/tests/mcp-smoke.ts +191 -0
  341. package/tests/mcp-trackcd.ts +169 -0
  342. package/tests/mcp-tracke.ts +229 -0
  343. package/tests/mcp-trackf.ts +330 -0
  344. package/tests/mcp-trackg.ts +219 -0
  345. package/tests/mcp-tracki.ts +174 -0
  346. package/tests/mcp-watcher.ts +126 -0
  347. package/tests/optspec.ts +194 -0
  348. package/tests/parallel-index.ts +333 -0
  349. package/tests/parallel-read.ts +125 -0
  350. package/tests/parallel-recovery.ts +241 -0
  351. package/tests/perf-callers.ts +145 -0
  352. package/tests/query-parity.ts +184 -0
  353. package/tests/query-perf.ts +55 -0
  354. package/tests/scale-parallel-parity.ts +225 -0
  355. package/tests/scale-test.ts +523 -0
  356. package/tests/smoke.ts +396 -0
  357. package/tests/trackcd.ts +325 -0
  358. package/tests/tracke-collisions.ts +255 -0
  359. package/tests/tracke.ts +314 -0
  360. package/tests/trackf-bugs.ts +406 -0
  361. package/tests/trackf.ts +390 -0
  362. package/tests/trackg.ts +1372 -0
  363. package/tests/tracki-boundaries.ts +202 -0
  364. package/tests/tracki-continuity.ts +253 -0
  365. package/tests/tracki-contract-diff.ts +249 -0
  366. package/tests/tracki-external-bundles.ts +341 -0
  367. package/tests/tracki-preflight.ts +251 -0
  368. package/tests/verify-roles.ts +51 -0
  369. package/tests/worker-parity.ts +286 -0
  370. package/tests/worker-pool.ts +262 -0
  371. package/tsconfig.json +20 -0
@@ -0,0 +1,37 @@
1
+ import type { FileExtraction, Language } from '../types.js';
2
+ import { ParserContext, detectLanguage } from './parserContext.js';
3
+
4
+ // Re-export the pure helpers — they hold no state and can move freely.
5
+ export { detectLanguage };
6
+ export { detectLanguage as getLanguage };
7
+
8
+ // ── Default ParserContext for the main-thread API ────────────────────────────
9
+ //
10
+ // Historically this file held module-level WASM state. After the Step 1
11
+ // refactor that state lives in `ParserContext`, and this module backs the
12
+ // legacy free-function API (`parseFile`, `wasmResetCount`,
13
+ // `setForceBaselineWalker`) with a single lazily-instantiated default
14
+ // instance. Worker threads construct their own `ParserContext` directly from
15
+ // `./parserContext.js` and do NOT go through these shims.
16
+
17
+ let _defaultContext: ParserContext | null = null;
18
+ function getDefaultContext(): ParserContext {
19
+ if (!_defaultContext) _defaultContext = new ParserContext();
20
+ return _defaultContext;
21
+ }
22
+
23
+ export async function parseFile(
24
+ content: string,
25
+ filePathOrLanguage: string,
26
+ languageOverride?: Language,
27
+ ): Promise<FileExtraction | null> {
28
+ return getDefaultContext().parseFile(content, filePathOrLanguage, languageOverride);
29
+ }
30
+
31
+ export function wasmResetCount(): number {
32
+ return getDefaultContext().wasmResetCount();
33
+ }
34
+
35
+ export function setForceBaselineWalker(force: boolean): void {
36
+ getDefaultContext().setForceBaselineWalker(force);
37
+ }
@@ -0,0 +1,361 @@
1
+ import type Parser from 'web-tree-sitter';
2
+ import type { SymbolDef, SymbolKind } from '../../types.js';
3
+ import type { LanguageExtractor } from '../walker.js';
4
+ import { firstLine } from '../walker.js';
5
+
6
+ /**
7
+ * C++ extractor — handles both .cpp/.cc/.cxx source files and .h/.hpp headers.
8
+ *
9
+ * Tree-sitter-cpp parses function names through recursive `declarator` chains,
10
+ * which is the main complexity here. A definition like:
11
+ *
12
+ * void Foo::bar(int x) { ... }
13
+ *
14
+ * parses as:
15
+ * function_definition
16
+ * ├ type: primitive_type "void"
17
+ * └ declarator: function_declarator
18
+ * ├ declarator: qualified_identifier
19
+ * │ ├ scope: namespace_identifier "Foo"
20
+ * │ └ name: identifier "bar"
21
+ * └ parameters: parameter_list
22
+ *
23
+ * The helper `extractDeclaratorName` walks down through pointer_declarator,
24
+ * reference_declarator, etc. to find the leaf identifier.
25
+ */
26
+ const CPP_BRANCH_NODES = new Set<string>([
27
+ 'if_statement', 'while_statement', 'do_statement', 'for_statement', 'for_range_loop',
28
+ 'case_statement', 'catch_clause', 'conditional_expression',
29
+ ]);
30
+
31
+ const CPP_NESTING_NODES = new Set<string>([
32
+ 'if_statement', 'while_statement', 'do_statement', 'for_statement', 'for_range_loop',
33
+ 'switch_statement', 'catch_clause', 'try_statement',
34
+ ]);
35
+
36
+ // Superset of every node type the C/C++ tryExtract* may accept. Some types
37
+ // (`class_specifier`, `alias_declaration`, `namespace_definition`) exist only
38
+ // in the C++ grammar; the parser's query compiler probes each type and drops
39
+ // any that the grammar rejects, so this list is safe to share between the
40
+ // `cpp` and `c` extractor instances.
41
+ const CPP_CANDIDATE_NODE_TYPES = [
42
+ // tryExtractDefinition (body-gated for struct/union/enum/class)
43
+ 'function_definition',
44
+ 'class_specifier',
45
+ 'struct_specifier',
46
+ 'union_specifier',
47
+ 'enum_specifier',
48
+ 'field_declaration',
49
+ 'declaration', // free-function prototypes / forward decls
50
+ 'type_definition',
51
+ 'alias_declaration',
52
+ // tryExtractCallName
53
+ 'call_expression',
54
+ // tryExtractImport
55
+ 'preproc_include',
56
+ // tryExtractContextName — namespace foo { ... } (C++ only)
57
+ 'namespace_definition',
58
+ ] as const;
59
+
60
+ export const cppExtractor: LanguageExtractor = {
61
+ languageName: 'cpp',
62
+ extensions: ['.cpp', '.cc', '.cxx', '.c++', '.hpp', '.hh', '.h++', '.h'],
63
+ branchNodeTypes: CPP_BRANCH_NODES,
64
+ nestingNodeTypes: CPP_NESTING_NODES,
65
+ candidateNodeTypes: CPP_CANDIDATE_NODE_TYPES,
66
+
67
+ tryExtractDefinition(node: Parser.SyntaxNode): SymbolDef | null {
68
+ switch (node.type) {
69
+ // void foo() { ... } or void Foo::bar() { ... }
70
+ case 'function_definition': {
71
+ const declarator = node.childForFieldName('declarator');
72
+ if (!declarator) return null;
73
+ // Out-of-line method definitions name their owner via a
74
+ // qualified_identifier declarator (`Vec<T>::dot`, `A::B::method`).
75
+ // Surface the owner scope so the qualified name is `…Vec.dot`, not a
76
+ // bare `dot` that reads like a free function.
77
+ const qual = extractQualifiedScope(declarator);
78
+ if (qual && qual.scopes.length > 0) {
79
+ const def = mkDef(qual.name, 'function', node);
80
+ def.scopePath = qual.scopes;
81
+ return def;
82
+ }
83
+ const name = extractDeclaratorName(declarator);
84
+ if (!name) return null;
85
+ return mkDef(name, 'function', node);
86
+ }
87
+
88
+ // class Foo { ... };
89
+ // The body gate is critical: without it, every forward declaration
90
+ // (`class Foo;`) and every use of Foo as a type (`Foo *p`) also matches
91
+ // class_specifier and would be emitted as a duplicate "class Foo" symbol.
92
+ // We only emit when there's a real definition body.
93
+ case 'class_specifier': {
94
+ if (!node.childForFieldName('body')) return null;
95
+ const nameNode = node.childForFieldName('name');
96
+ if (!nameNode) return null;
97
+ return mkDef(nameNode.text, 'class', node);
98
+ }
99
+
100
+ // struct Foo { ... };
101
+ // Body gate (see class_specifier above). In C, `struct_specifier`
102
+ // appears in EVERY type reference: `int foo(struct device *dev)` parses
103
+ // as a struct_specifier child of the parameter declaration. Without the
104
+ // body check, we'd emit ~50k bogus "struct device" symbols on the Linux
105
+ // kernel for one real definition.
106
+ case 'struct_specifier': {
107
+ if (!node.childForFieldName('body')) return null;
108
+ const nameNode = node.childForFieldName('name');
109
+ if (!nameNode) return null;
110
+ return mkDef(nameNode.text, 'struct', node);
111
+ }
112
+
113
+ // union Foo { ... };
114
+ // Same body-gate rationale as struct/class. Untracked previously; tracking
115
+ // explicitly so unions stop slipping through as anonymous type references.
116
+ case 'union_specifier': {
117
+ if (!node.childForFieldName('body')) return null;
118
+ const nameNode = node.childForFieldName('name');
119
+ if (!nameNode) return null;
120
+ return mkDef(nameNode.text, 'struct', node);
121
+ }
122
+
123
+ // enum Color { RED, GREEN }; or enum class Color { ... };
124
+ // Body gate (see struct_specifier). Linux has ~99k enum rows today, most
125
+ // of which are type references like `enum dma_data_direction dir`.
126
+ case 'enum_specifier': {
127
+ if (!node.childForFieldName('body')) return null;
128
+ const nameNode = node.childForFieldName('name');
129
+ if (!nameNode) return null;
130
+ return mkDef(nameNode.text, 'enum', node);
131
+ }
132
+
133
+ // Methods declared (not defined) inside a class body. These are field
134
+ // declarations whose declarator is a function_declarator — e.g.
135
+ // class Foo { void bar(); }; ← bar is a method declaration
136
+ // We extract it as a method symbol so it can be linked from elsewhere,
137
+ // but tag it as `symbolRole='declaration'` so default agent-facing
138
+ // queries (top by rank, search) skip the declaration site in favour of
139
+ // the body-bearing `void Foo::bar() { ... }` definition that lives in
140
+ // the .cpp. Callers/callees still work because edges resolve by name.
141
+ case 'field_declaration': {
142
+ const declarator = node.childForFieldName('declarator');
143
+ if (!declarator || declarator.type !== 'function_declarator') return null;
144
+ const name = extractDeclaratorName(declarator);
145
+ if (!name) return null;
146
+ const def = mkDef(name, 'method', node);
147
+ def.symbolRole = 'declaration';
148
+ return def;
149
+ }
150
+
151
+ // Free-function prototypes / forward declarations at file scope, e.g.
152
+ // void foo(int x);
153
+ // extern int g_counter; ← variable; we don't emit these
154
+ // struct foo; ← struct forward-decl (handled below)
155
+ // tree-sitter-c/cpp parse these as `declaration` nodes whose declarator
156
+ // is a function_declarator. They're explicit declarations, not
157
+ // definitions; surface them with symbolRole='declaration' so callers
158
+ // who want to navigate to "where is this announced" can find them while
159
+ // default queries focus on the body-bearing definitions.
160
+ case 'declaration': {
161
+ const declarator = node.childForFieldName('declarator');
162
+ if (!declarator || declarator.type !== 'function_declarator') return null;
163
+ const name = extractDeclaratorName(declarator);
164
+ if (!name) return null;
165
+ const def = mkDef(name, 'function', node);
166
+ def.symbolRole = 'declaration';
167
+ return def;
168
+ }
169
+
170
+ // typedef int Foo; or using Foo = int;
171
+ case 'type_definition': {
172
+ const declarator = node.childForFieldName('declarator');
173
+ const name = declarator ? extractDeclaratorName(declarator) : null;
174
+ if (!name) return null;
175
+ return mkDef(name, 'type', node);
176
+ }
177
+
178
+ case 'alias_declaration': {
179
+ const nameNode = node.childForFieldName('name');
180
+ if (!nameNode) return null;
181
+ return mkDef(nameNode.text, 'type', node);
182
+ }
183
+
184
+ default:
185
+ return null;
186
+ }
187
+ },
188
+
189
+ tryExtractCallName(node: Parser.SyntaxNode): string | null {
190
+ if (node.type !== 'call_expression') return null;
191
+ const funcNode = node.childForFieldName('function');
192
+ if (!funcNode) return null;
193
+
194
+ // foo()
195
+ if (funcNode.type === 'identifier') return funcNode.text;
196
+
197
+ // obj.method() or obj->method()
198
+ if (funcNode.type === 'field_expression') {
199
+ return funcNode.childForFieldName('field')?.text ?? null;
200
+ }
201
+
202
+ // ns::func() or Class::staticMethod()
203
+ if (funcNode.type === 'qualified_identifier') {
204
+ // Walk down the right side — there may be nested qualified_identifiers
205
+ let cur: Parser.SyntaxNode | null = funcNode;
206
+ while (cur && cur.type === 'qualified_identifier') {
207
+ const name = cur.childForFieldName('name');
208
+ if (name && name.type === 'identifier') return name.text;
209
+ cur = name;
210
+ }
211
+ return null;
212
+ }
213
+
214
+ // template specialization: foo<int>()
215
+ if (funcNode.type === 'template_function') {
216
+ const name = funcNode.childForFieldName('name');
217
+ return name?.text ?? null;
218
+ }
219
+
220
+ return null;
221
+ },
222
+
223
+ tryExtractImport(node: Parser.SyntaxNode): string | null {
224
+ // #include "foo.h" or #include <foo.h>
225
+ if (node.type === 'preproc_include') {
226
+ const pathNode = node.childForFieldName('path');
227
+ if (!pathNode) return null;
228
+ // The text includes the surrounding "" or <>
229
+ return pathNode.text.replace(/^[<"]/, '').replace(/[>"]$/, '');
230
+ }
231
+ return null;
232
+ },
233
+
234
+ /**
235
+ * Class/struct bodies provide naming context for nested method declarations,
236
+ * so that `class Foo { void bar(); }` gives `bar` the qualified name `Foo.bar`.
237
+ */
238
+ tryExtractContextName(node: Parser.SyntaxNode): string | null {
239
+ if (node.type === 'class_specifier' || node.type === 'struct_specifier') {
240
+ // We've already emitted the class as a symbol, but we also want to
241
+ // *re-push* its name so methods inside get `Foo.method` qualification.
242
+ // However, the walker already pushes the def's `name` when it accepts a
243
+ // definition — so this hook is redundant for definitions that are also
244
+ // emitted. We return null here and let walker's normal def-stack push
245
+ // handle nesting. (This hook is reserved for nodes like Rust impl that
246
+ // AREN'T emitted as symbols themselves.)
247
+ return null;
248
+ }
249
+ // namespace foo { ... } — push the namespace name for qualified context
250
+ if (node.type === 'namespace_definition') {
251
+ const nameNode = node.childForFieldName('name');
252
+ return nameNode?.text ?? null;
253
+ }
254
+ return null;
255
+ },
256
+ };
257
+
258
+ /**
259
+ * Walk a declarator chain (which may be wrapped in pointer/reference/array
260
+ * declarators) to find the inner identifier. Examples:
261
+ *
262
+ * identifier "foo" → "foo"
263
+ * pointer_declarator "*foo" → "foo"
264
+ * function_declarator "foo(int)" → "foo" (recurse on inner declarator)
265
+ * qualified_identifier "Foo::bar" → "bar" (the leaf name)
266
+ * field_identifier "method" → "method"
267
+ * destructor_name "~Foo" → "~Foo"
268
+ * operator_name "operator==" → "operator=="
269
+ */
270
+ function extractDeclaratorName(node: Parser.SyntaxNode): string | null {
271
+ // Direct identifier nodes
272
+ if (node.type === 'identifier' || node.type === 'field_identifier') {
273
+ return node.text;
274
+ }
275
+ if (node.type === 'destructor_name' || node.type === 'operator_name') {
276
+ return node.text;
277
+ }
278
+
279
+ // Qualified: Foo::bar → "bar"
280
+ if (node.type === 'qualified_identifier') {
281
+ const name = node.childForFieldName('name');
282
+ return name ? extractDeclaratorName(name) : null;
283
+ }
284
+
285
+ // Wrapping declarators — recurse into the `declarator` field
286
+ if (
287
+ node.type === 'function_declarator' ||
288
+ node.type === 'pointer_declarator' ||
289
+ node.type === 'reference_declarator' ||
290
+ node.type === 'array_declarator' ||
291
+ node.type === 'parenthesized_declarator'
292
+ ) {
293
+ const inner = node.childForFieldName('declarator');
294
+ return inner ? extractDeclaratorName(inner) : null;
295
+ }
296
+
297
+ // Template names: foo<int> → "foo"
298
+ if (node.type === 'template_function') {
299
+ const name = node.childForFieldName('name');
300
+ return name ? extractDeclaratorName(name) : null;
301
+ }
302
+
303
+ return null;
304
+ }
305
+
306
+ /**
307
+ * For an out-of-line definition whose declarator is (or wraps) a
308
+ * `qualified_identifier`, return the owner scope chain and the leaf name:
309
+ *
310
+ * void Foo::bar() {} → { scopes: ['Foo'], name: 'bar' }
311
+ * T Vec<T>::dot() {} → { scopes: ['Vec'], name: 'dot' } (template args folded off)
312
+ * int A::B::compute() {} → { scopes: ['A','B'], name: 'compute' }
313
+ * void Widget::~Widget() {} → { scopes: ['Widget'], name: '~Widget' }
314
+ *
315
+ * Returns null when the declarator is unqualified (a normal free function or
316
+ * in-class definition) so the caller falls back to the plain name path.
317
+ */
318
+ function extractQualifiedScope(
319
+ declarator: Parser.SyntaxNode,
320
+ ): { scopes: string[]; name: string } | null {
321
+ // Unwrap pointer/reference/function/parenthesized declarators to the core.
322
+ let node: Parser.SyntaxNode | null = declarator;
323
+ while (
324
+ node &&
325
+ (node.type === 'function_declarator' ||
326
+ node.type === 'pointer_declarator' ||
327
+ node.type === 'reference_declarator' ||
328
+ node.type === 'parenthesized_declarator')
329
+ ) {
330
+ node = node.childForFieldName('declarator');
331
+ }
332
+ if (!node || node.type !== 'qualified_identifier') return null;
333
+
334
+ const scopes: string[] = [];
335
+ let cur: Parser.SyntaxNode | null = node;
336
+ while (cur && cur.type === 'qualified_identifier') {
337
+ const scope = cur.childForFieldName('scope');
338
+ if (scope) {
339
+ // Fold template arguments off the scope: `Vec<T>` → `Vec`. Anonymous or
340
+ // empty scopes are skipped rather than emitted as ''.
341
+ const folded = scope.text.split('<')[0].trim();
342
+ if (folded) scopes.push(folded);
343
+ }
344
+ cur = cur.childForFieldName('name');
345
+ }
346
+ const name = cur ? extractDeclaratorName(cur) : null;
347
+ if (!name) return null;
348
+ return { scopes, name };
349
+ }
350
+
351
+ function mkDef(name: string, kind: SymbolKind, node: Parser.SyntaxNode): SymbolDef {
352
+ return {
353
+ name,
354
+ kind,
355
+ lineStart: node.startPosition.row,
356
+ lineEnd: node.endPosition.row,
357
+ colStart: node.startPosition.column,
358
+ colEnd: node.endPosition.column,
359
+ signature: firstLine(node),
360
+ };
361
+ }
@@ -0,0 +1,235 @@
1
+ import type Parser from 'web-tree-sitter';
2
+ import type { SymbolDef, SymbolKind, ServiceCallDef } from '../../types.js';
3
+ import type { LanguageExtractor } from '../walker.js';
4
+ import { firstLine } from '../walker.js';
5
+
6
+ // C# HttpClient async method names → HTTP verb.
7
+ const CS_HTTP_CLIENT_METHODS = new Map<string, string>([
8
+ ['GetAsync', 'GET'], ['GetStringAsync', 'GET'], ['GetByteArrayAsync', 'GET'],
9
+ ['GetStreamAsync', 'GET'], ['GetFromJsonAsync', 'GET'],
10
+ ['PostAsync', 'POST'], ['PostAsJsonAsync', 'POST'],
11
+ ['PutAsync', 'PUT'], ['PutAsJsonAsync', 'PUT'],
12
+ ['PatchAsync', 'PATCH'],
13
+ ['DeleteAsync', 'DELETE'],
14
+ ['SendAsync', 'ANY'],
15
+ ]);
16
+
17
+ function csLooksLikeHttpTarget(s: string): boolean {
18
+ if (!s) return false;
19
+ if (s.startsWith('/')) return true;
20
+ if (/^https?:\/\//i.test(s)) return true;
21
+ return false;
22
+ }
23
+
24
+ /**
25
+ * C# extractor — covers .cs files. Common in Godot (since Godot 4 supports
26
+ * C# scripting via partial classes) and Unity.
27
+ *
28
+ * The C# tree-sitter grammar mostly mirrors Java's structure with a few
29
+ * naming differences (`invocation_expression` rather than `method_invocation`,
30
+ * `object_creation_expression` for `new`, etc.).
31
+ */
32
+ const CS_BRANCH_NODES = new Set<string>([
33
+ 'if_statement', 'while_statement', 'do_statement', 'for_statement', 'for_each_statement',
34
+ 'switch_section', 'catch_clause', 'conditional_expression',
35
+ ]);
36
+
37
+ const CS_NESTING_NODES = new Set<string>([
38
+ 'if_statement', 'while_statement', 'do_statement', 'for_statement', 'for_each_statement',
39
+ 'switch_statement', 'catch_clause', 'try_statement',
40
+ ]);
41
+
42
+ const CS_CANDIDATE_NODE_TYPES = [
43
+ // tryExtractDefinition
44
+ 'method_declaration',
45
+ 'class_declaration',
46
+ 'interface_declaration',
47
+ 'struct_declaration',
48
+ 'enum_declaration',
49
+ 'constructor_declaration',
50
+ 'record_declaration',
51
+ 'delegate_declaration',
52
+ // tryExtractCallName (invocation + object_creation)
53
+ 'invocation_expression',
54
+ 'object_creation_expression',
55
+ // tryExtractImport
56
+ 'using_directive',
57
+ ] as const;
58
+
59
+ export const csharpExtractor: LanguageExtractor = {
60
+ languageName: 'csharp',
61
+ extensions: ['.cs'],
62
+ branchNodeTypes: CS_BRANCH_NODES,
63
+ nestingNodeTypes: CS_NESTING_NODES,
64
+ candidateNodeTypes: CS_CANDIDATE_NODE_TYPES,
65
+
66
+ tryExtractDefinition(node: Parser.SyntaxNode): SymbolDef | null {
67
+ switch (node.type) {
68
+ case 'method_declaration': {
69
+ const nameNode = node.childForFieldName('name');
70
+ if (!nameNode) return null;
71
+ return mkDef(nameNode.text, 'method', node);
72
+ }
73
+
74
+ case 'class_declaration': {
75
+ const nameNode = node.childForFieldName('name');
76
+ if (!nameNode) return null;
77
+ return mkDef(nameNode.text, 'class', node);
78
+ }
79
+
80
+ case 'interface_declaration': {
81
+ const nameNode = node.childForFieldName('name');
82
+ if (!nameNode) return null;
83
+ return mkDef(nameNode.text, 'interface', node);
84
+ }
85
+
86
+ case 'struct_declaration': {
87
+ const nameNode = node.childForFieldName('name');
88
+ if (!nameNode) return null;
89
+ return mkDef(nameNode.text, 'struct', node);
90
+ }
91
+
92
+ case 'enum_declaration': {
93
+ const nameNode = node.childForFieldName('name');
94
+ if (!nameNode) return null;
95
+ return mkDef(nameNode.text, 'enum', node);
96
+ }
97
+
98
+ case 'constructor_declaration': {
99
+ const nameNode = node.childForFieldName('name');
100
+ if (!nameNode) return null;
101
+ return mkDef(nameNode.text, 'constructor', node);
102
+ }
103
+
104
+ // record Foo(int X, string Y); — a C# 9+ record (acts like a class)
105
+ case 'record_declaration': {
106
+ const nameNode = node.childForFieldName('name');
107
+ if (!nameNode) return null;
108
+ return mkDef(nameNode.text, 'class', node);
109
+ }
110
+
111
+ // delegate void Foo(int x); — captured as a `type` symbol
112
+ case 'delegate_declaration': {
113
+ const nameNode = node.childForFieldName('name');
114
+ if (!nameNode) return null;
115
+ return mkDef(nameNode.text, 'type', node);
116
+ }
117
+
118
+ default:
119
+ return null;
120
+ }
121
+ },
122
+
123
+ tryExtractCallName(node: Parser.SyntaxNode): string | null {
124
+ // foo() or obj.method()
125
+ if (node.type === 'invocation_expression') {
126
+ const funcNode = node.childForFieldName('function');
127
+ if (!funcNode) return null;
128
+ if (funcNode.type === 'identifier') return funcNode.text;
129
+ if (funcNode.type === 'member_access_expression') {
130
+ return funcNode.childForFieldName('name')?.text ?? null;
131
+ }
132
+ // generic call: foo<int>() parses as invocation_expression whose
133
+ // function is `generic_name`
134
+ if (funcNode.type === 'generic_name') {
135
+ return funcNode.childForFieldName('name')?.text
136
+ ?? funcNode.namedChildren[0]?.text
137
+ ?? null;
138
+ }
139
+ return null;
140
+ }
141
+
142
+ // new Foo() — count as a call to Foo
143
+ if (node.type === 'object_creation_expression') {
144
+ const typeNode = node.childForFieldName('type');
145
+ if (!typeNode) return null;
146
+ if (typeNode.type === 'identifier') return typeNode.text;
147
+ if (typeNode.type === 'generic_name') {
148
+ return typeNode.childForFieldName('name')?.text
149
+ ?? typeNode.namedChildren[0]?.text
150
+ ?? null;
151
+ }
152
+ if (typeNode.type === 'qualified_name') {
153
+ // ns.Class → Class
154
+ return typeNode.childForFieldName('name')?.text ?? null;
155
+ }
156
+ return null;
157
+ }
158
+
159
+ return null;
160
+ },
161
+
162
+ tryExtractImport(node: Parser.SyntaxNode): string | null {
163
+ // using System; or using System.Collections.Generic;
164
+ if (node.type === 'using_directive') {
165
+ // The grammar stores the imported namespace as a child (qualified_name
166
+ // or identifier). The `name` field isn't always set, so scan children.
167
+ for (const child of node.namedChildren) {
168
+ if (child.type === 'qualified_name' || child.type === 'identifier') {
169
+ return child.text;
170
+ }
171
+ }
172
+ }
173
+ return null;
174
+ },
175
+
176
+ /**
177
+ * C# HttpClient calls: client.GetAsync("/api/x"), httpClient.PostAsJsonAsync(url, body).
178
+ * The first string-literal arg is taken as the URL.
179
+ */
180
+ tryExtractServiceCalls(node: Parser.SyntaxNode): ServiceCallDef[] | null {
181
+ if (node.type !== 'invocation_expression') return null;
182
+ const fn = node.childForFieldName('function');
183
+ if (!fn || fn.type !== 'member_access_expression') return null;
184
+ const name = fn.childForFieldName('name')?.text;
185
+ if (!name) return null;
186
+ const verb = CS_HTTP_CLIENT_METHODS.get(name);
187
+ if (!verb) return null;
188
+
189
+ const args = node.childForFieldName('arguments');
190
+ if (!args) return null;
191
+ // arguments → argument_list with `argument` children, each wrapping an expr.
192
+ let first: Parser.SyntaxNode | null = null;
193
+ for (const a of args.namedChildren) {
194
+ if (a.type === 'argument') {
195
+ first = a.namedChildren[0];
196
+ break;
197
+ }
198
+ first = a; break;
199
+ }
200
+ if (!first) return null;
201
+ let raw: string | null = null;
202
+ if (first.type === 'string_literal' || first.type === 'verbatim_string_literal') {
203
+ raw = first.text.replace(/^@?["']|["']$/g, '');
204
+ } else if (first.type === 'interpolated_string_expression') {
205
+ // C# interpolated string $"…" — pick the literal_string parts.
206
+ let text = '';
207
+ for (const c of first.namedChildren) {
208
+ if (c.type === 'interpolated_string_text') text += c.text;
209
+ }
210
+ if (text) raw = text;
211
+ }
212
+ if (!raw || !csLooksLikeHttpTarget(raw)) return null;
213
+
214
+ return [{
215
+ protocol: 'http',
216
+ method: verb,
217
+ rawTarget: raw.slice(0, 240),
218
+ framework: 'HttpClient',
219
+ line: node.startPosition.row,
220
+ confidence: 0.85,
221
+ }];
222
+ },
223
+ };
224
+
225
+ function mkDef(name: string, kind: SymbolKind, node: Parser.SyntaxNode): SymbolDef {
226
+ return {
227
+ name,
228
+ kind,
229
+ lineStart: node.startPosition.row,
230
+ lineEnd: node.endPosition.row,
231
+ colStart: node.startPosition.column,
232
+ colEnd: node.endPosition.column,
233
+ signature: firstLine(node),
234
+ };
235
+ }