gitnexus 1.6.9-rc.11 → 1.6.9-rc.12

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.
@@ -732,18 +732,20 @@ async function stitchCrossRepo(deps, p, fromEp, toEp, groupDir, notes) {
732
732
  const FILE_BASENAME_RE = /\.(ts|tsx|js|jsx|mjs|cjs|py|go|php|java|kt|kts|rb|cs|rs|swift|dart|scala|c|cc|cpp|cxx|h|hpp|m|mm)$/i;
733
733
  /**
734
734
  * A provider endpoint's display label. A resolved handler has a real function
735
- * name; the source-scan fallbacks leave a generic token (`'handler'`/`'fetch'`)
736
- * or a file basename. Those are treated as anonymous and shown as
735
+ * name; the source-scan fallbacks leave a generic token (`'handler'`/`'fetch'`,
736
+ * or `'route'` for an unresolved named-controller / closure Laravel route) or a
737
+ * file basename. Those are treated as anonymous and shown as
737
738
  * `<METHOD /path handler>` so the endpoint is still identifiable by route. When
738
739
  * the bridge row carries a resolved `providerUid`, the name IS a real symbol —
739
- * the `'handler'`/`'fetch'` sentinel check is suppressed so a function genuinely
740
- * named `handler` is not mislabeled anonymous.
740
+ * the sentinel check is suppressed so a function genuinely named `handler` (or,
741
+ * hypothetically, `route`) is not mislabeled anonymous.
741
742
  */
742
743
  function providerLabel(providerName, contractId, providerUid) {
743
744
  const resolved = providerUid !== '';
744
745
  const generic = providerName === '' ||
745
746
  FILE_BASENAME_RE.test(providerName) ||
746
- (!resolved && (providerName === 'handler' || providerName === 'fetch'));
747
+ (!resolved &&
748
+ (providerName === 'handler' || providerName === 'fetch' || providerName === 'route'));
747
749
  return generic
748
750
  ? { label: `<${contractId} handler>`, anon: true }
749
751
  : { label: providerName, anon: false };
@@ -9,8 +9,11 @@ import { compilePatterns, runCompiledPatterns, unquoteLiteral, } from '../tree-s
9
9
  */
10
10
  // ─── Provider: framework routing ──────────────────────────────────────
11
11
  // Matches `\w+\.GET(...)` etc. (gin, echo, chi all share this shape).
12
- // Captures the HTTP method (field name), path literal, and handler
13
- // identifier passed as the second argument.
12
+ // Captures the HTTP method (field name), path literal, and the handler
13
+ // anchored to the LAST argument (`@handler .`) so a variadic middleware
14
+ // chain (`r.GET("/x", mw, handler)`, gin/echo/chi style) binds the real
15
+ // handler, not a middleware identifier (which would otherwise over-match
16
+ // and attach the route to the wrong symbol — see #2276 review).
14
17
  const FRAMEWORK_ROUTE_PATTERNS = compilePatterns({
15
18
  name: 'go-framework-route',
16
19
  language: Go,
@@ -23,7 +26,8 @@ const FRAMEWORK_ROUTE_PATTERNS = compilePatterns({
23
26
  field: (field_identifier) @http_method (#match? @http_method "^(GET|POST|PUT|DELETE|PATCH)$"))
24
27
  arguments: (argument_list
25
28
  (interpreted_string_literal) @path
26
- (identifier) @handler))
29
+ [(identifier) (func_literal)] @handler
30
+ .))
27
31
  `,
28
32
  },
29
33
  ],
@@ -42,7 +46,8 @@ const HANDLE_FUNC_PATTERNS = compilePatterns({
42
46
  field: (field_identifier) @fn (#eq? @fn "HandleFunc"))
43
47
  arguments: (argument_list
44
48
  (interpreted_string_literal) @path
45
- (identifier) @handler))
49
+ [(identifier) (func_literal)] @handler
50
+ .))
46
51
  `,
47
52
  },
48
53
  ],
@@ -125,12 +130,18 @@ export const GO_HTTP_PLUGIN = {
125
130
  const path = unquoteLiteral(pathNode.text);
126
131
  if (path === null)
127
132
  continue;
133
+ // An inline `func(){…}` handler has no name → emit `name: null` and a
134
+ // `line` so it resolves to its containing/closure symbol by line-span
135
+ // containment (like a consumer). A named identifier handler keeps its
136
+ // name and resolves by name; `line` is harmless there.
137
+ const isInlineHandler = handlerNode?.type === 'func_literal';
128
138
  out.push({
129
139
  role: 'provider',
130
140
  framework: 'go-framework',
131
141
  method: methodNode.text.toUpperCase(),
132
142
  path,
133
- name: handlerNode?.text ?? null,
143
+ name: isInlineHandler ? null : (handlerNode?.text ?? null),
144
+ line: (handlerNode ?? pathNode).startPosition.row + 1,
134
145
  confidence: 0.8,
135
146
  });
136
147
  }
@@ -143,12 +154,16 @@ export const GO_HTTP_PLUGIN = {
143
154
  const path = unquoteLiteral(pathNode.text);
144
155
  if (path === null)
145
156
  continue;
157
+ // Inline `func(){…}` handler → resolve by containment (see go-framework
158
+ // note above); a named handler resolves by name.
159
+ const isInlineHandler = handlerNode?.type === 'func_literal';
146
160
  out.push({
147
161
  role: 'provider',
148
162
  framework: 'go-stdlib',
149
163
  method: 'GET',
150
164
  path,
151
- name: handlerNode?.text ?? null,
165
+ name: isInlineHandler ? null : (handlerNode?.text ?? null),
166
+ line: (handlerNode ?? pathNode).startPosition.row + 1,
152
167
  confidence: 0.8,
153
168
  });
154
169
  }
@@ -634,6 +634,13 @@ export const JAVA_HTTP_PLUGIN = {
634
634
  method: route.httpMethod,
635
635
  path: joinPath(prefix, route.rawPath),
636
636
  name: route.methodName,
637
+ // Spring providers are named controller methods resolved BY NAME, so
638
+ // `line` is inert — a named provider never falls through to line-span
639
+ // containment. Gate it on a present name so a (grammar-impossible)
640
+ // nameless provider degrades to file-level rather than resolving by
641
+ // containment to the enclosing class. Wired for consumer-emit parity
642
+ // and a future inline DSL.
643
+ line: route.methodName ? route.methodNode.startPosition.row + 1 : undefined,
637
644
  confidence: 0.8,
638
645
  });
639
646
  }
@@ -977,6 +977,13 @@ function buildKotlinPlugin(language) {
977
977
  method: httpMethod,
978
978
  path: joinPath(prefix, rawPath),
979
979
  name: nameNode?.text ?? null,
980
+ // Spring providers are named controller methods resolved BY NAME, so
981
+ // `line` is inert — a named provider never falls through to line-span
982
+ // containment. Gate it on a present name so a (grammar-impossible)
983
+ // nameless provider degrades to file-level rather than resolving by
984
+ // containment to the enclosing class. Wired for consumer-emit parity
985
+ // and a future inline DSL.
986
+ line: nameNode?.text ? methodNode.startPosition.row + 1 : undefined,
980
987
  confidence: 0.8,
981
988
  });
982
989
  }
@@ -27,7 +27,9 @@ const LARAVEL_ROUTE_SPEC = {
27
27
  (scoped_call_expression
28
28
  scope: (name) @scope (#eq? @scope "Route")
29
29
  name: (name) @method (#match? @method "^(get|post|put|delete|patch)$")
30
- arguments: (arguments . (argument (string) @path)))
30
+ arguments: (arguments
31
+ . (argument (string) @path)
32
+ (argument [(anonymous_function) (arrow_function)] @closure)?))
31
33
  `,
32
34
  };
33
35
  const HTTP_FACADE_SPEC = {
@@ -125,12 +127,22 @@ export const PHP_HTTP_PLUGIN = {
125
127
  const path = phpStringText(pathNode);
126
128
  if (path === null)
127
129
  continue;
130
+ // A closure handler (`Route::get('/x', function(){…})` / `fn() => …`) has
131
+ // no name → emit `name: null` + the registration line so it resolves to
132
+ // its containing symbol (e.g. a service-provider `boot()` or controller
133
+ // method) by line-span containment. A named-controller route keeps the
134
+ // `'route'` label — resolving its array/string handler to a real method is
135
+ // a separate, graph-backed concern. NOTE: a closure at FILE scope
136
+ // (routes/web.php) has no enclosing function and PHP closures are not yet
137
+ // indexed as symbols, so it still degrades to file-level (see #2276).
138
+ const closureNode = match.captures.closure;
128
139
  out.push({
129
140
  role: 'provider',
130
141
  framework: 'laravel',
131
142
  method: methodNode.text.toUpperCase(),
132
143
  path,
133
- name: 'route',
144
+ name: closureNode ? null : 'route',
145
+ line: (closureNode ?? pathNode).startPosition.row + 1,
134
146
  confidence: 0.8,
135
147
  });
136
148
  }
@@ -967,6 +967,12 @@ export const PYTHON_HTTP_PLUGIN = {
967
967
  method: httpMethod,
968
968
  path,
969
969
  name: null,
970
+ // The decorated handler has no captured name → resolve by line-span
971
+ // containment. Best-effort fallback: FastAPI routes are graph-backed
972
+ // (ingestion decorator routes) and the function span starts at `def`
973
+ // (decorators excluded), so this lands the single-decorator case and
974
+ // degrades to file-level for multi-decorator stacks.
975
+ line: pathNode.startPosition.row + 1,
970
976
  confidence: 0.8,
971
977
  });
972
978
  }
@@ -1008,6 +1014,8 @@ export const PYTHON_HTTP_PLUGIN = {
1008
1014
  method: httpMethod,
1009
1015
  path: p,
1010
1016
  name: null,
1017
+ // Best-effort containment fallback — see the @app provider note above.
1018
+ line: pathNode.startPosition.row + 1,
1011
1019
  confidence: 0.8,
1012
1020
  });
1013
1021
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.9-rc.11",
3
+ "version": "1.6.9-rc.12",
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",