gitnexus 1.6.6-rc.151 → 1.6.6-rc.152

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.
@@ -335,6 +335,19 @@ function joinPath(prefix, methodPath) {
335
335
  return `/${cleanSub}`;
336
336
  return `/${cleanPrefix}/${cleanSub}`;
337
337
  }
338
+ function joinInheritedSpringPath(controllerPrefix, inheritedPath, inheritedOwnerPrefix = '') {
339
+ const joined = joinPath(controllerPrefix, inheritedPath);
340
+ const cleanPrefix = controllerPrefix.replace(/^\/+/, '').replace(/\/+$/, '');
341
+ const cleanOwnerPrefix = inheritedOwnerPrefix.replace(/^\/+/, '').replace(/\/+$/, '');
342
+ const cleanInherited = inheritedPath.replace(/^\/+/, '');
343
+ if (!cleanPrefix)
344
+ return joined;
345
+ if (cleanPrefix === cleanOwnerPrefix &&
346
+ (cleanInherited === cleanPrefix || cleanInherited.startsWith(`${cleanPrefix}/`))) {
347
+ return `/${cleanInherited}`;
348
+ }
349
+ return joined;
350
+ }
338
351
  function getNodeName(node) {
339
352
  return node.childForFieldName('name')?.text ?? null;
340
353
  }
@@ -543,6 +556,7 @@ function scanSpringProject(files) {
543
556
  const routes = method.routes.map((route) => ({
544
557
  method: route.method,
545
558
  path: type.classPrefix ? joinPath(type.classPrefix, route.path) : route.path,
559
+ ownerPrefix: type.classPrefix,
546
560
  }));
547
561
  if (routes.length > 0)
548
562
  methodMap.set(method.name, routes);
@@ -563,7 +577,7 @@ function scanSpringProject(files) {
563
577
  const routes = routeMap.get(method.name) ?? [];
564
578
  return routes.map((route) => ({
565
579
  method: route.method,
566
- path: joinPath(type.classPrefix, route.path),
580
+ path: joinInheritedSpringPath(type.classPrefix, route.path, route.ownerPrefix),
567
581
  }));
568
582
  });
569
583
  for (const route of inheritedRoutes) {
@@ -27,11 +27,11 @@ import type { CaptureMatch } from '../../../../_shared/index.js';
27
27
  * 1. **Full SFC content** (sequential path, <15 files): `sourceText`
28
28
  * contains the whole `.vue` file with `<template>`, `<script>`, etc.
29
29
  * `extractVueScript` extracts the script block and we delegate to
30
- * `emitTsScopeCaptures` with that extracted content.
30
+ * `emitTsScopeCaptures` or `emitJsScopeCaptures` based on `lang`.
31
31
  *
32
32
  * 2. **Already-extracted script content** (worker-mode path, ≥15 files):
33
33
  * the parse worker calls `extractVueScript` itself before calling
34
- * `extractParsedFile`, so `sourceText` is already the bare TypeScript
34
+ * `extractParsedFile`, so `sourceText` is already the bare script
35
35
  * text with no `<script>` tags. The caller marks this explicitly via
36
36
  * `sourceMeta.sourceKind === 'pre-extracted-script'`.
37
37
  *
@@ -42,4 +42,5 @@ import type { CaptureMatch } from '../../../../_shared/index.js';
42
42
  */
43
43
  export declare function emitVueScopeCaptures(sourceText: string, filePath: string, cachedTree?: unknown, sourceMeta?: {
44
44
  sourceKind?: 'full-file' | 'pre-extracted-script';
45
+ setupLang?: string;
45
46
  }): readonly CaptureMatch[];
@@ -20,6 +20,7 @@
20
20
  */
21
21
  import { extractVueScript } from '../../vue-sfc-extractor.js';
22
22
  import { emitTsScopeCaptures } from '../typescript/captures.js';
23
+ import { emitJsScopeCaptures } from '../javascript/captures.js';
23
24
  /**
24
25
  * Emit scope captures for a Vue SFC.
25
26
  *
@@ -28,11 +29,11 @@ import { emitTsScopeCaptures } from '../typescript/captures.js';
28
29
  * 1. **Full SFC content** (sequential path, <15 files): `sourceText`
29
30
  * contains the whole `.vue` file with `<template>`, `<script>`, etc.
30
31
  * `extractVueScript` extracts the script block and we delegate to
31
- * `emitTsScopeCaptures` with that extracted content.
32
+ * `emitTsScopeCaptures` or `emitJsScopeCaptures` based on `lang`.
32
33
  *
33
34
  * 2. **Already-extracted script content** (worker-mode path, ≥15 files):
34
35
  * the parse worker calls `extractVueScript` itself before calling
35
- * `extractParsedFile`, so `sourceText` is already the bare TypeScript
36
+ * `extractParsedFile`, so `sourceText` is already the bare script
36
37
  * text with no `<script>` tags. The caller marks this explicitly via
37
38
  * `sourceMeta.sourceKind === 'pre-extracted-script'`.
38
39
  *
@@ -49,10 +50,18 @@ export function emitVueScopeCaptures(sourceText, filePath, cachedTree, sourceMet
49
50
  return emitTsScopeCaptures(sourceText, filePath, cachedTree);
50
51
  }
51
52
  if (sourceMeta?.sourceKind === 'pre-extracted-script') {
53
+ // Worker-mode path: the parse worker always uses TypeScript grammar for
54
+ // .vue files. Lang-based grammar selection is a sequential-path feature.
52
55
  return emitTsScopeCaptures(sourceText, filePath, cachedTree);
53
56
  }
54
57
  const extracted = extractVueScript(sourceText);
55
58
  if (extracted === null)
56
59
  return [];
60
+ // Select captures based on script lang attribute.
61
+ // Use TS grammar unless ALL blocks explicitly request JS/JSX.
62
+ // Mixed-lang: TS handles JS natively; JS grammar chokes on TS syntax.
63
+ if (extracted.lang === 'js' || extracted.lang === 'jsx') {
64
+ return emitJsScopeCaptures(extracted.scriptContent, filePath, cachedTree);
65
+ }
57
66
  return emitTsScopeCaptures(extracted.scriptContent, filePath, cachedTree);
58
67
  }
@@ -9,19 +9,20 @@
9
9
  export interface VueScriptExtraction {
10
10
  /** Extracted script content (TypeScript/JavaScript) */
11
11
  scriptContent: string;
12
- /** 0-based line number in the .vue file where the script content starts */
12
+ /** 1-based line number in the .vue file where the script content starts
13
+ * (used as offset from tree-sitter's 0-based row). */
13
14
  lineOffset: number;
14
- /** true if the primary block is <script setup> */
15
+ /** true if at least one block is <script setup> */
15
16
  isSetup: boolean;
17
+ /** Value of the `lang` attribute on the extracted script block (e.g. "ts", "js", "tsx", "jsx", or "" for default). */
18
+ lang: string;
16
19
  }
17
20
  /**
18
21
  * Extract script content from a Vue SFC.
19
22
  *
20
- * When both <script> and <script setup> are present, returns only the
21
- * <script setup> block (the dominant pattern 94% of Vue files in real
22
- * projects use setup). The <script> (non-setup) block typically contains
23
- * only `defineOptions` or legacy option merges and is less important for
24
- * the knowledge graph.
23
+ * When both <script> and <script setup> are present, the content of all
24
+ * blocks is combined (non-setup first, then setup) so the full script
25
+ * surface is available to the knowledge graph.
25
26
  */
26
27
  export declare function extractVueScript(vueContent: string): VueScriptExtraction | null;
27
28
  /**
@@ -210,11 +210,9 @@ function parseScriptBlock(attrs, content, precedingText) {
210
210
  /**
211
211
  * Extract script content from a Vue SFC.
212
212
  *
213
- * When both <script> and <script setup> are present, returns only the
214
- * <script setup> block (the dominant pattern 94% of Vue files in real
215
- * projects use setup). The <script> (non-setup) block typically contains
216
- * only `defineOptions` or legacy option merges and is less important for
217
- * the knowledge graph.
213
+ * When both <script> and <script setup> are present, the content of all
214
+ * blocks is combined (non-setup first, then setup) so the full script
215
+ * surface is available to the knowledge graph.
218
216
  */
219
217
  export function extractVueScript(vueContent) {
220
218
  const blocks = [];
@@ -227,13 +225,21 @@ export function extractVueScript(vueContent) {
227
225
  }
228
226
  if (blocks.length === 0)
229
227
  return null;
230
- // Prefer <script setup> if present
231
- const setupBlock = blocks.find((b) => b.isSetup);
232
- const primary = setupBlock ?? blocks[0];
228
+ // Merge all blocks: non-setup first, then setup, so content order is stable.
229
+ const nonSetupBlocks = blocks.filter((b) => !b.isSetup);
230
+ const setupBlocks = blocks.filter((b) => b.isSetup);
231
+ const ordered = [...nonSetupBlocks, ...setupBlocks];
232
+ const combinedContent = ordered.map((b) => b.content).join('\n');
233
+ const lineOffset = ordered[0].lineOffset;
234
+ // Only use JavaScript grammar when ALL blocks are explicitly lang="js"
235
+ // or lang="jsx". If any block omits lang or uses ts/tsx, TypeScript wins.
236
+ const allBlocksJs = blocks.length > 0 && blocks.every((b) => b.lang === 'js' || b.lang === 'jsx');
237
+ const lang = allBlocksJs ? 'js' : '';
233
238
  return {
234
- scriptContent: primary.content,
235
- lineOffset: primary.lineOffset,
236
- isSetup: primary.isSetup,
239
+ scriptContent: combinedContent,
240
+ lineOffset,
241
+ isSetup: blocks.some((b) => b.isSetup),
242
+ lang,
237
243
  };
238
244
  }
239
245
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.6-rc.151",
3
+ "version": "1.6.6-rc.152",
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",