codebeacon 0.1.2__py3-none-any.whl

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 (59) hide show
  1. codebeacon/__init__.py +1 -0
  2. codebeacon/__main__.py +3 -0
  3. codebeacon/cache.py +136 -0
  4. codebeacon/cli.py +391 -0
  5. codebeacon/common/__init__.py +0 -0
  6. codebeacon/common/filters.py +170 -0
  7. codebeacon/common/symbols.py +121 -0
  8. codebeacon/common/types.py +98 -0
  9. codebeacon/config.py +144 -0
  10. codebeacon/contextmap/__init__.py +0 -0
  11. codebeacon/contextmap/generator.py +602 -0
  12. codebeacon/discover/__init__.py +0 -0
  13. codebeacon/discover/detector.py +388 -0
  14. codebeacon/discover/scanner.py +192 -0
  15. codebeacon/export/__init__.py +0 -0
  16. codebeacon/export/mcp.py +515 -0
  17. codebeacon/export/obsidian.py +812 -0
  18. codebeacon/extract/__init__.py +22 -0
  19. codebeacon/extract/base.py +372 -0
  20. codebeacon/extract/components.py +357 -0
  21. codebeacon/extract/dependencies.py +140 -0
  22. codebeacon/extract/entities.py +575 -0
  23. codebeacon/extract/queries/README.md +116 -0
  24. codebeacon/extract/queries/actix.scm +115 -0
  25. codebeacon/extract/queries/angular.scm +155 -0
  26. codebeacon/extract/queries/aspnet.scm +159 -0
  27. codebeacon/extract/queries/django.scm +122 -0
  28. codebeacon/extract/queries/express.scm +124 -0
  29. codebeacon/extract/queries/fastapi.scm +152 -0
  30. codebeacon/extract/queries/flask.scm +120 -0
  31. codebeacon/extract/queries/gin.scm +142 -0
  32. codebeacon/extract/queries/ktor.scm +144 -0
  33. codebeacon/extract/queries/laravel.scm +172 -0
  34. codebeacon/extract/queries/nestjs.scm +183 -0
  35. codebeacon/extract/queries/rails.scm +114 -0
  36. codebeacon/extract/queries/react.scm +111 -0
  37. codebeacon/extract/queries/spring_boot.scm +204 -0
  38. codebeacon/extract/queries/svelte.scm +73 -0
  39. codebeacon/extract/queries/vapor.scm +130 -0
  40. codebeacon/extract/queries/vue.scm +123 -0
  41. codebeacon/extract/routes.py +910 -0
  42. codebeacon/extract/semantic.py +280 -0
  43. codebeacon/extract/services.py +597 -0
  44. codebeacon/graph/__init__.py +1 -0
  45. codebeacon/graph/analyze.py +281 -0
  46. codebeacon/graph/build.py +320 -0
  47. codebeacon/graph/cluster.py +160 -0
  48. codebeacon/graph/enrich.py +206 -0
  49. codebeacon/skill/SKILL.md +127 -0
  50. codebeacon/wave.py +292 -0
  51. codebeacon/wiki/__init__.py +0 -0
  52. codebeacon/wiki/generator.py +376 -0
  53. codebeacon/wiki/index.py +95 -0
  54. codebeacon/wiki/templates.py +467 -0
  55. codebeacon-0.1.2.dist-info/METADATA +319 -0
  56. codebeacon-0.1.2.dist-info/RECORD +59 -0
  57. codebeacon-0.1.2.dist-info/WHEEL +4 -0
  58. codebeacon-0.1.2.dist-info/entry_points.txt +2 -0
  59. codebeacon-0.1.2.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,115 @@
1
+ ; ── Actix-web / Axum (Rust) ───────────────────────────────────────────────────
2
+ ; Grammar: tree-sitter-rust
3
+ ;
4
+ ; Rust grammar note:
5
+ ; - attribute_item: #[get("/users")]
6
+ ; - attribute: get("/users") — identifier + token_tree
7
+ ; - token_tree: the (...) argument list (unparsed by tree-sitter)
8
+ ; - string_literal / string_content: path string
9
+ ; - function_item: async fn handler
10
+ ; - struct_item: struct definition
11
+ ; - field_declaration: struct field
12
+ ;
13
+ ; Proc macro note:
14
+ ; #[derive(Queryable, Serialize)] — captured by @entity.derive_trait
15
+ ; Diesel table! macro handled by regexp in entities.py
16
+ ;
17
+ ; Captures:
18
+ ; @route.proc_macro - get/post/put/patch/delete (Actix proc macro name)
19
+ ; @route.path - path string content
20
+ ; @route.func_name - handler function name
21
+ ; @route.axum_method - Axum: get/post/put/delete (from axum::routing::get)
22
+ ; @route.axum_path - Axum: path string in Router::new().route(path, ...)
23
+ ; @entity.struct_name - struct with derive macros
24
+ ; @entity.derive_trait - Queryable/DeriveEntityModel/Serialize etc.
25
+ ; @entity.field_name - struct field name
26
+ ; @entity.field_type - struct field type
27
+ ; @service.struct_name - AppState / service struct
28
+ ; @import.path - use path
29
+
30
+ ; ── Actix: #[get("/users")] async fn handler() ───────────────────────────────
31
+
32
+ (function_item
33
+ .
34
+ (attribute_item
35
+ (attribute
36
+ (identifier) @route.proc_macro
37
+ (#match? @route.proc_macro "^(get|post|put|patch|delete|options|head)$")
38
+ (token_tree
39
+ (string_literal
40
+ (string_content) @route.path
41
+ )
42
+ )
43
+ )
44
+ )
45
+ name: (identifier) @route.func_name
46
+ ) @route.actix_handler
47
+
48
+ ; ── Axum: Router::new().route("/users", get(handler)) ────────────────────────
49
+
50
+ (call_expression
51
+ function: (field_expression
52
+ field: (field_identifier) @_route_fn
53
+ (#eq? @_route_fn "route")
54
+ )
55
+ arguments: (arguments
56
+ (string_literal
57
+ (string_content) @route.axum_path
58
+ )
59
+ (call_expression
60
+ function: (identifier) @route.axum_method
61
+ (#match? @route.axum_method "^(get|post|put|patch|delete|options|head)$")
62
+ arguments: (arguments
63
+ (identifier) @route.axum_handler
64
+ )
65
+ )
66
+ )
67
+ ) @route.axum_route
68
+
69
+ ; ── #[derive(Queryable, Serialize, ...)] struct ──────────────────────────────
70
+
71
+ (struct_item
72
+ .
73
+ (attribute_item
74
+ (attribute
75
+ (identifier) @_derive (#eq? @_derive "derive")
76
+ (token_tree
77
+ (identifier) @entity.derive_trait
78
+ (#match? @entity.derive_trait "^(Queryable|DeriveEntityModel|DeriveRelation|FromRow|Model|Serialize|Deserialize|sqlx)$")
79
+ )
80
+ )
81
+ )
82
+ name: (type_identifier) @entity.struct_name
83
+ ) @entity.struct
84
+
85
+ ; All struct fields
86
+ (struct_item
87
+ name: (type_identifier) @entity.struct_name
88
+ body: (field_declaration_list
89
+ (field_declaration
90
+ name: (field_identifier) @entity.field_name
91
+ type: _ @entity.field_type
92
+ )
93
+ )
94
+ ) @entity.struct_with_fields
95
+
96
+ ; ── All attribute_items on functions (for proc macro detection) ───────────────
97
+
98
+ (attribute_item
99
+ (attribute
100
+ (identifier) @route.attr_name
101
+ (#match? @route.attr_name "^(get|post|put|patch|delete|options|head|route|web)$")
102
+ )
103
+ ) @route.attr
104
+
105
+ ; ── AppState / service struct ─────────────────────────────────────────────────
106
+
107
+ (struct_item
108
+ name: (type_identifier) @service.struct_name
109
+ ) @service.struct
110
+
111
+ ; ── use declarations ─────────────────────────────────────────────────────────
112
+
113
+ (use_declaration
114
+ argument: _ @import.path
115
+ ) @import.use
@@ -0,0 +1,155 @@
1
+ ; ── Angular (TypeScript) ─────────────────────────────────────────────────────
2
+ ; Grammar: tree-sitter-typescript
3
+ ;
4
+ ; TypeScript decorator note:
5
+ ; - decorator: @Component({...})
6
+ ; - call_expression: Component({...}) inside decorator
7
+ ; - object: { selector: "...", templateUrl: "..." }
8
+ ; - property_identifier: key names
9
+ ;
10
+ ; Angular-specific:
11
+ ; - @Component({ selector, templateUrl/template, styleUrls })
12
+ ; - @Injectable({ providedIn: "root" })
13
+ ; - @NgModule({ declarations, imports, providers, bootstrap })
14
+ ; - RouterModule.forRoot(routes) / RouterModule.forChild(routes)
15
+ ; - constructor(private service: ServiceType) → DI
16
+ ;
17
+ ; Captures:
18
+ ; @component.class_name - @Component class name
19
+ ; @component.selector - selector: "app-root"
20
+ ; @component.template_url - templateUrl: "./foo.component.html"
21
+ ; @service.class_name - @Injectable class name
22
+ ; @service.inject_type - constructor injected type
23
+ ; @module.class_name - @NgModule class name
24
+ ; @module.providers - providers array items
25
+ ; @route.path - Routes array { path: "users" }
26
+ ; @route.component - Routes array { component: UserComponent }
27
+ ; @route.lazy_load - loadComponent/loadChildren
28
+ ; @import.path - import source
29
+
30
+ ; ── @Component({...}) class ───────────────────────────────────────────────────
31
+
32
+ (class_declaration
33
+ (decorator
34
+ (call_expression
35
+ function: (identifier) @_comp (#eq? @_comp "Component")
36
+ arguments: (arguments
37
+ (object
38
+ (pair
39
+ key: (property_identifier) @_sel (#eq? @_sel "selector")
40
+ value: (string
41
+ (string_fragment) @component.selector
42
+ )
43
+ )
44
+ )
45
+ )
46
+ )
47
+ )
48
+ name: (type_identifier) @component.class_name
49
+ ) @component.class
50
+
51
+ ; templateUrl capture
52
+ (decorator
53
+ (call_expression
54
+ function: (identifier) @_comp2 (#eq? @_comp2 "Component")
55
+ arguments: (arguments
56
+ (object
57
+ (pair
58
+ key: (property_identifier) @_turl
59
+ (#eq? @_turl "templateUrl")
60
+ value: (string
61
+ (string_fragment) @component.template_url
62
+ )
63
+ )
64
+ )
65
+ )
66
+ )
67
+ ) @component.template_url_decorator
68
+
69
+ ; ── @Injectable({ providedIn: "root" }) class ────────────────────────────────
70
+
71
+ (class_declaration
72
+ (decorator
73
+ (call_expression
74
+ function: (identifier) @_inj (#eq? @_inj "Injectable")
75
+ )
76
+ )
77
+ name: (type_identifier) @service.class_name
78
+ ) @service.injectable
79
+
80
+ ; Constructor DI
81
+ (method_definition
82
+ name: (property_identifier) @_ctor
83
+ (#eq? @_ctor "constructor")
84
+ parameters: (formal_parameters
85
+ (required_parameter
86
+ pattern: (identifier) @_pname
87
+ type: (type_annotation
88
+ (type_identifier) @service.inject_type
89
+ )
90
+ )
91
+ )
92
+ ) @service.constructor_di
93
+
94
+ ; ── @NgModule({...}) class ────────────────────────────────────────────────────
95
+
96
+ (class_declaration
97
+ (decorator
98
+ (call_expression
99
+ function: (identifier) @_mod (#eq? @_mod "NgModule")
100
+ arguments: (arguments
101
+ (object
102
+ (pair
103
+ key: (property_identifier) @_providers (#eq? @_providers "providers")
104
+ value: (array
105
+ (identifier) @module.providers
106
+ )
107
+ )
108
+ )
109
+ )
110
+ )
111
+ )
112
+ name: (type_identifier) @module.class_name
113
+ ) @module.ngmodule
114
+
115
+ ; ── Angular Router routes array ───────────────────────────────────────────────
116
+
117
+ ; Routes array: { path: "users", component: UserListComponent }
118
+ (array
119
+ (object
120
+ (pair
121
+ key: (property_identifier) @_path (#eq? @_path "path")
122
+ value: (string
123
+ (string_fragment) @route.path
124
+ )
125
+ )
126
+ )
127
+ ) @route.routes
128
+
129
+ ; component reference in route
130
+ (object
131
+ (pair
132
+ key: (property_identifier) @_path2 (#eq? @_path2 "path")
133
+ value: (string (string_fragment) @route.path)
134
+ )
135
+ (pair
136
+ key: (property_identifier) @_comp3
137
+ (#match? @_comp3 "^(component|redirectTo)$")
138
+ value: (identifier) @route.component
139
+ )
140
+ ) @route.route_entry
141
+
142
+ ; Lazy loading: loadComponent: () => import("./foo").then(m => m.FooComponent)
143
+ (object
144
+ (pair
145
+ key: (property_identifier) @_ll
146
+ (#match? @_ll "^(loadComponent|loadChildren)$")
147
+ value: _ @route.lazy_load
148
+ )
149
+ ) @route.lazy
150
+
151
+ ; ── imports ───────────────────────────────────────────────────────────────────
152
+
153
+ (import_statement
154
+ source: (string) @import.path
155
+ ) @import.decl
@@ -0,0 +1,159 @@
1
+ ; ── ASP.NET Core (C#) ─────────────────────────────────────────────────────────
2
+ ; Grammar: tree-sitter-c-sharp
3
+ ;
4
+ ; C# grammar note:
5
+ ; - attribute_list: [HttpGet("{id}")] — wraps attribute nodes
6
+ ; - attribute: HttpGet("{id}") — name + attribute_argument_list
7
+ ; - identifier: attribute/class/method names
8
+ ; - string_literal_content: content inside string_literal
9
+ ;
10
+ ; Special handling in extract/routes.py:
11
+ ; - [Route("api/[controller]")] → replace [controller] with class name minus "Controller"
12
+ ; - Minimal API: app.MapGet("/users", handler)
13
+ ;
14
+ ; Captures:
15
+ ; @route.class_attr - [Route("api/[controller]")] on class → path template
16
+ ; @route.class_name - controller class name
17
+ ; @route.method_attr - [HttpGet] / [HttpPost] etc. attribute name
18
+ ; @route.method_path - path in [HttpGet("{id}")]
19
+ ; @route.method_name - action method name
20
+ ; @route.map_method - MapGet/MapPost etc. (minimal API)
21
+ ; @route.map_path - path string (minimal API)
22
+ ; @service.class_name - service class name
23
+ ; @service.interface - implemented interface
24
+ ; @di.service_type - AddScoped<IService, ServiceImpl> → interface type
25
+ ; @di.impl_type - implementation type
26
+ ; @entity.class_name - EF Core entity class (DbSet target)
27
+ ; @entity.dbset_name - DbSet<User> property name
28
+ ; @import.path - using namespace
29
+
30
+ ; ── Controller class with [Route(...)] ───────────────────────────────────────
31
+
32
+ (class_declaration
33
+ (attribute_list
34
+ (attribute
35
+ name: (identifier) @_route (#eq? @_route "Route")
36
+ (attribute_argument_list
37
+ (attribute_argument
38
+ (string_literal
39
+ (string_literal_content) @route.class_attr
40
+ )
41
+ )
42
+ )
43
+ )
44
+ )
45
+ name: (identifier) @route.class_name
46
+ ) @route.controller_class
47
+
48
+ ; Controller class without route (uses [ApiController] convention)
49
+ (class_declaration
50
+ (attribute_list
51
+ (attribute
52
+ name: (identifier) @_api
53
+ (#match? @_api "^(ApiController|Controller)$")
54
+ )
55
+ )
56
+ name: (identifier) @route.class_name
57
+ ) @route.controller_bare
58
+
59
+ ; ── Method route attributes ───────────────────────────────────────────────────
60
+
61
+ ; [HttpGet("{id}")] — with path
62
+ (method_declaration
63
+ (attribute_list
64
+ (attribute
65
+ name: (identifier) @route.method_attr
66
+ (#match? @route.method_attr "^(HttpGet|HttpPost|HttpPut|HttpPatch|HttpDelete|HttpOptions|HttpHead|Route)$")
67
+ (attribute_argument_list
68
+ (attribute_argument
69
+ (string_literal
70
+ (string_literal_content) @route.method_path
71
+ )
72
+ )
73
+ )
74
+ )
75
+ )
76
+ name: (identifier) @route.method_name
77
+ ) @route.method_with_path
78
+
79
+ ; [HttpPost] — without path
80
+ (method_declaration
81
+ (attribute_list
82
+ (attribute
83
+ name: (identifier) @route.method_attr
84
+ (#match? @route.method_attr "^(HttpGet|HttpPost|HttpPut|HttpPatch|HttpDelete|HttpOptions|HttpHead)$")
85
+ )
86
+ )
87
+ name: (identifier) @route.method_name
88
+ ) @route.method_bare
89
+
90
+ ; ── Minimal API: app.MapGet("/users", handler) ───────────────────────────────
91
+
92
+ (expression_statement
93
+ (invocation_expression
94
+ expression: (member_access_expression
95
+ name: (identifier) @route.map_method
96
+ (#match? @route.map_method "^(MapGet|MapPost|MapPut|MapPatch|MapDelete|MapMethods|Map)$")
97
+ )
98
+ (argument_list
99
+ (argument
100
+ (string_literal
101
+ (string_literal_content) @route.map_path
102
+ )
103
+ )
104
+ )
105
+ )
106
+ ) @route.minimal_api
107
+
108
+ ; ── Service class implementing interface ──────────────────────────────────────
109
+
110
+ (class_declaration
111
+ name: (identifier) @service.class_name
112
+ (base_list
113
+ (identifier) @service.interface
114
+ )
115
+ ) @service.class
116
+
117
+ ; ── DI registration: builder.Services.AddScoped<IFoo, FooImpl>() ─────────────
118
+
119
+ (invocation_expression
120
+ expression: (member_access_expression
121
+ name: (identifier) @_scope
122
+ (#match? @_scope "^(AddScoped|AddSingleton|AddTransient|AddHostedService)$")
123
+ )
124
+ (argument_list)
125
+ ) @di.registration
126
+
127
+ ; Generic DI: AddScoped<IFoo, FooImpl>()
128
+ (invocation_expression
129
+ expression: (generic_name
130
+ (identifier) @_scope
131
+ (#match? @_scope "^(AddScoped|AddSingleton|AddTransient)$")
132
+ (type_argument_list
133
+ (identifier) @di.service_type
134
+ (identifier) @di.impl_type
135
+ )
136
+ )
137
+ ) @di.generic_registration
138
+
139
+ ; ── EF Core DbContext ─────────────────────────────────────────────────────────
140
+
141
+ (property_declaration
142
+ type: (generic_name
143
+ (identifier) @_dbset (#eq? @_dbset "DbSet")
144
+ (type_argument_list
145
+ (identifier) @entity.class_name
146
+ )
147
+ )
148
+ name: (identifier) @entity.dbset_name
149
+ ) @entity.dbset
150
+
151
+ ; ── using directives ─────────────────────────────────────────────────────────
152
+
153
+ (using_directive
154
+ (qualified_name) @import.path
155
+ ) @import.using
156
+
157
+ (using_directive
158
+ (identifier) @import.path
159
+ ) @import.using_simple
@@ -0,0 +1,122 @@
1
+ ; ── Django (Python) ───────────────────────────────────────────────────────────
2
+ ; Grammar: tree-sitter-python
3
+ ;
4
+ ; Convention note: Django routes live in urls.py, models in models.py.
5
+ ; The extractor handles file-name-based dispatch before running these queries.
6
+ ;
7
+ ; Captures:
8
+ ; @route.path_call - path("...", view) call
9
+ ; @route.path_str - URL string
10
+ ; @route.view_name - view function/class reference
11
+ ; @route.include_path - include("app.urls") string
12
+ ; @route.re_path_str - re_path("regex") string
13
+ ; @entity.class_name - models.Model subclass
14
+ ; @entity.field_name - model field name
15
+ ; @entity.field_type - model field type (e.g. CharField, ForeignKey)
16
+ ; @view.class_name - CBV class name
17
+ ; @view.func_name - FBV function name
18
+ ; @import.path - import path
19
+
20
+ ; ── urlpatterns path() entries ───────────────────────────────────────────────
21
+
22
+ (assignment
23
+ left: (identifier) @_up
24
+ (#eq? @_up "urlpatterns")
25
+ right: (list
26
+ (call
27
+ function: (identifier) @_path_fn
28
+ (#match? @_path_fn "^(path|re_path)$")
29
+ arguments: (argument_list
30
+ (string) @route.path_str
31
+ [
32
+ (identifier) @route.view_name
33
+ (attribute
34
+ attribute: (identifier) @route.view_name
35
+ )
36
+ (call
37
+ function: (attribute
38
+ attribute: (identifier) @_asv
39
+ (#eq? @_asv "as_view")
40
+ )
41
+ )
42
+ ]
43
+ )
44
+ )
45
+ )
46
+ ) @route.urlpatterns
47
+
48
+ ; include() inside urlpatterns
49
+ (call
50
+ function: (identifier) @_inc
51
+ (#eq? @_inc "include")
52
+ arguments: (argument_list
53
+ (string) @route.include_path
54
+ )
55
+ ) @route.include
56
+
57
+ ; ── Django model ──────────────────────────────────────────────────────────────
58
+
59
+ (class_definition
60
+ name: (identifier) @entity.class_name
61
+ superclasses: (argument_list
62
+ [
63
+ (attribute
64
+ attribute: (identifier) @_model
65
+ (#match? @_model "^(Model|AbstractModel|AbstractBaseModel)$")
66
+ )
67
+ (identifier) @_model
68
+ (#match? @_model "^(Model|AbstractModel)$")
69
+ ]
70
+ )
71
+ body: (block
72
+ (expression_statement
73
+ (assignment
74
+ left: (identifier) @entity.field_name
75
+ right: (call
76
+ function: [
77
+ (identifier) @entity.field_type
78
+ (attribute
79
+ attribute: (identifier) @entity.field_type
80
+ )
81
+ ]
82
+ (#match? @entity.field_type "^(CharField|IntegerField|FloatField|BooleanField|DateField|DateTimeField|ForeignKey|OneToOneField|ManyToManyField|TextField|EmailField|URLField|SlugField|UUIDField|FileField|ImageField|JSONField|AutoField|BigAutoField|SmallIntegerField|PositiveIntegerField)$")
83
+ )
84
+ )
85
+ )
86
+ )
87
+ ) @entity.model
88
+
89
+ ; ── Class-based views ────────────────────────────────────────────────────────
90
+
91
+ (class_definition
92
+ name: (identifier) @view.class_name
93
+ superclasses: (argument_list
94
+ [
95
+ (identifier) @_view_base
96
+ (attribute attribute: (identifier) @_view_base)
97
+ ]
98
+ (#match? @_view_base "^(View|ListView|DetailView|CreateView|UpdateView|DeleteView|TemplateView|APIView|GenericAPIView|ModelViewSet|ReadOnlyModelViewSet|ViewSet|FormView)$")
99
+ )
100
+ ) @view.cbv
101
+
102
+ ; ── Function-based views (decorated with @login_required etc.) ───────────────
103
+
104
+ (decorated_definition
105
+ definition: (function_definition
106
+ name: (identifier) @view.func_name
107
+ parameters: (parameters
108
+ (identifier) @_req
109
+ (#eq? @_req "request")
110
+ )
111
+ )
112
+ ) @view.fbv_decorated
113
+
114
+ ; ── imports ───────────────────────────────────────────────────────────────────
115
+
116
+ (import_from_statement
117
+ module_name: _ @import.path
118
+ ) @import.from
119
+
120
+ (import_statement
121
+ name: _ @import.path
122
+ ) @import.plain
@@ -0,0 +1,124 @@
1
+ ; ── Express / Koa / Fastify (JavaScript/TypeScript) ──────────────────────────
2
+ ; Grammar: tree-sitter-javascript / tree-sitter-typescript
3
+ ;
4
+ ; Captures:
5
+ ; @route.method - "get", "post", "put", "delete", "patch", "all"
6
+ ; @route.path - path string literal
7
+ ; @route.object - router/app object name (for prefix tracking)
8
+ ; @route.use_prefix - path passed to app.use() for prefix mounting
9
+ ; @service.name - exported class name
10
+ ; @import.path - import/require path
11
+
12
+ ; ── app.METHOD("/path", handler) ─────────────────────────────────────────────
13
+
14
+ (expression_statement
15
+ (call_expression
16
+ function: (member_expression
17
+ object: (identifier) @route.object
18
+ property: (property_identifier) @route.method
19
+ (#match? @route.method "^(get|post|put|patch|delete|del|options|head|all|use)$")
20
+ )
21
+ arguments: (arguments
22
+ .
23
+ (string) @route.path
24
+ )
25
+ )
26
+ ) @route.call
27
+
28
+ ; ── router.route("/path").get(handler).post(handler) ─────────────────────────
29
+
30
+ (call_expression
31
+ function: (member_expression
32
+ object: (call_expression
33
+ function: (member_expression
34
+ object: (identifier) @route.object
35
+ property: (property_identifier) @_route_kw
36
+ (#eq? @_route_kw "route")
37
+ )
38
+ arguments: (arguments
39
+ .
40
+ (string) @route.path
41
+ )
42
+ )
43
+ property: (property_identifier) @route.method
44
+ (#match? @route.method "^(get|post|put|patch|delete|options|head|all)$")
45
+ )
46
+ ) @route.chained
47
+
48
+ ; ── app.use("/prefix", router) — prefix mounting ─────────────────────────────
49
+
50
+ (expression_statement
51
+ (call_expression
52
+ function: (member_expression
53
+ object: (identifier) @_obj
54
+ property: (property_identifier) @_use
55
+ (#eq? @_use "use")
56
+ )
57
+ arguments: (arguments
58
+ .
59
+ (string) @route.use_prefix
60
+ .
61
+ _
62
+ )
63
+ )
64
+ ) @route.use_mount
65
+
66
+ ; ── const router = express.Router() / Router() ───────────────────────────────
67
+
68
+ (variable_declarator
69
+ name: (identifier) @route.router_name
70
+ value: (call_expression
71
+ function: [
72
+ (identifier) @_r (#eq? @_r "Router")
73
+ (member_expression property: (property_identifier) @_r (#eq? @_r "Router"))
74
+ ]
75
+ )
76
+ ) @route.router_decl
77
+
78
+ ; ── Fastify: fastify.register(plugin, { prefix: "/api" }) ────────────────────
79
+
80
+ (call_expression
81
+ function: (member_expression
82
+ object: (identifier) @_app
83
+ property: (property_identifier) @_reg
84
+ (#eq? @_reg "register")
85
+ )
86
+ arguments: (arguments
87
+ _
88
+ (object
89
+ (pair
90
+ key: (property_identifier) @_k
91
+ (#eq? @_k "prefix")
92
+ value: (string) @route.use_prefix
93
+ )
94
+ )
95
+ )
96
+ ) @route.fastify_register
97
+
98
+ ; ── Exported class (service) ──────────────────────────────────────────────────
99
+
100
+ (export_statement
101
+ declaration: (class_declaration
102
+ name: (identifier) @service.name
103
+ )
104
+ ) @service.export_class
105
+
106
+ (class_declaration
107
+ name: (identifier) @service.name
108
+ ) @service.class
109
+
110
+ ; ── imports ───────────────────────────────────────────────────────────────────
111
+
112
+ ; ES module: import ... from "..."
113
+ (import_statement
114
+ source: (string) @import.path
115
+ ) @import.es
116
+
117
+ ; CommonJS: require("...")
118
+ (call_expression
119
+ function: (identifier) @_req
120
+ (#eq? @_req "require")
121
+ arguments: (arguments
122
+ (string) @import.path
123
+ )
124
+ ) @import.cjs