gitnexus 1.5.3 → 1.6.1

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 (304) hide show
  1. package/README.md +10 -0
  2. package/dist/_shared/graph/types.d.ts +1 -1
  3. package/dist/_shared/graph/types.d.ts.map +1 -1
  4. package/dist/_shared/index.d.ts +1 -0
  5. package/dist/_shared/index.d.ts.map +1 -1
  6. package/dist/_shared/language-detection.d.ts.map +1 -1
  7. package/dist/_shared/language-detection.js +2 -0
  8. package/dist/_shared/language-detection.js.map +1 -1
  9. package/dist/_shared/languages.d.ts +1 -0
  10. package/dist/_shared/languages.d.ts.map +1 -1
  11. package/dist/_shared/languages.js +1 -0
  12. package/dist/_shared/languages.js.map +1 -1
  13. package/dist/_shared/lbug/schema-constants.d.ts +1 -1
  14. package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
  15. package/dist/_shared/lbug/schema-constants.js +3 -1
  16. package/dist/_shared/lbug/schema-constants.js.map +1 -1
  17. package/dist/_shared/mro-strategy.d.ts +19 -0
  18. package/dist/_shared/mro-strategy.d.ts.map +1 -0
  19. package/dist/_shared/mro-strategy.js +2 -0
  20. package/dist/_shared/mro-strategy.js.map +1 -0
  21. package/dist/cli/ai-context.d.ts +1 -0
  22. package/dist/cli/ai-context.js +28 -4
  23. package/dist/cli/analyze.d.ts +2 -0
  24. package/dist/cli/analyze.js +30 -4
  25. package/dist/cli/group.d.ts +2 -0
  26. package/dist/cli/group.js +233 -0
  27. package/dist/cli/index.js +3 -0
  28. package/dist/cli/serve.js +4 -1
  29. package/dist/cli/setup.js +34 -3
  30. package/dist/config/ignore-service.js +8 -3
  31. package/dist/core/augmentation/engine.js +1 -1
  32. package/dist/core/git-staleness.d.ts +13 -0
  33. package/dist/core/git-staleness.js +29 -0
  34. package/dist/core/group/bridge-db.d.ts +82 -0
  35. package/dist/core/group/bridge-db.js +460 -0
  36. package/dist/core/group/bridge-schema.d.ts +27 -0
  37. package/dist/core/group/bridge-schema.js +55 -0
  38. package/dist/core/group/config-parser.d.ts +3 -0
  39. package/dist/core/group/config-parser.js +83 -0
  40. package/dist/core/group/contract-extractor.d.ts +7 -0
  41. package/dist/core/group/contract-extractor.js +1 -0
  42. package/dist/core/group/extractors/fs-utils.d.ts +10 -0
  43. package/dist/core/group/extractors/fs-utils.js +24 -0
  44. package/dist/core/group/extractors/grpc-extractor.d.ts +25 -0
  45. package/dist/core/group/extractors/grpc-extractor.js +386 -0
  46. package/dist/core/group/extractors/grpc-patterns/go.d.ts +2 -0
  47. package/dist/core/group/extractors/grpc-patterns/go.js +97 -0
  48. package/dist/core/group/extractors/grpc-patterns/index.d.ts +19 -0
  49. package/dist/core/group/extractors/grpc-patterns/index.js +46 -0
  50. package/dist/core/group/extractors/grpc-patterns/java.d.ts +2 -0
  51. package/dist/core/group/extractors/grpc-patterns/java.js +173 -0
  52. package/dist/core/group/extractors/grpc-patterns/node.d.ts +4 -0
  53. package/dist/core/group/extractors/grpc-patterns/node.js +290 -0
  54. package/dist/core/group/extractors/grpc-patterns/proto.d.ts +9 -0
  55. package/dist/core/group/extractors/grpc-patterns/proto.js +134 -0
  56. package/dist/core/group/extractors/grpc-patterns/python.d.ts +2 -0
  57. package/dist/core/group/extractors/grpc-patterns/python.js +67 -0
  58. package/dist/core/group/extractors/grpc-patterns/types.d.ts +50 -0
  59. package/dist/core/group/extractors/grpc-patterns/types.js +1 -0
  60. package/dist/core/group/extractors/http-patterns/go.d.ts +2 -0
  61. package/dist/core/group/extractors/http-patterns/go.js +215 -0
  62. package/dist/core/group/extractors/http-patterns/index.d.ts +17 -0
  63. package/dist/core/group/extractors/http-patterns/index.js +44 -0
  64. package/dist/core/group/extractors/http-patterns/java.d.ts +2 -0
  65. package/dist/core/group/extractors/http-patterns/java.js +253 -0
  66. package/dist/core/group/extractors/http-patterns/node.d.ts +4 -0
  67. package/dist/core/group/extractors/http-patterns/node.js +354 -0
  68. package/dist/core/group/extractors/http-patterns/php.d.ts +2 -0
  69. package/dist/core/group/extractors/http-patterns/php.js +70 -0
  70. package/dist/core/group/extractors/http-patterns/python.d.ts +2 -0
  71. package/dist/core/group/extractors/http-patterns/python.js +133 -0
  72. package/dist/core/group/extractors/http-patterns/types.d.ts +61 -0
  73. package/dist/core/group/extractors/http-patterns/types.js +1 -0
  74. package/dist/core/group/extractors/http-route-extractor.d.ts +21 -0
  75. package/dist/core/group/extractors/http-route-extractor.js +391 -0
  76. package/dist/core/group/extractors/manifest-extractor.d.ts +54 -0
  77. package/dist/core/group/extractors/manifest-extractor.js +235 -0
  78. package/dist/core/group/extractors/topic-extractor.d.ts +8 -0
  79. package/dist/core/group/extractors/topic-extractor.js +97 -0
  80. package/dist/core/group/extractors/topic-patterns/go.d.ts +2 -0
  81. package/dist/core/group/extractors/topic-patterns/go.js +120 -0
  82. package/dist/core/group/extractors/topic-patterns/index.d.ts +14 -0
  83. package/dist/core/group/extractors/topic-patterns/index.js +38 -0
  84. package/dist/core/group/extractors/topic-patterns/java.d.ts +2 -0
  85. package/dist/core/group/extractors/topic-patterns/java.js +80 -0
  86. package/dist/core/group/extractors/topic-patterns/node.d.ts +4 -0
  87. package/dist/core/group/extractors/topic-patterns/node.js +155 -0
  88. package/dist/core/group/extractors/topic-patterns/python.d.ts +2 -0
  89. package/dist/core/group/extractors/topic-patterns/python.js +116 -0
  90. package/dist/core/group/extractors/topic-patterns/types.d.ts +25 -0
  91. package/dist/core/group/extractors/topic-patterns/types.js +10 -0
  92. package/dist/core/group/extractors/tree-sitter-scanner.d.ts +113 -0
  93. package/dist/core/group/extractors/tree-sitter-scanner.js +94 -0
  94. package/dist/core/group/matching.d.ts +13 -0
  95. package/dist/core/group/matching.js +198 -0
  96. package/dist/core/group/normalization.d.ts +3 -0
  97. package/dist/core/group/normalization.js +115 -0
  98. package/dist/core/group/service-boundary-detector.d.ts +8 -0
  99. package/dist/core/group/service-boundary-detector.js +155 -0
  100. package/dist/core/group/service.d.ts +46 -0
  101. package/dist/core/group/service.js +160 -0
  102. package/dist/core/group/storage.d.ts +9 -0
  103. package/dist/core/group/storage.js +91 -0
  104. package/dist/core/group/sync.d.ts +21 -0
  105. package/dist/core/group/sync.js +148 -0
  106. package/dist/core/group/types.d.ts +130 -0
  107. package/dist/core/group/types.js +1 -0
  108. package/dist/core/ingestion/binding-accumulator.d.ts +212 -0
  109. package/dist/core/ingestion/binding-accumulator.js +336 -0
  110. package/dist/core/ingestion/call-processor.d.ts +155 -24
  111. package/dist/core/ingestion/call-processor.js +1129 -247
  112. package/dist/core/ingestion/class-extractors/generic.d.ts +2 -0
  113. package/dist/core/ingestion/class-extractors/generic.js +135 -0
  114. package/dist/core/ingestion/class-types.d.ts +34 -0
  115. package/dist/core/ingestion/class-types.js +1 -0
  116. package/dist/core/ingestion/cobol-processor.d.ts +1 -1
  117. package/dist/core/ingestion/entry-point-scoring.d.ts +1 -0
  118. package/dist/core/ingestion/entry-point-scoring.js +1 -0
  119. package/dist/core/ingestion/field-types.d.ts +2 -2
  120. package/dist/core/ingestion/filesystem-walker.js +8 -0
  121. package/dist/core/ingestion/framework-detection.d.ts +1 -0
  122. package/dist/core/ingestion/framework-detection.js +1 -0
  123. package/dist/core/ingestion/heritage-processor.d.ts +8 -15
  124. package/dist/core/ingestion/heritage-processor.js +15 -28
  125. package/dist/core/ingestion/import-processor.d.ts +1 -11
  126. package/dist/core/ingestion/import-processor.js +1 -13
  127. package/dist/core/ingestion/import-resolvers/utils.js +1 -0
  128. package/dist/core/ingestion/import-resolvers/vue.d.ts +8 -0
  129. package/dist/core/ingestion/import-resolvers/vue.js +9 -0
  130. package/dist/core/ingestion/language-config.js +1 -1
  131. package/dist/core/ingestion/language-provider.d.ts +14 -3
  132. package/dist/core/ingestion/languages/c-cpp.js +168 -1
  133. package/dist/core/ingestion/languages/csharp.js +20 -0
  134. package/dist/core/ingestion/languages/dart.js +26 -4
  135. package/dist/core/ingestion/languages/go.js +22 -0
  136. package/dist/core/ingestion/languages/index.d.ts +1 -0
  137. package/dist/core/ingestion/languages/index.js +2 -0
  138. package/dist/core/ingestion/languages/java.js +17 -0
  139. package/dist/core/ingestion/languages/kotlin.js +24 -1
  140. package/dist/core/ingestion/languages/php.js +23 -11
  141. package/dist/core/ingestion/languages/python.js +9 -0
  142. package/dist/core/ingestion/languages/ruby.js +43 -0
  143. package/dist/core/ingestion/languages/rust.js +38 -0
  144. package/dist/core/ingestion/languages/swift.js +31 -0
  145. package/dist/core/ingestion/languages/typescript.d.ts +1 -0
  146. package/dist/core/ingestion/languages/typescript.js +52 -3
  147. package/dist/core/ingestion/languages/vue.d.ts +13 -0
  148. package/dist/core/ingestion/languages/vue.js +81 -0
  149. package/dist/core/ingestion/markdown-processor.d.ts +1 -1
  150. package/dist/core/ingestion/method-extractors/configs/c-cpp.d.ts +3 -0
  151. package/dist/core/ingestion/method-extractors/configs/c-cpp.js +387 -0
  152. package/dist/core/ingestion/method-extractors/configs/csharp.js +5 -1
  153. package/dist/core/ingestion/method-extractors/configs/dart.d.ts +2 -0
  154. package/dist/core/ingestion/method-extractors/configs/dart.js +376 -0
  155. package/dist/core/ingestion/method-extractors/configs/go.d.ts +2 -0
  156. package/dist/core/ingestion/method-extractors/configs/go.js +176 -0
  157. package/dist/core/ingestion/method-extractors/configs/jvm.js +14 -4
  158. package/dist/core/ingestion/method-extractors/configs/php.d.ts +2 -0
  159. package/dist/core/ingestion/method-extractors/configs/php.js +304 -0
  160. package/dist/core/ingestion/method-extractors/configs/python.d.ts +2 -0
  161. package/dist/core/ingestion/method-extractors/configs/python.js +309 -0
  162. package/dist/core/ingestion/method-extractors/configs/ruby.d.ts +2 -0
  163. package/dist/core/ingestion/method-extractors/configs/ruby.js +286 -0
  164. package/dist/core/ingestion/method-extractors/configs/rust.d.ts +2 -0
  165. package/dist/core/ingestion/method-extractors/configs/rust.js +195 -0
  166. package/dist/core/ingestion/method-extractors/configs/swift.d.ts +2 -0
  167. package/dist/core/ingestion/method-extractors/configs/swift.js +277 -0
  168. package/dist/core/ingestion/method-extractors/configs/typescript-javascript.js +85 -8
  169. package/dist/core/ingestion/method-extractors/generic.d.ts +6 -0
  170. package/dist/core/ingestion/method-extractors/generic.js +84 -17
  171. package/dist/core/ingestion/method-types.d.ts +29 -0
  172. package/dist/core/ingestion/model/field-registry.d.ts +18 -0
  173. package/dist/core/ingestion/model/field-registry.js +22 -0
  174. package/dist/core/ingestion/model/heritage-map.d.ts +70 -0
  175. package/dist/core/ingestion/model/heritage-map.js +159 -0
  176. package/dist/core/ingestion/model/index.d.ts +20 -0
  177. package/dist/core/ingestion/model/index.js +41 -0
  178. package/dist/core/ingestion/model/method-registry.d.ts +62 -0
  179. package/dist/core/ingestion/model/method-registry.js +130 -0
  180. package/dist/core/ingestion/model/registration-table.d.ts +139 -0
  181. package/dist/core/ingestion/model/registration-table.js +224 -0
  182. package/dist/core/ingestion/model/resolution-context.d.ts +93 -0
  183. package/dist/core/ingestion/model/resolution-context.js +337 -0
  184. package/dist/core/ingestion/model/resolve.d.ts +56 -0
  185. package/dist/core/ingestion/model/resolve.js +297 -0
  186. package/dist/core/ingestion/model/semantic-model.d.ts +86 -0
  187. package/dist/core/ingestion/model/semantic-model.js +120 -0
  188. package/dist/core/ingestion/model/symbol-table.d.ts +222 -0
  189. package/dist/core/ingestion/model/symbol-table.js +206 -0
  190. package/dist/core/ingestion/model/type-registry.d.ts +39 -0
  191. package/dist/core/ingestion/model/type-registry.js +62 -0
  192. package/dist/core/ingestion/mro-processor.d.ts +5 -4
  193. package/dist/core/ingestion/mro-processor.js +311 -107
  194. package/dist/core/ingestion/parsing-processor.d.ts +5 -4
  195. package/dist/core/ingestion/parsing-processor.js +224 -87
  196. package/dist/core/ingestion/pipeline-phases/cobol.d.ts +16 -0
  197. package/dist/core/ingestion/pipeline-phases/cobol.js +45 -0
  198. package/dist/core/ingestion/pipeline-phases/communities.d.ts +16 -0
  199. package/dist/core/ingestion/pipeline-phases/communities.js +62 -0
  200. package/dist/core/ingestion/pipeline-phases/cross-file-impl.d.ts +17 -0
  201. package/dist/core/ingestion/pipeline-phases/cross-file-impl.js +156 -0
  202. package/dist/core/ingestion/pipeline-phases/cross-file.d.ts +37 -0
  203. package/dist/core/ingestion/pipeline-phases/cross-file.js +63 -0
  204. package/dist/core/ingestion/pipeline-phases/index.d.ts +21 -0
  205. package/dist/core/ingestion/pipeline-phases/index.js +22 -0
  206. package/dist/core/ingestion/pipeline-phases/markdown.d.ts +17 -0
  207. package/dist/core/ingestion/pipeline-phases/markdown.js +33 -0
  208. package/dist/core/ingestion/pipeline-phases/mro.d.ts +18 -0
  209. package/dist/core/ingestion/pipeline-phases/mro.js +36 -0
  210. package/dist/core/ingestion/pipeline-phases/orm-extraction.d.ts +22 -0
  211. package/dist/core/ingestion/pipeline-phases/orm-extraction.js +92 -0
  212. package/dist/core/ingestion/pipeline-phases/orm.d.ts +15 -0
  213. package/dist/core/ingestion/pipeline-phases/orm.js +74 -0
  214. package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +47 -0
  215. package/dist/core/ingestion/pipeline-phases/parse-impl.js +437 -0
  216. package/dist/core/ingestion/pipeline-phases/parse.d.ts +49 -0
  217. package/dist/core/ingestion/pipeline-phases/parse.js +33 -0
  218. package/dist/core/ingestion/pipeline-phases/processes.d.ts +16 -0
  219. package/dist/core/ingestion/pipeline-phases/processes.js +143 -0
  220. package/dist/core/ingestion/pipeline-phases/routes.d.ts +21 -0
  221. package/dist/core/ingestion/pipeline-phases/routes.js +243 -0
  222. package/dist/core/ingestion/pipeline-phases/runner.d.ts +22 -0
  223. package/dist/core/ingestion/pipeline-phases/runner.js +203 -0
  224. package/dist/core/ingestion/pipeline-phases/scan.d.ts +21 -0
  225. package/dist/core/ingestion/pipeline-phases/scan.js +46 -0
  226. package/dist/core/ingestion/pipeline-phases/structure.d.ts +27 -0
  227. package/dist/core/ingestion/pipeline-phases/structure.js +35 -0
  228. package/dist/core/ingestion/pipeline-phases/tools.d.ts +20 -0
  229. package/dist/core/ingestion/pipeline-phases/tools.js +79 -0
  230. package/dist/core/ingestion/pipeline-phases/types.d.ts +79 -0
  231. package/dist/core/ingestion/pipeline-phases/types.js +37 -0
  232. package/dist/core/ingestion/pipeline-phases/wildcard-synthesis.d.ts +35 -0
  233. package/dist/core/ingestion/pipeline-phases/wildcard-synthesis.js +174 -0
  234. package/dist/core/ingestion/pipeline.d.ts +18 -10
  235. package/dist/core/ingestion/pipeline.js +66 -1410
  236. package/dist/core/ingestion/process-processor.js +1 -1
  237. package/dist/core/ingestion/tree-sitter-queries.d.ts +5 -5
  238. package/dist/core/ingestion/tree-sitter-queries.js +90 -0
  239. package/dist/core/ingestion/type-env.d.ts +15 -2
  240. package/dist/core/ingestion/type-env.js +163 -102
  241. package/dist/core/ingestion/type-extractors/csharp.js +17 -0
  242. package/dist/core/ingestion/type-extractors/jvm.js +11 -0
  243. package/dist/core/ingestion/type-extractors/php.js +0 -55
  244. package/dist/core/ingestion/type-extractors/ruby.js +0 -32
  245. package/dist/core/ingestion/type-extractors/swift.js +13 -0
  246. package/dist/core/ingestion/type-extractors/types.d.ts +8 -8
  247. package/dist/core/ingestion/type-extractors/typescript.js +66 -69
  248. package/dist/core/ingestion/utils/ast-helpers.d.ts +32 -44
  249. package/dist/core/ingestion/utils/ast-helpers.js +157 -573
  250. package/dist/core/ingestion/utils/env.d.ts +10 -0
  251. package/dist/core/ingestion/utils/env.js +10 -0
  252. package/dist/core/ingestion/utils/graph-sort.d.ts +58 -0
  253. package/dist/core/ingestion/utils/graph-sort.js +100 -0
  254. package/dist/core/ingestion/utils/method-props.d.ts +32 -0
  255. package/dist/core/ingestion/utils/method-props.js +147 -0
  256. package/dist/core/ingestion/vue-sfc-extractor.d.ts +44 -0
  257. package/dist/core/ingestion/vue-sfc-extractor.js +94 -0
  258. package/dist/core/ingestion/workers/parse-worker.d.ts +31 -19
  259. package/dist/core/ingestion/workers/parse-worker.js +469 -200
  260. package/dist/core/lbug/lbug-adapter.d.ts +6 -0
  261. package/dist/core/lbug/lbug-adapter.js +134 -27
  262. package/dist/core/lbug/pool-adapter.d.ts +76 -0
  263. package/dist/core/lbug/pool-adapter.js +522 -0
  264. package/dist/core/run-analyze.d.ts +2 -0
  265. package/dist/core/run-analyze.js +1 -1
  266. package/dist/core/search/bm25-index.js +1 -1
  267. package/dist/core/tree-sitter/parser-loader.js +1 -0
  268. package/dist/core/wiki/graph-queries.js +1 -1
  269. package/dist/mcp/core/embedder.js +6 -5
  270. package/dist/mcp/core/lbug-adapter.d.ts +3 -63
  271. package/dist/mcp/core/lbug-adapter.js +3 -484
  272. package/dist/mcp/local/local-backend.d.ts +31 -2
  273. package/dist/mcp/local/local-backend.js +255 -46
  274. package/dist/mcp/resources.js +5 -4
  275. package/dist/mcp/staleness.d.ts +3 -13
  276. package/dist/mcp/staleness.js +2 -31
  277. package/dist/mcp/tools.js +80 -4
  278. package/dist/server/analyze-job.d.ts +2 -0
  279. package/dist/server/analyze-job.js +4 -0
  280. package/dist/server/api.d.ts +20 -1
  281. package/dist/server/api.js +306 -71
  282. package/dist/server/git-clone.d.ts +2 -1
  283. package/dist/server/git-clone.js +98 -5
  284. package/dist/storage/git.d.ts +13 -0
  285. package/dist/storage/git.js +25 -0
  286. package/dist/storage/repo-manager.js +1 -1
  287. package/package.json +9 -3
  288. package/scripts/patch-tree-sitter-swift.cjs +78 -0
  289. package/vendor/tree-sitter-proto/binding.gyp +30 -0
  290. package/vendor/tree-sitter-proto/bindings/node/binding.cc +20 -0
  291. package/vendor/tree-sitter-proto/bindings/node/index.d.ts +28 -0
  292. package/vendor/tree-sitter-proto/bindings/node/index.js +7 -0
  293. package/vendor/tree-sitter-proto/package.json +18 -0
  294. package/vendor/tree-sitter-proto/src/node-types.json +1145 -0
  295. package/vendor/tree-sitter-proto/src/parser.c +10149 -0
  296. package/vendor/tree-sitter-proto/src/tree_sitter/alloc.h +54 -0
  297. package/vendor/tree-sitter-proto/src/tree_sitter/array.h +291 -0
  298. package/vendor/tree-sitter-proto/src/tree_sitter/parser.h +266 -0
  299. package/dist/core/ingestion/named-binding-processor.d.ts +0 -18
  300. package/dist/core/ingestion/named-binding-processor.js +0 -42
  301. package/dist/core/ingestion/resolution-context.d.ts +0 -58
  302. package/dist/core/ingestion/resolution-context.js +0 -135
  303. package/dist/core/ingestion/symbol-table.d.ts +0 -79
  304. package/dist/core/ingestion/symbol-table.js +0 -115
@@ -0,0 +1,253 @@
1
+ import Java from 'tree-sitter-java';
2
+ import { compilePatterns, runCompiledPatterns, unquoteLiteral, } from '../tree-sitter-scanner.js';
3
+ /**
4
+ * Java HTTP plugin. Handles:
5
+ * - Spring `@RequestMapping` class prefixes + `@(Get|Post|...)Mapping` method annotations
6
+ * - Spring `RestTemplate.getForObject/...`, `WebClient.method(HttpMethod.X, ...)`
7
+ * - OkHttp `new Request.Builder().url("...")`
8
+ *
9
+ * The plugin runs two pattern bundles: one to collect class-level
10
+ * `@RequestMapping` prefixes keyed by the enclosing class node, and a
11
+ * second to match method-level annotations. The `scan` function walks
12
+ * up from each matched annotation to find its enclosing class and
13
+ * combines the prefix with the method path.
14
+ */
15
+ const METHOD_ANNOTATION_TO_HTTP = {
16
+ GetMapping: 'GET',
17
+ PostMapping: 'POST',
18
+ PutMapping: 'PUT',
19
+ DeleteMapping: 'DELETE',
20
+ PatchMapping: 'PATCH',
21
+ };
22
+ // ─── Provider: Spring class-level @RequestMapping prefix ──────────────
23
+ const SPRING_CLASS_PREFIX_PATTERNS = compilePatterns({
24
+ name: 'java-spring-class-prefix',
25
+ language: Java,
26
+ patterns: [
27
+ {
28
+ meta: {},
29
+ query: `
30
+ (class_declaration
31
+ (modifiers
32
+ (annotation
33
+ name: (identifier) @ann (#eq? @ann "RequestMapping")
34
+ arguments: (annotation_argument_list (string_literal) @prefix)))) @class
35
+ `,
36
+ },
37
+ ],
38
+ });
39
+ // ─── Provider: Spring @(Get|Post|...)Mapping method annotations ───────
40
+ const SPRING_METHOD_ROUTE_PATTERNS = compilePatterns({
41
+ name: 'java-spring-method-route',
42
+ language: Java,
43
+ patterns: [
44
+ {
45
+ meta: {},
46
+ query: `
47
+ (method_declaration
48
+ (modifiers
49
+ (annotation
50
+ name: (identifier) @ann (#match? @ann "^(Get|Post|Put|Delete|Patch)Mapping$")
51
+ arguments: (annotation_argument_list (string_literal) @path)))
52
+ name: (identifier) @method_name) @method
53
+ `,
54
+ },
55
+ ],
56
+ });
57
+ // ─── Consumer: Spring RestTemplate (object-named + method-named) ──────
58
+ // RestTemplate.getForObject / getForEntity → GET
59
+ // RestTemplate.postForObject / postForEntity → POST
60
+ // RestTemplate.put → PUT
61
+ // RestTemplate.delete → DELETE
62
+ // RestTemplate.patchForObject → PATCH
63
+ const REST_TEMPLATE_TO_HTTP = {
64
+ getForObject: 'GET',
65
+ getForEntity: 'GET',
66
+ postForObject: 'POST',
67
+ postForEntity: 'POST',
68
+ put: 'PUT',
69
+ delete: 'DELETE',
70
+ patchForObject: 'PATCH',
71
+ };
72
+ const REST_TEMPLATE_PATTERNS = compilePatterns({
73
+ name: 'java-rest-template',
74
+ language: Java,
75
+ patterns: [
76
+ {
77
+ meta: { framework: 'spring-rest-template' },
78
+ query: `
79
+ (method_invocation
80
+ object: (identifier) @obj (#eq? @obj "restTemplate")
81
+ name: (identifier) @method
82
+ arguments: (argument_list . (string_literal) @path))
83
+ `,
84
+ },
85
+ ],
86
+ });
87
+ // ─── Consumer: Spring WebClient — webClient.method(HttpMethod.X, "path") ─
88
+ const WEB_CLIENT_PATTERNS = compilePatterns({
89
+ name: 'java-web-client',
90
+ language: Java,
91
+ patterns: [
92
+ {
93
+ meta: {},
94
+ query: `
95
+ (method_invocation
96
+ object: (identifier) @obj (#eq? @obj "webClient")
97
+ name: (identifier) @method (#eq? @method "method")
98
+ arguments: (argument_list
99
+ (field_access
100
+ object: (identifier) @httpMethodCls (#eq? @httpMethodCls "HttpMethod")
101
+ field: (identifier) @http_method)
102
+ (string_literal) @path))
103
+ `,
104
+ },
105
+ ],
106
+ });
107
+ // ─── Consumer: OkHttp `new Request.Builder().url("path")` ─────────────
108
+ // Note: `Request.Builder` is a `scoped_type_identifier` whose text includes
109
+ // the dot, so `#eq?` against the literal string matches cleanly (no need
110
+ // to escape a regex dot).
111
+ const OK_HTTP_PATTERNS = compilePatterns({
112
+ name: 'java-okhttp',
113
+ language: Java,
114
+ patterns: [
115
+ {
116
+ meta: {},
117
+ query: `
118
+ (method_invocation
119
+ object: (object_creation_expression
120
+ type: (scoped_type_identifier) @type (#eq? @type "Request.Builder"))
121
+ name: (identifier) @method (#eq? @method "url")
122
+ arguments: (argument_list . (string_literal) @path))
123
+ `,
124
+ },
125
+ ],
126
+ });
127
+ /**
128
+ * Find the nearest enclosing class_declaration ancestor for a node, or
129
+ * null if the node is top-level. Tree-sitter's SyntaxNode.parent walks
130
+ * one level at a time.
131
+ */
132
+ function findEnclosingClass(node) {
133
+ let cur = node.parent;
134
+ while (cur) {
135
+ if (cur.type === 'class_declaration')
136
+ return cur;
137
+ cur = cur.parent;
138
+ }
139
+ return null;
140
+ }
141
+ /**
142
+ * Join a class-level prefix and a method-level path into a single URL
143
+ * path. Mirrors the semantics of the original regex implementation:
144
+ * strip trailing slashes on the prefix, then ensure a single slash
145
+ * between prefix and method path.
146
+ */
147
+ function joinPath(prefix, methodPath) {
148
+ const cleanPrefix = prefix.replace(/^\/+/, '').replace(/\/+$/, '');
149
+ const cleanSub = methodPath.replace(/^\/+/, '');
150
+ if (!cleanPrefix)
151
+ return `/${cleanSub}`;
152
+ return `/${cleanPrefix}/${cleanSub}`;
153
+ }
154
+ export const JAVA_HTTP_PLUGIN = {
155
+ name: 'java-http',
156
+ language: Java,
157
+ scan(tree) {
158
+ const out = [];
159
+ // ─── Providers: Spring class prefix + method annotations ────────
160
+ const prefixByClassId = new Map();
161
+ for (const match of runCompiledPatterns(SPRING_CLASS_PREFIX_PATTERNS, tree)) {
162
+ const prefixNode = match.captures.prefix;
163
+ const classNode = match.captures.class;
164
+ if (!prefixNode || !classNode)
165
+ continue;
166
+ const prefix = unquoteLiteral(prefixNode.text);
167
+ if (prefix !== null)
168
+ prefixByClassId.set(classNode.id, prefix);
169
+ }
170
+ for (const match of runCompiledPatterns(SPRING_METHOD_ROUTE_PATTERNS, tree)) {
171
+ const annNode = match.captures.ann;
172
+ const pathNode = match.captures.path;
173
+ const nameNode = match.captures.method_name;
174
+ const methodNode = match.captures.method;
175
+ if (!annNode || !pathNode || !methodNode)
176
+ continue;
177
+ const httpMethod = METHOD_ANNOTATION_TO_HTTP[annNode.text];
178
+ if (!httpMethod)
179
+ continue;
180
+ const rawPath = unquoteLiteral(pathNode.text);
181
+ if (rawPath === null)
182
+ continue;
183
+ const enclosingClass = findEnclosingClass(methodNode);
184
+ const prefix = enclosingClass ? (prefixByClassId.get(enclosingClass.id) ?? '') : '';
185
+ const fullPath = joinPath(prefix, rawPath);
186
+ out.push({
187
+ role: 'provider',
188
+ framework: 'spring',
189
+ method: httpMethod,
190
+ path: fullPath,
191
+ name: nameNode?.text ?? null,
192
+ confidence: 0.8,
193
+ });
194
+ }
195
+ // ─── Consumers: RestTemplate ────────────────────────────────────
196
+ for (const match of runCompiledPatterns(REST_TEMPLATE_PATTERNS, tree)) {
197
+ const methodNode = match.captures.method;
198
+ const pathNode = match.captures.path;
199
+ if (!methodNode || !pathNode)
200
+ continue;
201
+ const httpMethod = REST_TEMPLATE_TO_HTTP[methodNode.text];
202
+ if (!httpMethod)
203
+ continue;
204
+ const path = unquoteLiteral(pathNode.text);
205
+ if (path === null)
206
+ continue;
207
+ out.push({
208
+ role: 'consumer',
209
+ framework: 'spring-rest-template',
210
+ method: httpMethod,
211
+ path,
212
+ name: null,
213
+ confidence: 0.7,
214
+ });
215
+ }
216
+ // ─── Consumers: WebClient.method(HttpMethod.X, "path") ──────────
217
+ for (const match of runCompiledPatterns(WEB_CLIENT_PATTERNS, tree)) {
218
+ const httpMethodNode = match.captures.http_method;
219
+ const pathNode = match.captures.path;
220
+ if (!httpMethodNode || !pathNode)
221
+ continue;
222
+ const path = unquoteLiteral(pathNode.text);
223
+ if (path === null)
224
+ continue;
225
+ out.push({
226
+ role: 'consumer',
227
+ framework: 'spring-web-client',
228
+ method: httpMethodNode.text.toUpperCase(),
229
+ path,
230
+ name: null,
231
+ confidence: 0.7,
232
+ });
233
+ }
234
+ // ─── Consumers: OkHttp Request.Builder().url("path") ────────────
235
+ for (const match of runCompiledPatterns(OK_HTTP_PATTERNS, tree)) {
236
+ const pathNode = match.captures.path;
237
+ if (!pathNode)
238
+ continue;
239
+ const path = unquoteLiteral(pathNode.text);
240
+ if (path === null)
241
+ continue;
242
+ out.push({
243
+ role: 'consumer',
244
+ framework: 'okhttp',
245
+ method: 'GET',
246
+ path,
247
+ name: null,
248
+ confidence: 0.7,
249
+ });
250
+ }
251
+ return out;
252
+ },
253
+ };
@@ -0,0 +1,4 @@
1
+ import type { HttpLanguagePlugin } from './types.js';
2
+ export declare const JAVASCRIPT_HTTP_PLUGIN: HttpLanguagePlugin;
3
+ export declare const TYPESCRIPT_HTTP_PLUGIN: HttpLanguagePlugin;
4
+ export declare const TSX_HTTP_PLUGIN: HttpLanguagePlugin;
@@ -0,0 +1,354 @@
1
+ import JavaScript from 'tree-sitter-javascript';
2
+ import TypeScript from 'tree-sitter-typescript';
3
+ import { compilePatterns, runCompiledPatterns, unquoteLiteral, } from '../tree-sitter-scanner.js';
4
+ /**
5
+ * Node.js / TypeScript HTTP plugin family. Handles:
6
+ * - NestJS `@Controller('prefix')` classes with `@Get(':id')` methods
7
+ * - Express `router.get(...)` / `app.post(...)` providers
8
+ * - `fetch(url)` / `fetch(url, { method: 'POST' })` consumers
9
+ * - `axios.get(url)` / `axios.delete(url)` consumers
10
+ *
11
+ * Because the JavaScript and TypeScript tree-sitter grammars share
12
+ * node type names for every construct we query, pattern sources are
13
+ * defined once and compiled against each grammar variant. The plugin
14
+ * exports three `HttpLanguagePlugin`s (JS, TS, TSX) that share the
15
+ * same `scan` function but bind to different grammars.
16
+ */
17
+ // ─── Provider: NestJS — class-level @Controller('prefix') ────────────
18
+ // In tree-sitter-typescript decorators are NOT children of
19
+ // class_declaration / method_definition — they're siblings in the
20
+ // surrounding class_body / program node. We therefore match the
21
+ // decorator standalone and walk to its related class/method in JS.
22
+ const NEST_CONTROLLER_SPEC = {
23
+ meta: {},
24
+ query: `
25
+ (decorator
26
+ (call_expression
27
+ function: (identifier) @dec (#eq? @dec "Controller")
28
+ arguments: (arguments . [(string) (template_string)] @prefix))) @ctrl_decorator
29
+ `,
30
+ };
31
+ // ─── Provider: NestJS — method-level @Get/@Post/... decorators ───────
32
+ // Matches either `@Get('path')` or `@Get()`. The `@path` capture is
33
+ // optional — when the first argument isn't a string, the plugin falls
34
+ // back to '/' for the method-level path.
35
+ const NEST_METHOD_SPEC = {
36
+ meta: {},
37
+ query: `
38
+ (decorator
39
+ (call_expression
40
+ function: (identifier) @dec (#match? @dec "^(Get|Post|Put|Delete|Patch)$")
41
+ arguments: (arguments) @args)) @method_decorator
42
+ `,
43
+ };
44
+ // ─── Provider: Express — router.get/app.post/... ─────────────────────
45
+ const EXPRESS_SPEC = {
46
+ meta: {},
47
+ query: `
48
+ (call_expression
49
+ function: (member_expression
50
+ object: (identifier) @obj (#match? @obj "^(router|app)$")
51
+ property: (property_identifier) @http_method (#match? @http_method "^(get|post|put|delete|patch)$"))
52
+ arguments: (arguments . [(string) (template_string)] @path))
53
+ `,
54
+ };
55
+ // ─── Consumer: fetch(url) with NO options ─────────────────────────────
56
+ const FETCH_NO_OPTIONS_SPEC = {
57
+ meta: {},
58
+ query: `
59
+ (call_expression
60
+ function: (identifier) @fn (#eq? @fn "fetch")
61
+ arguments: (arguments . [(string) (template_string)] @path .))
62
+ `,
63
+ };
64
+ // ─── Consumer: fetch(url, { method: 'X', ... }) ──────────────────────
65
+ const FETCH_WITH_OPTIONS_SPEC = {
66
+ meta: {},
67
+ query: `
68
+ (call_expression
69
+ function: (identifier) @fn (#eq? @fn "fetch")
70
+ arguments: (arguments
71
+ . [(string) (template_string)] @path
72
+ (object
73
+ (pair
74
+ key: (property_identifier) @key (#eq? @key "method")
75
+ value: (string) @http_method))))
76
+ `,
77
+ };
78
+ // ─── Consumer: axios.get/post/... ────────────────────────────────────
79
+ const AXIOS_SPEC = {
80
+ meta: {},
81
+ query: `
82
+ (call_expression
83
+ function: (member_expression
84
+ object: (identifier) @obj (#eq? @obj "axios")
85
+ property: (property_identifier) @http_method (#match? @http_method "^(get|post|put|delete|patch)$"))
86
+ arguments: (arguments . [(string) (template_string)] @path))
87
+ `,
88
+ };
89
+ function compileBundle(language, name) {
90
+ const mk = (spec, suffix) => compilePatterns({
91
+ name: `${name}-${suffix}`,
92
+ language,
93
+ patterns: [spec],
94
+ });
95
+ return {
96
+ controller: mk(NEST_CONTROLLER_SPEC, 'nest-controller'),
97
+ methodDecorator: mk(NEST_METHOD_SPEC, 'nest-method-decorator'),
98
+ express: mk(EXPRESS_SPEC, 'express'),
99
+ fetchNoOptions: mk(FETCH_NO_OPTIONS_SPEC, 'fetch-no-options'),
100
+ fetchWithOptions: mk(FETCH_WITH_OPTIONS_SPEC, 'fetch-with-options'),
101
+ axios: mk(AXIOS_SPEC, 'axios'),
102
+ };
103
+ }
104
+ const JAVASCRIPT_BUNDLE = compileBundle(JavaScript, 'javascript-http');
105
+ const TYPESCRIPT_BUNDLE = compileBundle(TypeScript.typescript, 'typescript-http');
106
+ const TSX_BUNDLE = compileBundle(TypeScript.tsx, 'tsx-http');
107
+ const NEST_DECORATOR_TO_HTTP = {
108
+ Get: 'GET',
109
+ Post: 'POST',
110
+ Put: 'PUT',
111
+ Delete: 'DELETE',
112
+ Patch: 'PATCH',
113
+ };
114
+ /**
115
+ * Find the nearest enclosing class_declaration for a node, or null.
116
+ */
117
+ function findEnclosingClass(node) {
118
+ let cur = node.parent;
119
+ while (cur) {
120
+ if (cur.type === 'class_declaration')
121
+ return cur;
122
+ cur = cur.parent;
123
+ }
124
+ return null;
125
+ }
126
+ function joinPath(prefix, sub) {
127
+ const cleanPrefix = prefix.replace(/^\/+/, '').replace(/\/+$/, '');
128
+ const cleanSub = sub.replace(/^\/+/, '');
129
+ if (!cleanPrefix)
130
+ return `/${cleanSub}`;
131
+ return `/${cleanPrefix}/${cleanSub}`;
132
+ }
133
+ /**
134
+ * For a standalone `decorator` node (child of class_body / program),
135
+ * find the related `class_declaration` node that it decorates. In
136
+ * tree-sitter-typescript the decorator is placed before the class
137
+ * declaration as a sibling (when decorating a class) or inside the
138
+ * class_body before a method_definition (when decorating a method);
139
+ * we walk the parent chain until we find the enclosing class.
140
+ */
141
+ function findDecoratedClass(decoratorNode) {
142
+ const parent = decoratorNode.parent;
143
+ if (!parent)
144
+ return null;
145
+ // Case 1: decorator is a sibling of the class_declaration at program /
146
+ // export_statement level. Walk forward through siblings until we find
147
+ // the class_declaration this decorator belongs to.
148
+ for (let i = 0; i < parent.namedChildCount; i++) {
149
+ const child = parent.namedChild(i);
150
+ if (child && child.id === decoratorNode.id) {
151
+ for (let j = i + 1; j < parent.namedChildCount; j++) {
152
+ const next = parent.namedChild(j);
153
+ if (!next)
154
+ continue;
155
+ if (next.type === 'decorator')
156
+ continue; // adjacent decorators stack
157
+ if (next.type === 'class_declaration')
158
+ return next;
159
+ if (next.type === 'export_statement') {
160
+ // `export class Foo { ... }` wraps the declaration.
161
+ for (let k = 0; k < next.namedChildCount; k++) {
162
+ const inner = next.namedChild(k);
163
+ if (inner?.type === 'class_declaration')
164
+ return inner;
165
+ }
166
+ }
167
+ break;
168
+ }
169
+ break;
170
+ }
171
+ }
172
+ // Case 2: decorator is inside a class_body (decorating a method) —
173
+ // walk up to the enclosing class_declaration.
174
+ return findEnclosingClass(decoratorNode);
175
+ }
176
+ /**
177
+ * For a method-level decorator node (child of class_body before a
178
+ * method_definition), find the method_definition it decorates.
179
+ */
180
+ function findDecoratedMethod(decoratorNode) {
181
+ const parent = decoratorNode.parent;
182
+ if (!parent || parent.type !== 'class_body')
183
+ return null;
184
+ for (let i = 0; i < parent.namedChildCount; i++) {
185
+ const child = parent.namedChild(i);
186
+ if (child && child.id === decoratorNode.id) {
187
+ for (let j = i + 1; j < parent.namedChildCount; j++) {
188
+ const next = parent.namedChild(j);
189
+ if (!next)
190
+ continue;
191
+ if (next.type === 'decorator')
192
+ continue;
193
+ if (next.type === 'method_definition')
194
+ return next;
195
+ return null;
196
+ }
197
+ return null;
198
+ }
199
+ }
200
+ return null;
201
+ }
202
+ function scanBundle(bundle, tree) {
203
+ const out = [];
204
+ // NestJS: collect `@Controller('prefix')` class decorators, keyed by
205
+ // the `class_declaration` they decorate.
206
+ const prefixByClassId = new Map();
207
+ for (const match of runCompiledPatterns(bundle.controller, tree)) {
208
+ const prefixNode = match.captures.prefix;
209
+ const decoratorNode = match.captures.ctrl_decorator;
210
+ if (!prefixNode || !decoratorNode)
211
+ continue;
212
+ const prefix = unquoteLiteral(prefixNode.text);
213
+ if (prefix === null)
214
+ continue;
215
+ const classNode = findDecoratedClass(decoratorNode);
216
+ if (!classNode)
217
+ continue;
218
+ prefixByClassId.set(classNode.id, prefix);
219
+ }
220
+ // NestJS: method-level @Get/@Post/... decorators. The decorator's
221
+ // arguments list may be empty (`@Get()`), a string (`@Get('path')`),
222
+ // or something else (which we skip).
223
+ for (const match of runCompiledPatterns(bundle.methodDecorator, tree)) {
224
+ const decNode = match.captures.dec;
225
+ const argsNode = match.captures.args;
226
+ const decoratorNode = match.captures.method_decorator;
227
+ if (!decNode || !argsNode || !decoratorNode)
228
+ continue;
229
+ const httpMethod = NEST_DECORATOR_TO_HTTP[decNode.text];
230
+ if (!httpMethod)
231
+ continue;
232
+ const methodNode = findDecoratedMethod(decoratorNode);
233
+ if (!methodNode)
234
+ continue;
235
+ const enclosingClass = findEnclosingClass(methodNode);
236
+ // Only emit NestJS detections when the class actually has a
237
+ // @Controller decorator — without it, the match is almost certainly
238
+ // something else (e.g. an unrelated library using similar names).
239
+ if (!enclosingClass || !prefixByClassId.has(enclosingClass.id))
240
+ continue;
241
+ const prefix = prefixByClassId.get(enclosingClass.id) ?? '';
242
+ let rawPath = '/';
243
+ const firstArg = argsNode.namedChild(0);
244
+ if (firstArg && (firstArg.type === 'string' || firstArg.type === 'template_string')) {
245
+ const unquoted = unquoteLiteral(firstArg.text);
246
+ if (unquoted !== null)
247
+ rawPath = unquoted;
248
+ }
249
+ // Get the method name from the decorated method_definition.
250
+ const methodNameNode = methodNode.childForFieldName('name');
251
+ const name = methodNameNode?.text ?? null;
252
+ out.push({
253
+ role: 'provider',
254
+ framework: 'nest',
255
+ method: httpMethod,
256
+ path: joinPath(prefix, rawPath),
257
+ name,
258
+ confidence: 0.8,
259
+ });
260
+ }
261
+ // Express: router/app.<verb>(...)
262
+ for (const match of runCompiledPatterns(bundle.express, tree)) {
263
+ const methodNode = match.captures.http_method;
264
+ const pathNode = match.captures.path;
265
+ if (!methodNode || !pathNode)
266
+ continue;
267
+ const path = unquoteLiteral(pathNode.text);
268
+ if (path === null)
269
+ continue;
270
+ out.push({
271
+ role: 'provider',
272
+ framework: 'express',
273
+ method: methodNode.text.toUpperCase(),
274
+ path,
275
+ name: 'handler',
276
+ confidence: 0.8,
277
+ });
278
+ }
279
+ // Consumer: fetch with options { method: 'X' }
280
+ const fetchSeen = new Set();
281
+ for (const match of runCompiledPatterns(bundle.fetchWithOptions, tree)) {
282
+ const pathNode = match.captures.path;
283
+ const methodNode = match.captures.http_method;
284
+ if (!pathNode || !methodNode)
285
+ continue;
286
+ const path = unquoteLiteral(pathNode.text);
287
+ const method = unquoteLiteral(methodNode.text);
288
+ if (path === null || method === null)
289
+ continue;
290
+ fetchSeen.add(pathNode.id);
291
+ out.push({
292
+ role: 'consumer',
293
+ framework: 'fetch',
294
+ method: method.toUpperCase(),
295
+ path,
296
+ name: null,
297
+ confidence: 0.7,
298
+ });
299
+ }
300
+ // Consumer: plain fetch(path) — default GET. Skip path nodes we already
301
+ // matched with the options variant so we don't double-emit.
302
+ for (const match of runCompiledPatterns(bundle.fetchNoOptions, tree)) {
303
+ const pathNode = match.captures.path;
304
+ if (!pathNode)
305
+ continue;
306
+ if (fetchSeen.has(pathNode.id))
307
+ continue;
308
+ const path = unquoteLiteral(pathNode.text);
309
+ if (path === null)
310
+ continue;
311
+ out.push({
312
+ role: 'consumer',
313
+ framework: 'fetch',
314
+ method: 'GET',
315
+ path,
316
+ name: null,
317
+ confidence: 0.7,
318
+ });
319
+ }
320
+ // Consumer: axios.<verb>(url)
321
+ for (const match of runCompiledPatterns(bundle.axios, tree)) {
322
+ const methodNode = match.captures.http_method;
323
+ const pathNode = match.captures.path;
324
+ if (!methodNode || !pathNode)
325
+ continue;
326
+ const path = unquoteLiteral(pathNode.text);
327
+ if (path === null)
328
+ continue;
329
+ out.push({
330
+ role: 'consumer',
331
+ framework: 'axios',
332
+ method: methodNode.text.toUpperCase(),
333
+ path,
334
+ name: null,
335
+ confidence: 0.7,
336
+ });
337
+ }
338
+ return out;
339
+ }
340
+ export const JAVASCRIPT_HTTP_PLUGIN = {
341
+ name: 'javascript-http',
342
+ language: JavaScript,
343
+ scan: (tree) => scanBundle(JAVASCRIPT_BUNDLE, tree),
344
+ };
345
+ export const TYPESCRIPT_HTTP_PLUGIN = {
346
+ name: 'typescript-http',
347
+ language: TypeScript.typescript,
348
+ scan: (tree) => scanBundle(TYPESCRIPT_BUNDLE, tree),
349
+ };
350
+ export const TSX_HTTP_PLUGIN = {
351
+ name: 'tsx-http',
352
+ language: TypeScript.tsx,
353
+ scan: (tree) => scanBundle(TSX_BUNDLE, tree),
354
+ };
@@ -0,0 +1,2 @@
1
+ import type { HttpLanguagePlugin } from './types.js';
2
+ export declare const PHP_HTTP_PLUGIN: HttpLanguagePlugin;
@@ -0,0 +1,70 @@
1
+ import PHP from 'tree-sitter-php';
2
+ import { compilePatterns, runCompiledPatterns, unquoteLiteral, } from '../tree-sitter-scanner.js';
3
+ /**
4
+ * PHP HTTP plugin — Laravel `Route::get/post/...` declarations.
5
+ *
6
+ * The pipeline already uses `PHP.php_only` for ingesting plain `.php`
7
+ * files (see `core/tree-sitter/parser-loader.ts`), and we do the same
8
+ * here so Laravel route files are parsed with the right grammar dialect.
9
+ */
10
+ const LARAVEL_PATTERNS = compilePatterns({
11
+ name: 'php-laravel',
12
+ language: PHP.php_only,
13
+ patterns: [
14
+ {
15
+ meta: {},
16
+ query: `
17
+ (scoped_call_expression
18
+ scope: (name) @scope (#eq? @scope "Route")
19
+ name: (name) @method (#match? @method "^(get|post|put|delete|patch)$")
20
+ arguments: (arguments . (argument (string) @path)))
21
+ `,
22
+ },
23
+ ],
24
+ });
25
+ /**
26
+ * Extract the inner text of a PHP `string` node. The tree-sitter-php
27
+ * grammar wraps single / double-quoted literals differently depending
28
+ * on content; we try both the raw `text` (with quotes) through
29
+ * `unquoteLiteral`, and a fallback via the `string_value` / `string_content`
30
+ * child nodes.
31
+ */
32
+ function phpStringText(node) {
33
+ // Most single-quoted strings expose their inner content through the
34
+ // full node text (including quotes), which unquoteLiteral strips.
35
+ const direct = unquoteLiteral(node.text);
36
+ if (direct !== null && direct !== node.text)
37
+ return direct;
38
+ // Fall back to child string_content / string_value node if present.
39
+ for (const child of node.children) {
40
+ if (child.type === 'string_content' || child.type === 'string_value') {
41
+ return child.text;
42
+ }
43
+ }
44
+ return direct;
45
+ }
46
+ export const PHP_HTTP_PLUGIN = {
47
+ name: 'php-http',
48
+ language: PHP.php_only,
49
+ scan(tree) {
50
+ const out = [];
51
+ for (const match of runCompiledPatterns(LARAVEL_PATTERNS, tree)) {
52
+ const methodNode = match.captures.method;
53
+ const pathNode = match.captures.path;
54
+ if (!methodNode || !pathNode)
55
+ continue;
56
+ const path = phpStringText(pathNode);
57
+ if (path === null)
58
+ continue;
59
+ out.push({
60
+ role: 'provider',
61
+ framework: 'laravel',
62
+ method: methodNode.text.toUpperCase(),
63
+ path,
64
+ name: 'route',
65
+ confidence: 0.8,
66
+ });
67
+ }
68
+ return out;
69
+ },
70
+ };
@@ -0,0 +1,2 @@
1
+ import type { HttpLanguagePlugin } from './types.js';
2
+ export declare const PYTHON_HTTP_PLUGIN: HttpLanguagePlugin;