gitnexus 1.6.6-rc.93 → 1.6.6-rc.94

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.
@@ -6,14 +6,18 @@ import { compilePatterns, runCompiledPatterns, unquoteLiteral, } from '../tree-s
6
6
  * - Spring `RestTemplate.getForObject/...`, `exchange(...)`
7
7
  * - Spring `WebClient.method(HttpMethod.X, ...)`, `WebClient.get().uri(...)`
8
8
  * - OkHttp `new Request.Builder().url("...")`
9
- * - OpenFeign interfaces with Spring MVC method annotations
9
+ * - OpenFeign interfaces with Spring MVC method annotations or
10
+ * native `@RequestLine("METHOD /path")` annotations
10
11
  * - Java / Apache HttpClient literal request construction
11
12
  *
12
- * The plugin runs two pattern bundles: one to collect class-level
13
- * `@RequestMapping` prefixes keyed by the enclosing class node, and a
14
- * second to match method-level annotations. The `scan` function walks
15
- * up from each matched annotation to find its enclosing class and
16
- * combines the prefix with the method path.
13
+ * Every route-defining annotation (class/interface `@RequestMapping`
14
+ * prefixes, `@FeignClient(path)` prefixes, `@(Get|...)Mapping` method
15
+ * routes and native `@RequestLine`s) is matched by a single consolidated
16
+ * query (`JAVA_ROUTE_ANNOTATION_PATTERNS`) in one pass via
17
+ * `scanRouteAnnotations`. The `scan` function then walks up from each
18
+ * matched method to its enclosing class/interface to combine the prefix
19
+ * with the method path. Call-site consumers (RestTemplate, WebClient,
20
+ * OkHttp, Java/Apache HttpClient) keep their own focused queries.
17
21
  */
18
22
  const METHOD_ANNOTATION_TO_HTTP = {
19
23
  GetMapping: 'GET',
@@ -22,9 +26,34 @@ const METHOD_ANNOTATION_TO_HTTP = {
22
26
  DeleteMapping: 'DELETE',
23
27
  PatchMapping: 'PATCH',
24
28
  };
25
- // ─── Provider: Spring class/interface-level @RequestMapping prefix ───
26
- const SPRING_TYPE_PREFIX_PATTERNS = compilePatterns({
27
- name: 'java-spring-type-prefix',
29
+ // ─── Route-defining annotations (one generic query, one pass) ─────────
30
+ // Every Java route-mapper annotation shares one shape: an annotation carrying a
31
+ // single string argument — positional `"..."` or named `key = "..."` — on a
32
+ // class, interface, or method. This SINGLE query matches that shape generically;
33
+ // `scanRouteAnnotations` then reads the annotation NAME (`@ann`) and declaration
34
+ // kind (`@node.type`) in its for-loop to decide what each match means. Adding a
35
+ // new framework annotation that follows this single-string-argument shape is a
36
+ // change to that loop (and the lookup maps), not to this query. Annotations with
37
+ // a different argument shape — e.g. an array value `@RequestMapping({"/a","/b"})`
38
+ // — are out of scope here (as they were for the prior queries) and would need a
39
+ // new branch.
40
+ //
41
+ // Captures (shared across all branches; intentionally framework-agnostic):
42
+ // @ann → the annotation name identifier (RequestMapping, GetMapping, RequestLine, …)
43
+ // @node → the enclosing declaration (class_declaration | interface_declaration | method_declaration)
44
+ // @value → the string-literal argument
45
+ // @key → the named-argument member key (absent for the positional shape)
46
+ // @member → the method name (method_declaration branches only)
47
+ //
48
+ // The query carries NO `#eq?` / `#match?` predicates. Under the pinned
49
+ // tree-sitter 0.21.x binding a top-level `[ ... ]` alternation compiles to one
50
+ // pattern whose text predicates share a single bucket keyed by capture name, and
51
+ // a `#match?` against a capture absent from the matched branch evaluates FALSE —
52
+ // silently dropping sibling-branch matches. Keeping the query predicate-free
53
+ // sidesteps that hazard entirely; all name/key discrimination lives in the
54
+ // for-loop, where it reads as straight-line code.
55
+ const JAVA_ROUTE_ANNOTATION_PATTERNS = compilePatterns({
56
+ name: 'java-route-annotation',
28
57
  language: Java,
29
58
  patterns: [
30
59
  {
@@ -34,36 +63,44 @@ const SPRING_TYPE_PREFIX_PATTERNS = compilePatterns({
34
63
  (class_declaration
35
64
  (modifiers
36
65
  (annotation
37
- name: (identifier) @ann (#eq? @ann "RequestMapping")
38
- arguments: (annotation_argument_list (string_literal) @prefix)))) @type
66
+ name: (identifier) @ann
67
+ arguments: (annotation_argument_list (string_literal) @value)))) @node
39
68
  (interface_declaration
40
69
  (modifiers
41
70
  (annotation
42
- name: (identifier) @ann (#eq? @ann "RequestMapping")
43
- arguments: (annotation_argument_list (string_literal) @prefix)))) @type
44
- ]
45
- `,
46
- },
47
- {
48
- meta: {},
49
- query: `
50
- [
71
+ name: (identifier) @ann
72
+ arguments: (annotation_argument_list (string_literal) @value)))) @node
51
73
  (class_declaration
52
74
  (modifiers
53
75
  (annotation
54
- name: (identifier) @ann (#eq? @ann "RequestMapping")
76
+ name: (identifier) @ann
55
77
  arguments: (annotation_argument_list
56
78
  (element_value_pair
57
- key: (identifier) @key (#match? @key "^(path|value)$")
58
- value: (string_literal) @prefix))))) @type
79
+ key: (identifier) @key
80
+ value: (string_literal) @value))))) @node
59
81
  (interface_declaration
60
82
  (modifiers
61
83
  (annotation
62
- name: (identifier) @ann (#eq? @ann "RequestMapping")
84
+ name: (identifier) @ann
63
85
  arguments: (annotation_argument_list
64
86
  (element_value_pair
65
- key: (identifier) @key (#match? @key "^(path|value)$")
66
- value: (string_literal) @prefix))))) @type
87
+ key: (identifier) @key
88
+ value: (string_literal) @value))))) @node
89
+ (method_declaration
90
+ (modifiers
91
+ (annotation
92
+ name: (identifier) @ann
93
+ arguments: (annotation_argument_list (string_literal) @value)))
94
+ name: (identifier) @member) @node
95
+ (method_declaration
96
+ (modifiers
97
+ (annotation
98
+ name: (identifier) @ann
99
+ arguments: (annotation_argument_list
100
+ (element_value_pair
101
+ key: (identifier) @key
102
+ value: (string_literal) @value))))
103
+ name: (identifier) @member) @node
67
104
  ]
68
105
  `,
69
106
  },
@@ -84,88 +121,43 @@ const SPRING_TYPE_DECLARATION_PATTERNS = compilePatterns({
84
121
  },
85
122
  ],
86
123
  });
87
- // ─── Consumer: OpenFeign interface-level prefixes ───────────────────
88
- // Feign's `name`/`value` attributes identify a service, not an HTTP path,
89
- // so only `path` is used as a URL prefix. `@RequestMapping` on a Feign
90
- // interface is also common and does carry a path prefix.
91
- const FEIGN_INTERFACE_PREFIX_PATTERNS = compilePatterns({
92
- name: 'java-feign-interface-prefix',
93
- language: Java,
94
- patterns: [
95
- {
96
- meta: {},
97
- query: `
98
- (interface_declaration
99
- (modifiers
100
- (annotation
101
- name: (identifier) @ann (#eq? @ann "FeignClient")
102
- arguments: (annotation_argument_list
103
- (element_value_pair
104
- key: (identifier) @key (#eq? @key "path")
105
- value: (string_literal) @prefix))))) @interface
106
- `,
107
- },
108
- {
109
- meta: {},
110
- query: `
111
- (interface_declaration
112
- (modifiers
113
- (annotation
114
- name: (identifier) @ann (#eq? @ann "RequestMapping")
115
- arguments: (annotation_argument_list (string_literal) @prefix)))) @interface
116
- `,
117
- },
118
- {
119
- meta: {},
120
- query: `
121
- (interface_declaration
122
- (modifiers
123
- (annotation
124
- name: (identifier) @ann (#eq? @ann "RequestMapping")
125
- arguments: (annotation_argument_list
126
- (element_value_pair
127
- key: (identifier) @key (#match? @key "^(path|value)$")
128
- value: (string_literal) @prefix))))) @interface
129
- `,
130
- },
131
- ],
132
- });
133
- // ─── Provider: Spring @(Get|Post|...)Mapping method annotations ───────
134
- // Same dual-pattern approach: positional vs named argument. The named
135
- // pattern restricts the annotation member name to `path`/`value` to
136
- // avoid capturing unrelated string-valued attributes
137
- // (`produces`, `consumes`, `headers`, `name`, `params`, ...).
138
- const SPRING_METHOD_ROUTE_PATTERNS = compilePatterns({
139
- name: 'java-spring-method-route',
140
- language: Java,
141
- patterns: [
142
- {
143
- meta: {},
144
- query: `
145
- (method_declaration
146
- (modifiers
147
- (annotation
148
- name: (identifier) @ann (#match? @ann "^(Get|Post|Put|Delete|Patch)Mapping$")
149
- arguments: (annotation_argument_list (string_literal) @path)))
150
- name: (identifier) @method_name) @method
151
- `,
152
- },
153
- {
154
- meta: {},
155
- query: `
156
- (method_declaration
157
- (modifiers
158
- (annotation
159
- name: (identifier) @ann (#match? @ann "^(Get|Post|Put|Delete|Patch)Mapping$")
160
- arguments: (annotation_argument_list
161
- (element_value_pair
162
- key: (identifier) @key (#match? @key "^(path|value)$")
163
- value: (string_literal) @path))))
164
- name: (identifier) @method_name) @method
165
- `,
166
- },
167
- ],
168
- });
124
+ // ─── Consumer: OpenFeign `@RequestLine("METHOD /path")` parsing ───────
125
+ // OpenFeign's native annotation pairs an HTTP method and path in a single
126
+ // string literal see https://github.com/OpenFeign/feign#interface-annotations.
127
+ // It is method-level only and is mutually exclusive with Spring MVC
128
+ // `@GetMapping` / `@PostMapping` etc. on the same method (mixing them
129
+ // requires a different Feign Contract — they are not combined). The match
130
+ // itself comes from `JAVA_ROUTE_ANNOTATION_PATTERNS`; this regex splits the
131
+ // verb from the path of the captured literal.
132
+ //
133
+ // Examples:
134
+ // @RequestLine("GET /users/{id}")
135
+ // @RequestLine("POST /users?status=active")
136
+ const REQUEST_LINE_VERB_RE = /^\s*(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s+(\S.*?)\s*$/i;
137
+ /**
138
+ * Parse a Feign `@RequestLine` value into a method + path pair.
139
+ *
140
+ * `@RequestLine("METHOD /path[?query]")` packs both fields in one string;
141
+ * the query portion is dropped because contract IDs are method+path only
142
+ * (consistent with how other consumers like RestTemplate/WebClient drop
143
+ * query strings when their values are inline literals).
144
+ *
145
+ * Returns null if the value is not a recognized HTTP verb followed by a
146
+ * path beginning with `/`.
147
+ */
148
+ function parseRequestLine(raw) {
149
+ const match = REQUEST_LINE_VERB_RE.exec(raw);
150
+ if (!match)
151
+ return null;
152
+ const [, verb, rest] = match;
153
+ if (typeof verb !== 'string' || typeof rest !== 'string')
154
+ return null;
155
+ const queryIdx = rest.indexOf('?');
156
+ const pathOnly = (queryIdx >= 0 ? rest.slice(0, queryIdx) : rest).trim();
157
+ if (!pathOnly.startsWith('/'))
158
+ return null;
159
+ return { method: verb.toUpperCase(), path: pathOnly };
160
+ }
169
161
  // ─── Consumer: Spring RestTemplate (object-named + method-named) ──────
170
162
  // RestTemplate.getForObject / getForEntity → GET
171
163
  // RestTemplate.postForObject / postForEntity → POST
@@ -364,38 +356,110 @@ function hasAnnotation(node, names) {
364
356
  }
365
357
  return false;
366
358
  }
367
- function collectTypePrefixes(tree) {
368
- const prefixByTypeId = new Map();
369
- for (const match of runCompiledPatterns(SPRING_TYPE_PREFIX_PATTERNS, tree)) {
370
- const prefixNode = match.captures.prefix;
371
- const typeNode = match.captures.type;
372
- if (!prefixNode || !typeNode)
373
- continue;
374
- const prefix = unquoteLiteral(prefixNode.text);
375
- if (prefix !== null)
376
- prefixByTypeId.set(typeNode.id, prefix);
377
- }
378
- return prefixByTypeId;
359
+ /**
360
+ * A named annotation argument contributes a route only when its member key is
361
+ * `path` or `value`; a positional argument (no key node) always qualifies.
362
+ * This is the JS-side replacement for the in-query `^(path|value)$` filter and
363
+ * drops Spring's non-route string attributes (`produces`, `consumes`,
364
+ * `headers`, `name`, `params`) that would otherwise be mis-read as routes.
365
+ */
366
+ function isRouteMemberKey(keyNode) {
367
+ if (!keyNode)
368
+ return true;
369
+ return keyNode.text === 'path' || keyNode.text === 'value';
379
370
  }
380
- function collectMethodRoutes(tree) {
381
- const routesByMethodId = new Map();
382
- for (const match of runCompiledPatterns(SPRING_METHOD_ROUTE_PATTERNS, tree)) {
383
- const annNode = match.captures.ann;
384
- const pathNode = match.captures.path;
385
- const methodNode = match.captures.method;
386
- if (!annNode || !pathNode || !methodNode)
387
- continue;
388
- const httpMethod = METHOD_ANNOTATION_TO_HTTP[annNode.text];
389
- if (!httpMethod)
371
+ /**
372
+ * Resolve every Java route-defining annotation in a single tree-sitter pass.
373
+ *
374
+ * The generic `JAVA_ROUTE_ANNOTATION_PATTERNS` query yields one match per
375
+ * annotation-carrying-a-string-argument on any class / interface / method. This
376
+ * loop reads the annotation name and declaration kind to decide what each match
377
+ * means, ignoring annotations it does not recognise. The HTTP verb map
378
+ * (`METHOD_ANNOTATION_TO_HTTP`) and the `path`/`value` key filter
379
+ * (`isRouteMemberKey`) live here rather than in the query (see its header).
380
+ */
381
+ function scanRouteAnnotations(tree) {
382
+ const matches = runCompiledPatterns(JAVA_ROUTE_ANNOTATION_PATTERNS, tree);
383
+ // The two prefix maps intentionally diverge for the same interface node:
384
+ // `prefixByTypeId` feeds the Spring *provider* path (class prefix +
385
+ // collectSpringTypes cross-file inheritance), while `feignPrefixByInterfaceId`
386
+ // feeds the OpenFeign *consumer* path in scan(). An interface carrying both
387
+ // `@RequestMapping` and `@FeignClient(path)` lands a different value in each.
388
+ const prefixByTypeId = new Map();
389
+ const feignPrefixByInterfaceId = new Map();
390
+ const methodRoutes = [];
391
+ const requestLines = [];
392
+ // Interface `@RequestMapping` prefixes rank below `@FeignClient(path)`;
393
+ // collect them and apply only after the FeignClient pass below.
394
+ const interfaceRequestMappingPrefixes = [];
395
+ for (const { captures } of matches) {
396
+ const annNode = captures.ann;
397
+ const node = captures.node;
398
+ const valueNode = captures.value;
399
+ if (!annNode || !node || !valueNode)
390
400
  continue;
391
- const rawPath = unquoteLiteral(pathNode.text);
392
- if (rawPath === null)
401
+ const ann = annNode.text;
402
+ const keyNode = captures.key; // undefined for the positional shape
403
+ if (node.type === 'method_declaration') {
404
+ // Method-level: a Spring `@(Get|...)Mapping` route, or native `@RequestLine`.
405
+ const httpMethod = METHOD_ANNOTATION_TO_HTTP[ann];
406
+ if (httpMethod) {
407
+ if (!isRouteMemberKey(keyNode))
408
+ continue;
409
+ const rawPath = unquoteLiteral(valueNode.text);
410
+ if (rawPath !== null) {
411
+ methodRoutes.push({
412
+ methodNode: node,
413
+ methodName: captures.member?.text ?? null,
414
+ httpMethod,
415
+ rawPath,
416
+ });
417
+ }
418
+ }
419
+ else if (ann === 'RequestLine') {
420
+ // Feign packs verb + path in one literal; its only named argument is `value`.
421
+ if (keyNode && keyNode.text !== 'value')
422
+ continue;
423
+ const raw = unquoteLiteral(valueNode.text);
424
+ const parsed = raw !== null ? parseRequestLine(raw) : null;
425
+ if (parsed) {
426
+ requestLines.push({
427
+ methodNode: node,
428
+ methodName: captures.member?.text ?? null,
429
+ parsed,
430
+ });
431
+ }
432
+ }
393
433
  continue;
394
- const routes = routesByMethodId.get(methodNode.id) ?? [];
395
- routes.push({ method: httpMethod, path: rawPath });
396
- routesByMethodId.set(methodNode.id, routes);
434
+ }
435
+ // Type-level (class or interface): a Spring `@RequestMapping` URL prefix, or
436
+ // — on an interface — an OpenFeign `@FeignClient(path = "...")` prefix.
437
+ if (ann === 'RequestMapping') {
438
+ if (!isRouteMemberKey(keyNode))
439
+ continue;
440
+ const prefix = unquoteLiteral(valueNode.text);
441
+ if (prefix !== null) {
442
+ prefixByTypeId.set(node.id, prefix);
443
+ if (node.type === 'interface_declaration') {
444
+ interfaceRequestMappingPrefixes.push({ id: node.id, prefix });
445
+ }
446
+ }
447
+ }
448
+ else if (ann === 'FeignClient' && node.type === 'interface_declaration') {
449
+ // Feign's `name`/`value` identify a service, not a path — only `path` is a prefix.
450
+ if (!keyNode || keyNode.text !== 'path')
451
+ continue;
452
+ const prefix = unquoteLiteral(valueNode.text);
453
+ if (prefix !== null && !feignPrefixByInterfaceId.has(node.id)) {
454
+ feignPrefixByInterfaceId.set(node.id, prefix);
455
+ }
456
+ }
457
+ }
458
+ for (const { id, prefix } of interfaceRequestMappingPrefixes) {
459
+ if (!feignPrefixByInterfaceId.has(id))
460
+ feignPrefixByInterfaceId.set(id, prefix);
397
461
  }
398
- return routesByMethodId;
462
+ return { prefixByTypeId, feignPrefixByInterfaceId, methodRoutes, requestLines };
399
463
  }
400
464
  function collectDirectMethods(typeNode) {
401
465
  const out = [];
@@ -432,8 +496,13 @@ function collectImplementedInterfaces(typeNode) {
432
496
  return out;
433
497
  }
434
498
  function collectSpringTypes(filePath, tree) {
435
- const prefixByTypeId = collectTypePrefixes(tree);
436
- const routesByMethodId = collectMethodRoutes(tree);
499
+ const { prefixByTypeId, methodRoutes } = scanRouteAnnotations(tree);
500
+ const routesByMethodId = new Map();
501
+ for (const route of methodRoutes) {
502
+ const routes = routesByMethodId.get(route.methodNode.id) ?? [];
503
+ routes.push({ method: route.httpMethod, path: route.rawPath });
504
+ routesByMethodId.set(route.methodNode.id, routes);
505
+ }
437
506
  const out = [];
438
507
  for (const match of runCompiledPatterns(SPRING_TYPE_DECLARATION_PATTERNS, tree)) {
439
508
  const typeNode = match.captures.type;
@@ -521,59 +590,60 @@ export const JAVA_HTTP_PLUGIN = {
521
590
  language: Java,
522
591
  scan(tree) {
523
592
  const out = [];
524
- // ─── Providers: Spring class prefix + method annotations ────────
525
- const prefixByTypeId = collectTypePrefixes(tree);
526
- const feignPrefixByInterfaceId = new Map();
527
- for (const match of runCompiledPatterns(FEIGN_INTERFACE_PREFIX_PATTERNS, tree)) {
528
- const prefixNode = match.captures.prefix;
529
- const interfaceNode = match.captures.interface;
530
- if (!prefixNode || !interfaceNode)
531
- continue;
532
- const prefix = unquoteLiteral(prefixNode.text);
533
- if (prefix !== null && !feignPrefixByInterfaceId.has(interfaceNode.id))
534
- feignPrefixByInterfaceId.set(interfaceNode.id, prefix);
535
- }
536
- for (const match of runCompiledPatterns(SPRING_METHOD_ROUTE_PATTERNS, tree)) {
537
- const annNode = match.captures.ann;
538
- const pathNode = match.captures.path;
539
- const nameNode = match.captures.method_name;
540
- const methodNode = match.captures.method;
541
- if (!annNode || !pathNode || !methodNode)
542
- continue;
543
- const httpMethod = METHOD_ANNOTATION_TO_HTTP[annNode.text];
544
- if (!httpMethod)
545
- continue;
546
- const rawPath = unquoteLiteral(pathNode.text);
547
- if (rawPath === null)
548
- continue;
549
- const enclosingInterface = findEnclosingInterface(methodNode);
593
+ // ─── Spring providers + OpenFeign consumers (one query pass) ────
594
+ // `scanRouteAnnotations` resolves every route-defining annotation —
595
+ // class/interface prefixes, method `@(Get|...)Mapping`s and native
596
+ // `@RequestLine`s from a single `matches()` pass over the tree.
597
+ const { prefixByTypeId, feignPrefixByInterfaceId, methodRoutes, requestLines } = scanRouteAnnotations(tree);
598
+ // A `@(Get|...)Mapping` inside a `@FeignClient` interface is an OpenFeign
599
+ // *consumer* (it describes a remote call); the same annotation inside a
600
+ // class is a Spring *provider*. A mapping on a non-Feign interface has no
601
+ // enclosing class and is dropped here — interface→controller inheritance is
602
+ // handled by `scanProject`.
603
+ for (const route of methodRoutes) {
604
+ const enclosingInterface = findEnclosingInterface(route.methodNode);
550
605
  if (enclosingInterface && hasAnnotation(enclosingInterface, 'FeignClient')) {
551
606
  const prefix = feignPrefixByInterfaceId.get(enclosingInterface.id) ?? '';
552
- const fullPath = joinPath(prefix, rawPath);
553
607
  out.push({
554
608
  role: 'consumer',
555
609
  framework: 'openfeign',
556
- method: httpMethod,
557
- path: fullPath,
558
- name: nameNode?.text ?? null,
610
+ method: route.httpMethod,
611
+ path: joinPath(prefix, route.rawPath),
612
+ name: route.methodName,
559
613
  confidence: 0.7,
560
614
  });
561
615
  continue;
562
616
  }
563
- const enclosingClass = findEnclosingClass(methodNode);
617
+ const enclosingClass = findEnclosingClass(route.methodNode);
564
618
  if (!enclosingClass)
565
619
  continue;
566
620
  const prefix = prefixByTypeId.get(enclosingClass.id) ?? '';
567
- const fullPath = joinPath(prefix, rawPath);
568
621
  out.push({
569
622
  role: 'provider',
570
623
  framework: 'spring',
571
- method: httpMethod,
572
- path: fullPath,
573
- name: nameNode?.text ?? null,
624
+ method: route.httpMethod,
625
+ path: joinPath(prefix, route.rawPath),
626
+ name: route.methodName,
574
627
  confidence: 0.8,
575
628
  });
576
629
  }
630
+ // Native OpenFeign `@RequestLine("METHOD /path")`. Method-level only; the
631
+ // enclosing interface MUST carry `@FeignClient`, otherwise the same
632
+ // annotation name in unrelated libraries would be a false positive.
633
+ for (const requestLine of requestLines) {
634
+ const enclosingInterface = findEnclosingInterface(requestLine.methodNode);
635
+ if (!enclosingInterface || !hasAnnotation(enclosingInterface, 'FeignClient'))
636
+ continue;
637
+ const prefix = feignPrefixByInterfaceId.get(enclosingInterface.id) ?? '';
638
+ out.push({
639
+ role: 'consumer',
640
+ framework: 'openfeign',
641
+ method: requestLine.parsed.method,
642
+ path: joinPath(prefix, requestLine.parsed.path),
643
+ name: requestLine.methodName,
644
+ confidence: 0.75,
645
+ });
646
+ }
577
647
  // ─── Consumers: RestTemplate ────────────────────────────────────
578
648
  for (const match of runCompiledPatterns(REST_TEMPLATE_PATTERNS, tree)) {
579
649
  const methodNode = match.captures.method;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.6-rc.93",
3
+ "version": "1.6.6-rc.94",
4
4
  "description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
5
5
  "author": "Abhigyan Patwari",
6
6
  "license": "PolyForm-Noncommercial-1.0.0",