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.
- package/README.md +10 -0
- package/dist/_shared/graph/types.d.ts +1 -1
- package/dist/_shared/graph/types.d.ts.map +1 -1
- package/dist/_shared/index.d.ts +1 -0
- package/dist/_shared/index.d.ts.map +1 -1
- package/dist/_shared/language-detection.d.ts.map +1 -1
- package/dist/_shared/language-detection.js +2 -0
- package/dist/_shared/language-detection.js.map +1 -1
- package/dist/_shared/languages.d.ts +1 -0
- package/dist/_shared/languages.d.ts.map +1 -1
- package/dist/_shared/languages.js +1 -0
- package/dist/_shared/languages.js.map +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
- package/dist/_shared/lbug/schema-constants.js +3 -1
- package/dist/_shared/lbug/schema-constants.js.map +1 -1
- package/dist/_shared/mro-strategy.d.ts +19 -0
- package/dist/_shared/mro-strategy.d.ts.map +1 -0
- package/dist/_shared/mro-strategy.js +2 -0
- package/dist/_shared/mro-strategy.js.map +1 -0
- package/dist/cli/ai-context.d.ts +1 -0
- package/dist/cli/ai-context.js +28 -4
- package/dist/cli/analyze.d.ts +2 -0
- package/dist/cli/analyze.js +30 -4
- package/dist/cli/group.d.ts +2 -0
- package/dist/cli/group.js +233 -0
- package/dist/cli/index.js +3 -0
- package/dist/cli/serve.js +4 -1
- package/dist/cli/setup.js +34 -3
- package/dist/config/ignore-service.js +8 -3
- package/dist/core/augmentation/engine.js +1 -1
- package/dist/core/git-staleness.d.ts +13 -0
- package/dist/core/git-staleness.js +29 -0
- package/dist/core/group/bridge-db.d.ts +82 -0
- package/dist/core/group/bridge-db.js +460 -0
- package/dist/core/group/bridge-schema.d.ts +27 -0
- package/dist/core/group/bridge-schema.js +55 -0
- package/dist/core/group/config-parser.d.ts +3 -0
- package/dist/core/group/config-parser.js +83 -0
- package/dist/core/group/contract-extractor.d.ts +7 -0
- package/dist/core/group/contract-extractor.js +1 -0
- package/dist/core/group/extractors/fs-utils.d.ts +10 -0
- package/dist/core/group/extractors/fs-utils.js +24 -0
- package/dist/core/group/extractors/grpc-extractor.d.ts +25 -0
- package/dist/core/group/extractors/grpc-extractor.js +386 -0
- package/dist/core/group/extractors/grpc-patterns/go.d.ts +2 -0
- package/dist/core/group/extractors/grpc-patterns/go.js +97 -0
- package/dist/core/group/extractors/grpc-patterns/index.d.ts +19 -0
- package/dist/core/group/extractors/grpc-patterns/index.js +46 -0
- package/dist/core/group/extractors/grpc-patterns/java.d.ts +2 -0
- package/dist/core/group/extractors/grpc-patterns/java.js +173 -0
- package/dist/core/group/extractors/grpc-patterns/node.d.ts +4 -0
- package/dist/core/group/extractors/grpc-patterns/node.js +290 -0
- package/dist/core/group/extractors/grpc-patterns/proto.d.ts +9 -0
- package/dist/core/group/extractors/grpc-patterns/proto.js +134 -0
- package/dist/core/group/extractors/grpc-patterns/python.d.ts +2 -0
- package/dist/core/group/extractors/grpc-patterns/python.js +67 -0
- package/dist/core/group/extractors/grpc-patterns/types.d.ts +50 -0
- package/dist/core/group/extractors/grpc-patterns/types.js +1 -0
- package/dist/core/group/extractors/http-patterns/go.d.ts +2 -0
- package/dist/core/group/extractors/http-patterns/go.js +215 -0
- package/dist/core/group/extractors/http-patterns/index.d.ts +17 -0
- package/dist/core/group/extractors/http-patterns/index.js +44 -0
- package/dist/core/group/extractors/http-patterns/java.d.ts +2 -0
- package/dist/core/group/extractors/http-patterns/java.js +253 -0
- package/dist/core/group/extractors/http-patterns/node.d.ts +4 -0
- package/dist/core/group/extractors/http-patterns/node.js +354 -0
- package/dist/core/group/extractors/http-patterns/php.d.ts +2 -0
- package/dist/core/group/extractors/http-patterns/php.js +70 -0
- package/dist/core/group/extractors/http-patterns/python.d.ts +2 -0
- package/dist/core/group/extractors/http-patterns/python.js +133 -0
- package/dist/core/group/extractors/http-patterns/types.d.ts +61 -0
- package/dist/core/group/extractors/http-patterns/types.js +1 -0
- package/dist/core/group/extractors/http-route-extractor.d.ts +21 -0
- package/dist/core/group/extractors/http-route-extractor.js +391 -0
- package/dist/core/group/extractors/manifest-extractor.d.ts +54 -0
- package/dist/core/group/extractors/manifest-extractor.js +235 -0
- package/dist/core/group/extractors/topic-extractor.d.ts +8 -0
- package/dist/core/group/extractors/topic-extractor.js +97 -0
- package/dist/core/group/extractors/topic-patterns/go.d.ts +2 -0
- package/dist/core/group/extractors/topic-patterns/go.js +120 -0
- package/dist/core/group/extractors/topic-patterns/index.d.ts +14 -0
- package/dist/core/group/extractors/topic-patterns/index.js +38 -0
- package/dist/core/group/extractors/topic-patterns/java.d.ts +2 -0
- package/dist/core/group/extractors/topic-patterns/java.js +80 -0
- package/dist/core/group/extractors/topic-patterns/node.d.ts +4 -0
- package/dist/core/group/extractors/topic-patterns/node.js +155 -0
- package/dist/core/group/extractors/topic-patterns/python.d.ts +2 -0
- package/dist/core/group/extractors/topic-patterns/python.js +116 -0
- package/dist/core/group/extractors/topic-patterns/types.d.ts +25 -0
- package/dist/core/group/extractors/topic-patterns/types.js +10 -0
- package/dist/core/group/extractors/tree-sitter-scanner.d.ts +113 -0
- package/dist/core/group/extractors/tree-sitter-scanner.js +94 -0
- package/dist/core/group/matching.d.ts +13 -0
- package/dist/core/group/matching.js +198 -0
- package/dist/core/group/normalization.d.ts +3 -0
- package/dist/core/group/normalization.js +115 -0
- package/dist/core/group/service-boundary-detector.d.ts +8 -0
- package/dist/core/group/service-boundary-detector.js +155 -0
- package/dist/core/group/service.d.ts +46 -0
- package/dist/core/group/service.js +160 -0
- package/dist/core/group/storage.d.ts +9 -0
- package/dist/core/group/storage.js +91 -0
- package/dist/core/group/sync.d.ts +21 -0
- package/dist/core/group/sync.js +148 -0
- package/dist/core/group/types.d.ts +130 -0
- package/dist/core/group/types.js +1 -0
- package/dist/core/ingestion/binding-accumulator.d.ts +212 -0
- package/dist/core/ingestion/binding-accumulator.js +336 -0
- package/dist/core/ingestion/call-processor.d.ts +155 -24
- package/dist/core/ingestion/call-processor.js +1129 -247
- package/dist/core/ingestion/class-extractors/generic.d.ts +2 -0
- package/dist/core/ingestion/class-extractors/generic.js +135 -0
- package/dist/core/ingestion/class-types.d.ts +34 -0
- package/dist/core/ingestion/class-types.js +1 -0
- package/dist/core/ingestion/cobol-processor.d.ts +1 -1
- package/dist/core/ingestion/entry-point-scoring.d.ts +1 -0
- package/dist/core/ingestion/entry-point-scoring.js +1 -0
- package/dist/core/ingestion/field-types.d.ts +2 -2
- package/dist/core/ingestion/filesystem-walker.js +8 -0
- package/dist/core/ingestion/framework-detection.d.ts +1 -0
- package/dist/core/ingestion/framework-detection.js +1 -0
- package/dist/core/ingestion/heritage-processor.d.ts +8 -15
- package/dist/core/ingestion/heritage-processor.js +15 -28
- package/dist/core/ingestion/import-processor.d.ts +1 -11
- package/dist/core/ingestion/import-processor.js +1 -13
- package/dist/core/ingestion/import-resolvers/utils.js +1 -0
- package/dist/core/ingestion/import-resolvers/vue.d.ts +8 -0
- package/dist/core/ingestion/import-resolvers/vue.js +9 -0
- package/dist/core/ingestion/language-config.js +1 -1
- package/dist/core/ingestion/language-provider.d.ts +14 -3
- package/dist/core/ingestion/languages/c-cpp.js +168 -1
- package/dist/core/ingestion/languages/csharp.js +20 -0
- package/dist/core/ingestion/languages/dart.js +26 -4
- package/dist/core/ingestion/languages/go.js +22 -0
- package/dist/core/ingestion/languages/index.d.ts +1 -0
- package/dist/core/ingestion/languages/index.js +2 -0
- package/dist/core/ingestion/languages/java.js +17 -0
- package/dist/core/ingestion/languages/kotlin.js +24 -1
- package/dist/core/ingestion/languages/php.js +23 -11
- package/dist/core/ingestion/languages/python.js +9 -0
- package/dist/core/ingestion/languages/ruby.js +43 -0
- package/dist/core/ingestion/languages/rust.js +38 -0
- package/dist/core/ingestion/languages/swift.js +31 -0
- package/dist/core/ingestion/languages/typescript.d.ts +1 -0
- package/dist/core/ingestion/languages/typescript.js +52 -3
- package/dist/core/ingestion/languages/vue.d.ts +13 -0
- package/dist/core/ingestion/languages/vue.js +81 -0
- package/dist/core/ingestion/markdown-processor.d.ts +1 -1
- package/dist/core/ingestion/method-extractors/configs/c-cpp.d.ts +3 -0
- package/dist/core/ingestion/method-extractors/configs/c-cpp.js +387 -0
- package/dist/core/ingestion/method-extractors/configs/csharp.js +5 -1
- package/dist/core/ingestion/method-extractors/configs/dart.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/dart.js +376 -0
- package/dist/core/ingestion/method-extractors/configs/go.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/go.js +176 -0
- package/dist/core/ingestion/method-extractors/configs/jvm.js +14 -4
- package/dist/core/ingestion/method-extractors/configs/php.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/php.js +304 -0
- package/dist/core/ingestion/method-extractors/configs/python.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/python.js +309 -0
- package/dist/core/ingestion/method-extractors/configs/ruby.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/ruby.js +286 -0
- package/dist/core/ingestion/method-extractors/configs/rust.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/rust.js +195 -0
- package/dist/core/ingestion/method-extractors/configs/swift.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/swift.js +277 -0
- package/dist/core/ingestion/method-extractors/configs/typescript-javascript.js +85 -8
- package/dist/core/ingestion/method-extractors/generic.d.ts +6 -0
- package/dist/core/ingestion/method-extractors/generic.js +84 -17
- package/dist/core/ingestion/method-types.d.ts +29 -0
- package/dist/core/ingestion/model/field-registry.d.ts +18 -0
- package/dist/core/ingestion/model/field-registry.js +22 -0
- package/dist/core/ingestion/model/heritage-map.d.ts +70 -0
- package/dist/core/ingestion/model/heritage-map.js +159 -0
- package/dist/core/ingestion/model/index.d.ts +20 -0
- package/dist/core/ingestion/model/index.js +41 -0
- package/dist/core/ingestion/model/method-registry.d.ts +62 -0
- package/dist/core/ingestion/model/method-registry.js +130 -0
- package/dist/core/ingestion/model/registration-table.d.ts +139 -0
- package/dist/core/ingestion/model/registration-table.js +224 -0
- package/dist/core/ingestion/model/resolution-context.d.ts +93 -0
- package/dist/core/ingestion/model/resolution-context.js +337 -0
- package/dist/core/ingestion/model/resolve.d.ts +56 -0
- package/dist/core/ingestion/model/resolve.js +297 -0
- package/dist/core/ingestion/model/semantic-model.d.ts +86 -0
- package/dist/core/ingestion/model/semantic-model.js +120 -0
- package/dist/core/ingestion/model/symbol-table.d.ts +222 -0
- package/dist/core/ingestion/model/symbol-table.js +206 -0
- package/dist/core/ingestion/model/type-registry.d.ts +39 -0
- package/dist/core/ingestion/model/type-registry.js +62 -0
- package/dist/core/ingestion/mro-processor.d.ts +5 -4
- package/dist/core/ingestion/mro-processor.js +311 -107
- package/dist/core/ingestion/parsing-processor.d.ts +5 -4
- package/dist/core/ingestion/parsing-processor.js +224 -87
- package/dist/core/ingestion/pipeline-phases/cobol.d.ts +16 -0
- package/dist/core/ingestion/pipeline-phases/cobol.js +45 -0
- package/dist/core/ingestion/pipeline-phases/communities.d.ts +16 -0
- package/dist/core/ingestion/pipeline-phases/communities.js +62 -0
- package/dist/core/ingestion/pipeline-phases/cross-file-impl.d.ts +17 -0
- package/dist/core/ingestion/pipeline-phases/cross-file-impl.js +156 -0
- package/dist/core/ingestion/pipeline-phases/cross-file.d.ts +37 -0
- package/dist/core/ingestion/pipeline-phases/cross-file.js +63 -0
- package/dist/core/ingestion/pipeline-phases/index.d.ts +21 -0
- package/dist/core/ingestion/pipeline-phases/index.js +22 -0
- package/dist/core/ingestion/pipeline-phases/markdown.d.ts +17 -0
- package/dist/core/ingestion/pipeline-phases/markdown.js +33 -0
- package/dist/core/ingestion/pipeline-phases/mro.d.ts +18 -0
- package/dist/core/ingestion/pipeline-phases/mro.js +36 -0
- package/dist/core/ingestion/pipeline-phases/orm-extraction.d.ts +22 -0
- package/dist/core/ingestion/pipeline-phases/orm-extraction.js +92 -0
- package/dist/core/ingestion/pipeline-phases/orm.d.ts +15 -0
- package/dist/core/ingestion/pipeline-phases/orm.js +74 -0
- package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +47 -0
- package/dist/core/ingestion/pipeline-phases/parse-impl.js +437 -0
- package/dist/core/ingestion/pipeline-phases/parse.d.ts +49 -0
- package/dist/core/ingestion/pipeline-phases/parse.js +33 -0
- package/dist/core/ingestion/pipeline-phases/processes.d.ts +16 -0
- package/dist/core/ingestion/pipeline-phases/processes.js +143 -0
- package/dist/core/ingestion/pipeline-phases/routes.d.ts +21 -0
- package/dist/core/ingestion/pipeline-phases/routes.js +243 -0
- package/dist/core/ingestion/pipeline-phases/runner.d.ts +22 -0
- package/dist/core/ingestion/pipeline-phases/runner.js +203 -0
- package/dist/core/ingestion/pipeline-phases/scan.d.ts +21 -0
- package/dist/core/ingestion/pipeline-phases/scan.js +46 -0
- package/dist/core/ingestion/pipeline-phases/structure.d.ts +27 -0
- package/dist/core/ingestion/pipeline-phases/structure.js +35 -0
- package/dist/core/ingestion/pipeline-phases/tools.d.ts +20 -0
- package/dist/core/ingestion/pipeline-phases/tools.js +79 -0
- package/dist/core/ingestion/pipeline-phases/types.d.ts +79 -0
- package/dist/core/ingestion/pipeline-phases/types.js +37 -0
- package/dist/core/ingestion/pipeline-phases/wildcard-synthesis.d.ts +35 -0
- package/dist/core/ingestion/pipeline-phases/wildcard-synthesis.js +174 -0
- package/dist/core/ingestion/pipeline.d.ts +18 -10
- package/dist/core/ingestion/pipeline.js +66 -1410
- package/dist/core/ingestion/process-processor.js +1 -1
- package/dist/core/ingestion/tree-sitter-queries.d.ts +5 -5
- package/dist/core/ingestion/tree-sitter-queries.js +90 -0
- package/dist/core/ingestion/type-env.d.ts +15 -2
- package/dist/core/ingestion/type-env.js +163 -102
- package/dist/core/ingestion/type-extractors/csharp.js +17 -0
- package/dist/core/ingestion/type-extractors/jvm.js +11 -0
- package/dist/core/ingestion/type-extractors/php.js +0 -55
- package/dist/core/ingestion/type-extractors/ruby.js +0 -32
- package/dist/core/ingestion/type-extractors/swift.js +13 -0
- package/dist/core/ingestion/type-extractors/types.d.ts +8 -8
- package/dist/core/ingestion/type-extractors/typescript.js +66 -69
- package/dist/core/ingestion/utils/ast-helpers.d.ts +32 -44
- package/dist/core/ingestion/utils/ast-helpers.js +157 -573
- package/dist/core/ingestion/utils/env.d.ts +10 -0
- package/dist/core/ingestion/utils/env.js +10 -0
- package/dist/core/ingestion/utils/graph-sort.d.ts +58 -0
- package/dist/core/ingestion/utils/graph-sort.js +100 -0
- package/dist/core/ingestion/utils/method-props.d.ts +32 -0
- package/dist/core/ingestion/utils/method-props.js +147 -0
- package/dist/core/ingestion/vue-sfc-extractor.d.ts +44 -0
- package/dist/core/ingestion/vue-sfc-extractor.js +94 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +31 -19
- package/dist/core/ingestion/workers/parse-worker.js +469 -200
- package/dist/core/lbug/lbug-adapter.d.ts +6 -0
- package/dist/core/lbug/lbug-adapter.js +134 -27
- package/dist/core/lbug/pool-adapter.d.ts +76 -0
- package/dist/core/lbug/pool-adapter.js +522 -0
- package/dist/core/run-analyze.d.ts +2 -0
- package/dist/core/run-analyze.js +1 -1
- package/dist/core/search/bm25-index.js +1 -1
- package/dist/core/tree-sitter/parser-loader.js +1 -0
- package/dist/core/wiki/graph-queries.js +1 -1
- package/dist/mcp/core/embedder.js +6 -5
- package/dist/mcp/core/lbug-adapter.d.ts +3 -63
- package/dist/mcp/core/lbug-adapter.js +3 -484
- package/dist/mcp/local/local-backend.d.ts +31 -2
- package/dist/mcp/local/local-backend.js +255 -46
- package/dist/mcp/resources.js +5 -4
- package/dist/mcp/staleness.d.ts +3 -13
- package/dist/mcp/staleness.js +2 -31
- package/dist/mcp/tools.js +80 -4
- package/dist/server/analyze-job.d.ts +2 -0
- package/dist/server/analyze-job.js +4 -0
- package/dist/server/api.d.ts +20 -1
- package/dist/server/api.js +306 -71
- package/dist/server/git-clone.d.ts +2 -1
- package/dist/server/git-clone.js +98 -5
- package/dist/storage/git.d.ts +13 -0
- package/dist/storage/git.js +25 -0
- package/dist/storage/repo-manager.js +1 -1
- package/package.json +9 -3
- package/scripts/patch-tree-sitter-swift.cjs +78 -0
- package/vendor/tree-sitter-proto/binding.gyp +30 -0
- package/vendor/tree-sitter-proto/bindings/node/binding.cc +20 -0
- package/vendor/tree-sitter-proto/bindings/node/index.d.ts +28 -0
- package/vendor/tree-sitter-proto/bindings/node/index.js +7 -0
- package/vendor/tree-sitter-proto/package.json +18 -0
- package/vendor/tree-sitter-proto/src/node-types.json +1145 -0
- package/vendor/tree-sitter-proto/src/parser.c +10149 -0
- package/vendor/tree-sitter-proto/src/tree_sitter/alloc.h +54 -0
- package/vendor/tree-sitter-proto/src/tree_sitter/array.h +291 -0
- package/vendor/tree-sitter-proto/src/tree_sitter/parser.h +266 -0
- package/dist/core/ingestion/named-binding-processor.d.ts +0 -18
- package/dist/core/ingestion/named-binding-processor.js +0 -42
- package/dist/core/ingestion/resolution-context.d.ts +0 -58
- package/dist/core/ingestion/resolution-context.js +0 -135
- package/dist/core/ingestion/symbol-table.d.ts +0 -79
- 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,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,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
|
+
};
|