gitnexus 1.6.6-rc.149 → 1.6.6-rc.150

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.
@@ -1,11 +1,2 @@
1
1
  import type { FieldExtractionConfig } from '../generic.js';
2
- /**
3
- * Go field extraction config.
4
- *
5
- * Go struct fields live inside type_declaration > type_spec > struct_type >
6
- * field_declaration_list > field_declaration.
7
- *
8
- * Visibility in Go is based on the first character: uppercase = exported (public),
9
- * lowercase = unexported (package).
10
- */
11
2
  export declare const goConfig: FieldExtractionConfig;
@@ -10,13 +10,48 @@ import { extractSimpleTypeName } from '../../type-extractors/shared.js';
10
10
  * Visibility in Go is based on the first character: uppercase = exported (public),
11
11
  * lowercase = unexported (package).
12
12
  */
13
+ function goVisibilityForName(name) {
14
+ const first = name.charAt(0);
15
+ return first === first.toUpperCase() && first !== first.toLowerCase() ? 'public' : 'package';
16
+ }
17
+ function extractGoFieldNames(node) {
18
+ const names = [];
19
+ for (let i = 0; i < node.namedChildCount; i++) {
20
+ const child = node.namedChild(i);
21
+ if (child?.type === 'field_identifier')
22
+ names.push(child.text);
23
+ }
24
+ return names;
25
+ }
13
26
  export const goConfig = {
14
27
  language: SupportedLanguages.Go,
15
- typeDeclarationNodes: ['type_declaration'],
28
+ typeDeclarationNodes: ['type_declaration', 'struct_type'],
16
29
  fieldNodeTypes: ['field_declaration'],
17
30
  bodyNodeTypes: ['field_declaration_list'],
18
31
  defaultVisibility: 'package',
32
+ extractOwnerName(node) {
33
+ if (node.type === 'struct_type') {
34
+ return node.parent?.type === 'type_spec'
35
+ ? node.parent.childForFieldName('name')?.text
36
+ : undefined;
37
+ }
38
+ const typeSpec = node.namedChildren.find((child) => child.type === 'type_spec');
39
+ return typeSpec?.childForFieldName('name')?.text;
40
+ },
41
+ findBodyNodes(node) {
42
+ if (node.type === 'struct_type') {
43
+ const body = node.namedChildren.find((child) => child.type === 'field_declaration_list');
44
+ return body ? [body] : [];
45
+ }
46
+ const typeSpec = node.namedChildren.find((child) => child.type === 'type_spec');
47
+ const typeNode = typeSpec?.childForFieldName('type');
48
+ const body = typeNode?.namedChildren.find((child) => child.type === 'field_declaration_list');
49
+ return body ? [body] : [];
50
+ },
19
51
  extractName(node) {
52
+ const firstName = extractGoFieldNames(node)[0];
53
+ if (firstName)
54
+ return firstName;
20
55
  // field_declaration > name:(field_identifier)
21
56
  const name = node.childForFieldName('name');
22
57
  if (name)
@@ -29,6 +64,7 @@ export const goConfig = {
29
64
  }
30
65
  return undefined;
31
66
  },
67
+ extractNames: extractGoFieldNames,
32
68
  extractType(node) {
33
69
  // field_declaration > type:(type_identifier | pointer_type | ...)
34
70
  const typeNode = node.childForFieldName('type');
@@ -51,6 +87,9 @@ export const goConfig = {
51
87
  }
52
88
  return 'package';
53
89
  },
90
+ extractVisibilityForName(_node, name) {
91
+ return goVisibilityForName(name);
92
+ },
54
93
  isStatic(_node) {
55
94
  return false; // Go has no static fields
56
95
  },
@@ -19,6 +19,10 @@ export interface FieldExtractionConfig {
19
19
  bodyNodeTypes: string[];
20
20
  /** Default visibility when no modifier is present */
21
21
  defaultVisibility: FieldVisibility;
22
+ /** Extract owner type name from a type declaration node. */
23
+ extractOwnerName?: (node: SyntaxNode) => string | undefined;
24
+ /** Find body nodes inside a type declaration node. */
25
+ findBodyNodes?: (node: SyntaxNode) => SyntaxNode[];
22
26
  /**
23
27
  * Extract field name from a field declaration node.
24
28
  * Use this for nodes that declare exactly one field.
@@ -35,6 +39,8 @@ export interface FieldExtractionConfig {
35
39
  extractType: (node: SyntaxNode) => string | undefined;
36
40
  /** Extract visibility from a field declaration node */
37
41
  extractVisibility: (node: SyntaxNode) => FieldVisibility;
42
+ /** Extract visibility for one field name from a multi-name declaration. */
43
+ extractVisibilityForName?: (node: SyntaxNode, name: string) => FieldVisibility;
38
44
  /** Check if a field is static */
39
45
  isStatic: (node: SyntaxNode) => boolean;
40
46
  /** Check if a field is readonly/final/const */
@@ -21,10 +21,9 @@ export function createFieldExtractor(config) {
21
21
  extract(node, context) {
22
22
  if (!this.isTypeDeclaration(node))
23
23
  return null;
24
- const nameNode = node.childForFieldName('name');
25
- if (!nameNode)
24
+ const ownerFqn = config.extractOwnerName?.(node) ?? node.childForFieldName('name')?.text;
25
+ if (!ownerFqn)
26
26
  return null;
27
- const ownerFqn = nameNode.text;
28
27
  const fields = [];
29
28
  // Find body container(s)
30
29
  const bodies = this.findBodies(node);
@@ -43,6 +42,8 @@ export function createFieldExtractor(config) {
43
42
  // private helpers
44
43
  // ------------------------------------------------------------------
45
44
  findBodies(node) {
45
+ if (config.findBodyNodes)
46
+ return config.findBodyNodes(node);
46
47
  const result = [];
47
48
  // Try named 'body' field first
48
49
  const bodyField = node.childForFieldName('body');
@@ -105,7 +106,7 @@ export function createFieldExtractor(config) {
105
106
  return {
106
107
  name,
107
108
  type,
108
- visibility: config.extractVisibility(node),
109
+ visibility: config.extractVisibilityForName?.(node, name) ?? config.extractVisibility(node),
109
110
  isStatic: config.isStatic(node),
110
111
  isReadonly: config.isReadonly(node),
111
112
  sourceFile: context.filePath,
@@ -52,11 +52,15 @@ const GO_SCOPE_QUERY = `
52
52
  ;; Declarations — variables
53
53
  (var_declaration
54
54
  (var_spec
55
- name: (identifier) @declaration.name)) @declaration.variable
55
+ (identifier) @declaration.name)) @declaration.variable
56
+ (var_declaration
57
+ (var_spec_list
58
+ (var_spec
59
+ (identifier) @declaration.name))) @declaration.variable
56
60
 
57
61
  (const_declaration
58
62
  (const_spec
59
- name: (identifier) @declaration.name)) @declaration.const
63
+ (identifier) @declaration.name)) @declaration.const
60
64
 
61
65
  (short_var_declaration
62
66
  left: (expression_list (identifier) @declaration.name)) @declaration.variable
@@ -41,6 +41,10 @@ export interface WorkerExtractedData {
41
41
  * silently no-op'd by `KnowledgeGraph`).
42
42
  */
43
43
  export declare const mergeChunkResults: (graph: KnowledgeGraph, symbolTable: SymbolTableWriter, chunkResults: readonly ParseWorkerResult[]) => WorkerExtractedData;
44
+ export declare const processParsingSequential: (graph: KnowledgeGraph, files: {
45
+ path: string;
46
+ content: string;
47
+ }[], symbolTable: SymbolTableWriter, astCache: ASTCache, scopeTreeCache: ASTCache | undefined, onFileProgress?: FileProgressCallback) => Promise<void>;
44
48
  export declare const processParsing: (graph: KnowledgeGraph, files: {
45
49
  path: string;
46
50
  content: string;
@@ -263,7 +263,7 @@ function seqGetFieldInfo(classNode, provider, context) {
263
263
  seqFieldInfoCache.set(cacheKey, cached);
264
264
  return cached;
265
265
  }
266
- const processParsingSequential = async (graph, files, symbolTable, astCache, scopeTreeCache, onFileProgress) => {
266
+ export const processParsingSequential = async (graph, files, symbolTable, astCache, scopeTreeCache, onFileProgress) => {
267
267
  const parser = await loadParser();
268
268
  const total = files.length;
269
269
  const logSkipped = isVerboseIngestionEnabled();
@@ -276,6 +276,7 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, sco
276
276
  seqFieldInfoCache.clear();
277
277
  seqMethodExtractCache.clear();
278
278
  seqMethodMapCache.clear();
279
+ const seqVariableInfoCache = new Map();
279
280
  onFileProgress?.(i + 1, total, file.path);
280
281
  if (i % 20 === 0)
281
282
  await yieldToEventLoop();
@@ -699,6 +700,31 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, sco
699
700
  }
700
701
  // All 15 tree-sitter languages register a FieldExtractor — no fallback needed.
701
702
  }
703
+ if ((nodeLabel === 'Const' || nodeLabel === 'Static' || nodeLabel === 'Variable') &&
704
+ definitionNode &&
705
+ provider.variableExtractor) {
706
+ let variableInfoByName = seqVariableInfoCache.get(definitionNode.startIndex);
707
+ if (!variableInfoByName) {
708
+ const varCtx = {
709
+ filePath: file.path,
710
+ language,
711
+ };
712
+ variableInfoByName = new Map(provider.variableExtractor
713
+ .extractAll(definitionNode, varCtx)
714
+ .map((info) => [info.name, info]));
715
+ seqVariableInfoCache.set(definitionNode.startIndex, variableInfoByName);
716
+ }
717
+ const varInfo = variableInfoByName.get(nodeName);
718
+ if (varInfo) {
719
+ if (varInfo.type)
720
+ declaredType = varInfo.type;
721
+ seqVisibility = varInfo.visibility;
722
+ seqIsStatic = varInfo.isStatic;
723
+ methodProps.isConst = varInfo.isConst;
724
+ methodProps.isMutable = varInfo.isMutable;
725
+ methodProps.scope = varInfo.scope;
726
+ }
727
+ }
702
728
  // Apply field metadata to the graph node retroactively
703
729
  if (seqVisibility !== undefined)
704
730
  node.properties.visibility = seqVisibility;
@@ -708,6 +734,12 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, sco
708
734
  node.properties.isReadonly = seqIsReadonly;
709
735
  if (declaredType !== undefined)
710
736
  node.properties.declaredType = declaredType;
737
+ if (methodProps.isConst !== undefined)
738
+ node.properties.isConst = methodProps.isConst;
739
+ if (methodProps.isMutable !== undefined)
740
+ node.properties.isMutable = methodProps.isMutable;
741
+ if (methodProps.scope !== undefined)
742
+ node.properties.scope = methodProps.scope;
711
743
  symbolTable.add(file.path, nodeName, nodeId, nodeLabel, {
712
744
  parameterCount: methodProps.parameterCount,
713
745
  requiredParameterCount: methodProps.requiredParameterCount,
@@ -3,7 +3,7 @@ export declare const JAVASCRIPT_QUERIES: string;
3
3
  export declare const PYTHON_QUERIES = "\n(class_definition\n name: (identifier) @name) @definition.class\n\n(function_definition\n name: (identifier) @name) @definition.function\n\n(import_statement\n name: (dotted_name) @import.source) @import\n\n; import numpy as np \u2192 aliased_import captures the module name so the\n; import path is resolved and named-binding extraction stores \"np\" \u2192 \"numpy\".\n(import_statement\n name: (aliased_import\n name: (dotted_name) @import.source)) @import\n\n(import_from_statement\n module_name: (dotted_name) @import.source) @import\n\n(import_from_statement\n module_name: (relative_import) @import.source) @import\n\n(call\n function: (identifier) @call.name) @call\n\n(call\n function: (attribute\n attribute: (identifier) @call.name)) @call\n\n; Class attribute type annotations \u2014 PEP 526: address: Address or address: Address = Address()\n; Both bare annotations (address: Address) and annotated assignments (name: str = \"test\")\n; are parsed as (assignment left: ... type: ...) in tree-sitter-python.\n(expression_statement\n (assignment\n left: (identifier) @name\n type: (type)) @definition.property)\n\n; Plain variable assignments without type annotation: x = 5, MAX_SIZE = 100\n; Overlap with @definition.property (typed) is handled by parse-worker dedup.\n(expression_statement\n (assignment\n left: (identifier) @name)) @definition.variable\n\n; Write access: obj.field = value\n(assignment\n left: (attribute\n object: (_) @assignment.receiver\n attribute: (identifier) @assignment.property)\n right: (_)) @assignment\n\n; Write access: obj.field += value (compound assignment)\n(augmented_assignment\n left: (attribute\n object: (_) @assignment.receiver\n attribute: (identifier) @assignment.property)\n right: (_)) @assignment\n\n; Python HTTP clients: requests.get('/path'), httpx.post('/path'), session.get('/path')\n(call\n function: (attribute\n attribute: (identifier) @http_client.method)\n arguments: (argument_list\n (string (string_content) @http_client.url))) @http_client\n\n; Python decorators: @app.route, @router.get, etc.\n(decorator\n (call\n function: (attribute\n object: (identifier) @decorator.receiver\n attribute: (identifier) @decorator.name)\n arguments: (argument_list\n (string (string_content) @decorator.arg)?))) @decorator\n";
4
4
  export declare const JAVA_QUERIES = "\n; Classes, Interfaces, Enums, Annotations\n(class_declaration name: (identifier) @name) @definition.class\n(interface_declaration name: (identifier) @name) @definition.interface\n(enum_declaration name: (identifier) @name) @definition.enum\n(annotation_type_declaration name: (identifier) @name) @definition.annotation\n\n; Methods & Constructors\n(method_declaration name: (identifier) @name) @definition.method\n(constructor_declaration name: (identifier) @name) @definition.constructor\n\n; Fields \u2014 typed field declarations inside class bodies\n(field_declaration\n declarator: (variable_declarator\n name: (identifier) @name)) @definition.property\n\n; Imports - capture any import declaration child as source\n(import_declaration (_) @import.source) @import\n\n; Calls\n(method_invocation name: (identifier) @call.name) @call\n(method_invocation object: (_) name: (identifier) @call.name) @call\n(method_reference) @call\n\n; Constructor calls: new Foo()\n(object_creation_expression type: (type_identifier) @call.name) @call\n\n; Local variable declarations inside method bodies\n(local_variable_declaration\n declarator: (variable_declarator\n name: (identifier) @name)) @definition.variable\n\n; Write access: obj.field = value\n(assignment_expression\n left: (field_access\n object: (_) @assignment.receiver\n field: (identifier) @assignment.property)\n right: (_)) @assignment\n";
5
5
  export declare const C_QUERIES = "\n; Functions (direct declarator)\n(function_definition declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n(declaration declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n\n; Functions returning pointers (pointer_declarator wraps function_declarator)\n(function_definition declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name))) @definition.function\n(declaration declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name))) @definition.function\n\n; Functions returning double pointers (nested pointer_declarator)\n(function_definition declarator: (pointer_declarator declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name)))) @definition.function\n\n; Structs, Unions, Enums, Typedefs\n(struct_specifier name: (type_identifier) @name) @definition.struct\n(type_definition\n type: (struct_specifier\n body: (field_declaration_list))\n declarator: (type_identifier) @name) @definition.struct\n(union_specifier name: (type_identifier) @name) @definition.union\n(enum_specifier name: (type_identifier) @name) @definition.enum\n(type_definition\n type: (enum_specifier\n body: (enumerator_list))\n declarator: (type_identifier) @name) @definition.enum\n(enumerator name: (identifier) @name) @definition.const\n(type_definition declarator: (type_identifier) @name) @definition.typedef\n\n; Macros\n(preproc_function_def name: (identifier) @name) @definition.macro\n(preproc_def name: (identifier) @name) @definition.macro\n\n; Includes\n(preproc_include path: (_) @import.source) @import\n\n; Calls\n(call_expression function: (identifier) @call.name) @call\n(call_expression function: (field_expression field: (field_identifier) @call.name)) @call\n\n; Variable declarations: int x = 5; or int x;\n(declaration\n declarator: (init_declarator\n declarator: (identifier) @name)) @definition.variable\n";
6
- export declare const GO_QUERIES = "\n; Functions & Methods\n(function_declaration name: (identifier) @name) @definition.function\n(method_declaration name: (field_identifier) @name) @definition.method\n(method_elem name: (field_identifier) @name) @definition.method\n\n; Types\n(type_declaration (type_spec name: (type_identifier) @name type: (struct_type))) @definition.struct\n(type_declaration (type_spec name: (type_identifier) @name type: (interface_type))) @definition.interface\n\n; Imports\n(import_declaration (import_spec path: (interpreted_string_literal) @import.source)) @import\n(import_declaration (import_spec_list (import_spec path: (interpreted_string_literal) @import.source))) @import\n\n; Struct fields \u2014 named field declarations inside struct types\n(field_declaration_list\n (field_declaration\n name: (field_identifier) @name) @definition.property)\n\n; Calls\n(call_expression function: (identifier) @call.name) @call\n(call_expression function: (selector_expression field: (field_identifier) @call.name)) @call\n\n; Const/var declarations\n(const_declaration (const_spec name: (identifier) @name)) @definition.const\n(var_declaration (var_spec name: (identifier) @name)) @definition.variable\n\n; Short variable declaration: x := 5\n(short_var_declaration left: (expression_list (identifier) @name)) @definition.variable\n\n; Struct literal construction: User{Name: \"Alice\"}\n(composite_literal type: (type_identifier) @call.name) @call\n\n; Write access: obj.field = value\n(assignment_statement\n left: (expression_list\n (selector_expression\n operand: (_) @assignment.receiver\n field: (field_identifier) @assignment.property))\n right: (_)) @assignment\n\n; Write access: obj.field++ / obj.field--\n(inc_statement\n (selector_expression\n operand: (_) @assignment.receiver\n field: (field_identifier) @assignment.property)) @assignment\n(dec_statement\n (selector_expression\n operand: (_) @assignment.receiver\n field: (field_identifier) @assignment.property)) @assignment\n";
6
+ export declare const GO_QUERIES = "\n; Functions & Methods\n(function_declaration name: (identifier) @name) @definition.function\n(method_declaration name: (field_identifier) @name) @definition.method\n(method_elem name: (field_identifier) @name) @definition.method\n\n; Types\n(type_declaration (type_spec name: (type_identifier) @name type: (struct_type))) @definition.struct\n(type_declaration (type_spec name: (type_identifier) @name type: (interface_type))) @definition.interface\n\n; Imports\n(import_declaration (import_spec path: (interpreted_string_literal) @import.source)) @import\n(import_declaration (import_spec_list (import_spec path: (interpreted_string_literal) @import.source))) @import\n\n; Struct fields \u2014 named field declarations inside struct types\n(field_declaration_list\n (field_declaration\n name: (field_identifier) @name) @definition.property)\n\n; Calls\n(call_expression function: (identifier) @call.name) @call\n(call_expression function: (selector_expression field: (field_identifier) @call.name)) @call\n\n; Const/var declarations\n(const_declaration (const_spec (identifier) @name)) @definition.const\n(var_declaration (var_spec (identifier) @name)) @definition.variable\n(var_declaration (var_spec_list (var_spec (identifier) @name))) @definition.variable\n\n; Short variable declaration: x := 5\n(short_var_declaration left: (expression_list (identifier) @name)) @definition.variable\n\n; Struct literal construction: User{Name: \"Alice\"}\n(composite_literal type: (type_identifier) @call.name) @call\n\n; Write access: obj.field = value\n(assignment_statement\n left: (expression_list\n (selector_expression\n operand: (_) @assignment.receiver\n field: (field_identifier) @assignment.property))\n right: (_)) @assignment\n\n; Write access: obj.field++ / obj.field--\n(inc_statement\n (selector_expression\n operand: (_) @assignment.receiver\n field: (field_identifier) @assignment.property)) @assignment\n(dec_statement\n (selector_expression\n operand: (_) @assignment.receiver\n field: (field_identifier) @assignment.property)) @assignment\n";
7
7
  export declare const CPP_QUERIES = "\n; Classes, Structs, Namespaces\n(class_specifier name: (type_identifier) @name) @definition.class\n(class_specifier\n name: (template_type\n (type_identifier) @name\n (template_argument_list) @template-arguments)) @definition.class\n; Out-of-line nested definition: class Outer::Inner { ... } / struct Outer::Inner { ... }.\n; Key the node by the full qualified_identifier text so the def materializes a\n; node that matches the HAS_METHOD owner id (also the full qualified text) and\n; stays distinct from a same-tail type in another scope (#1975, #1978).\n(class_specifier name: (qualified_identifier) @name) @definition.class\n(struct_specifier name: (qualified_identifier) @name) @definition.struct\n(struct_specifier name: (type_identifier) @name) @definition.struct\n(struct_specifier\n name: (template_type\n (type_identifier) @name\n (template_argument_list) @template-arguments)) @definition.struct\n(namespace_definition name: (namespace_identifier) @name) @definition.namespace\n(enum_specifier name: (type_identifier) @name) @definition.enum\n\n; Typedefs and unions (common in C-style headers and mixed C/C++ code)\n(type_definition\n type: (struct_specifier\n body: (field_declaration_list))\n declarator: (type_identifier) @name) @definition.struct\n(type_definition\n type: (enum_specifier\n body: (enumerator_list))\n declarator: (type_identifier) @name) @definition.enum\n(enumerator name: (identifier) @name) @definition.const\n(type_definition declarator: (type_identifier) @name) @definition.typedef\n(union_specifier name: (type_identifier) @name) @definition.union\n\n; Macros\n(preproc_function_def name: (identifier) @name) @definition.macro\n(preproc_def name: (identifier) @name) @definition.macro\n\n; Functions & Methods (direct declarator)\n(function_definition declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n(function_definition declarator: (function_declarator declarator: (operator_name) @name)) @definition.function\n(function_definition declarator: (function_declarator declarator: (qualified_identifier name: (identifier) @name))) @definition.method\n(function_definition declarator: (function_declarator declarator: (qualified_identifier name: (operator_name) @name))) @definition.method\n\n; Functions/methods returning pointers (pointer_declarator wraps function_declarator)\n(function_definition declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name))) @definition.function\n(function_definition declarator: (pointer_declarator declarator: (function_declarator declarator: (qualified_identifier name: (identifier) @name)))) @definition.method\n\n; Functions/methods returning double pointers (nested pointer_declarator)\n(function_definition declarator: (pointer_declarator declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name)))) @definition.function\n(function_definition declarator: (pointer_declarator declarator: (pointer_declarator declarator: (function_declarator declarator: (qualified_identifier name: (identifier) @name))))) @definition.method\n\n; Functions/methods returning references (reference_declarator wraps function_declarator)\n(function_definition declarator: (reference_declarator (function_declarator declarator: (identifier) @name))) @definition.function\n(function_definition declarator: (reference_declarator (function_declarator declarator: (operator_name) @name))) @definition.function\n(function_definition declarator: (reference_declarator (function_declarator declarator: (qualified_identifier name: (identifier) @name)))) @definition.method\n(function_definition declarator: (reference_declarator (function_declarator declarator: (qualified_identifier name: (operator_name) @name)))) @definition.method\n\n; Destructors (destructor_name is distinct from identifier in tree-sitter-cpp)\n(function_definition declarator: (function_declarator declarator: (qualified_identifier name: (destructor_name) @name))) @definition.method\n\n; Function declarations / prototypes (common in headers)\n(declaration declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n(declaration declarator: (function_declarator declarator: (operator_name) @name)) @definition.function\n(declaration declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name))) @definition.function\n(declaration declarator: (reference_declarator (function_declarator declarator: (operator_name) @name))) @definition.function\n\n; Class/struct data member fields (Address address; int count;)\n; Uses field_identifier to exclude method declarations (which use function_declarator)\n(field_declaration\n declarator: (field_identifier) @name) @definition.property\n\n; Pointer member fields (Address* address;)\n(field_declaration\n declarator: (pointer_declarator\n declarator: (field_identifier) @name)) @definition.property\n\n; Reference member fields (Address& address;)\n(field_declaration\n declarator: (reference_declarator\n (field_identifier) @name)) @definition.property\n\n; Inline class method declarations (inside class body, no body: void save();)\n; tree-sitter-cpp uses field_identifier (not identifier) for names inside class bodies\n(field_declaration declarator: (function_declarator declarator: [(field_identifier) (identifier) (operator_name)] @name)) @definition.method\n\n; Inline class method declarations returning a pointer (User* lookup();)\n(field_declaration declarator: (pointer_declarator declarator: (function_declarator declarator: [(field_identifier) (identifier)] @name))) @definition.method\n\n; Inline class method declarations returning a reference (User& lookup();)\n(field_declaration declarator: (reference_declarator (function_declarator declarator: [(field_identifier) (identifier) (operator_name)] @name))) @definition.method\n\n; Inline class method definitions (inside class body, with body: void Foo() { ... })\n(field_declaration_list\n (function_definition\n declarator: (function_declarator\n declarator: [(field_identifier) (identifier) (operator_name) (destructor_name)] @name)) @definition.method)\n\n; Inline class methods returning a pointer type (User* lookup(int id) { ... })\n(field_declaration_list\n (function_definition\n declarator: (pointer_declarator\n declarator: (function_declarator\n declarator: [(field_identifier) (identifier) (operator_name)] @name))) @definition.method)\n\n; Inline class methods returning a reference type (User& lookup(int id) { ... })\n(field_declaration_list\n (function_definition\n declarator: (reference_declarator\n (function_declarator\n declarator: [(field_identifier) (identifier) (operator_name)] @name))) @definition.method)\n\n; Templates\n(template_declaration (class_specifier name: (type_identifier) @name)) @definition.template\n(template_declaration\n (class_specifier\n name: (template_type\n (type_identifier) @name\n (template_argument_list) @template-arguments))) @definition.template\n(template_declaration (function_definition declarator: (function_declarator declarator: (identifier) @name))) @definition.template\n\n; Includes\n(preproc_include path: (_) @import.source) @import\n\n; Calls\n(call_expression function: (identifier) @call.name) @call\n(call_expression function: (field_expression field: (field_identifier) @call.name)) @call\n(call_expression function: (qualified_identifier name: (identifier) @call.name)) @call\n(call_expression function: (template_function name: (identifier) @call.name)) @call\n(binary_expression operator: \"+\" @call.name) @call\n(binary_expression operator: \"<<\" @call.name) @call\n\n; Constructor calls: new User()\n(new_expression type: (type_identifier) @call.name) @call\n\n; Variable declarations: int x = 5; or auto x = 5;\n(declaration\n declarator: (init_declarator\n declarator: (identifier) @name)) @definition.variable\n\n; Write access: obj.field = value\n(assignment_expression\n left: (field_expression\n argument: (_) @assignment.receiver\n field: (field_identifier) @assignment.property)\n right: (_)) @assignment\n\n";
8
8
  export declare const CSHARP_QUERIES = "\n; Types\n(class_declaration name: (identifier) @name) @definition.class\n(interface_declaration name: (identifier) @name) @definition.interface\n(struct_declaration name: (identifier) @name) @definition.struct\n(enum_declaration name: (identifier) @name) @definition.enum\n(record_declaration name: (identifier) @name) @definition.record\n(delegate_declaration name: (identifier) @name) @definition.delegate\n\n; Namespaces (block form and C# 10+ file-scoped form)\n(namespace_declaration name: (identifier) @name) @definition.namespace\n(namespace_declaration name: (qualified_name) @name) @definition.namespace\n(file_scoped_namespace_declaration name: (identifier) @name) @definition.namespace\n(file_scoped_namespace_declaration name: (qualified_name) @name) @definition.namespace\n\n; Methods & Properties\n(method_declaration name: (identifier) @name) @definition.method\n(local_function_statement name: (identifier) @name) @definition.function\n(constructor_declaration name: (identifier) @name) @definition.constructor\n(property_declaration name: (identifier) @name) @definition.property\n\n; Primary constructors (C# 12): class User(string name, int age) { }\n(class_declaration name: (identifier) @name (parameter_list) @definition.constructor)\n(record_declaration name: (identifier) @name (parameter_list) @definition.constructor)\n\n; Using\n(using_directive (qualified_name) @import.source) @import\n(using_directive (identifier) @import.source) @import\n\n; Calls\n(invocation_expression function: (identifier) @call.name) @call\n(invocation_expression function: (member_access_expression name: (identifier) @call.name)) @call\n\n; Null-conditional method calls: user?.Save()\n; Parses as: invocation_expression \u2192 conditional_access_expression \u2192 member_binding_expression \u2192 identifier\n(invocation_expression\n function: (conditional_access_expression\n (member_binding_expression\n (identifier) @call.name))) @call\n\n; Constructor calls: new Foo() and new Foo { Props }\n(object_creation_expression type: (identifier) @call.name) @call\n\n; Target-typed new (C# 9): User u = new(\"x\", 5)\n(variable_declaration type: (identifier) @call.name (variable_declarator (implicit_object_creation_expression) @call))\n\n; Local variable declarations\n(local_declaration_statement\n (variable_declaration\n (variable_declarator\n (identifier) @name))) @definition.variable\n\n; Write access: obj.field = value\n(assignment_expression\n left: (member_access_expression\n expression: (_) @assignment.receiver\n name: (identifier) @assignment.property)\n right: (_)) @assignment\n";
9
9
  export declare const RUST_QUERIES = "\n; Functions & Items\n(function_item name: (identifier) @name) @definition.function\n(function_signature_item name: (identifier) @name) @definition.function\n(struct_item name: (type_identifier) @name) @definition.struct\n; A union is materialized as a Struct node (same rationale as the\n; scope-resolution @declaration.struct in languages/rust/query.ts: every\n; registry-primary resolution gate includes Struct but excludes Union, so a\n; Union-labeled node would be an unresolvable orphan). #1934 F71.\n(union_item name: (type_identifier) @name) @definition.struct\n(enum_item name: (type_identifier) @name) @definition.enum\n(trait_item name: (type_identifier) @name) @definition.trait\n(impl_item type: (type_identifier) @name !trait) @definition.impl\n(impl_item type: (generic_type type: (type_identifier) @name) !trait) @definition.impl\n; Scoped inherent impl: impl path::Type { ... }. Key the Impl node by the full\n; scoped_type_identifier text so it matches the owner id (also full text) and\n; stays distinct from a same-tail type in another module (#1975).\n(impl_item type: (scoped_type_identifier) @name !trait) @definition.impl\n(mod_item name: (identifier) @name) @definition.module\n\n; Type aliases, const, static, macros\n(type_item name: (type_identifier) @name) @definition.type\n(const_item name: (identifier) @name) @definition.const\n(static_item name: (identifier) @name) @definition.static\n(macro_definition name: (identifier) @name) @definition.macro\n\n; Use statements\n(use_declaration argument: (_) @import.source) @import\n\n; Calls\n(call_expression function: (identifier) @call.name) @call\n(call_expression function: (field_expression field: (field_identifier) @call.name)) @call\n(call_expression function: (scoped_identifier name: (identifier) @call.name)) @call\n(call_expression function: (generic_function function: (identifier) @call.name)) @call\n\n; Struct literal construction: User { name: value }\n(struct_expression name: (type_identifier) @call.name) @call\n\n; Struct fields \u2014 named field declarations inside struct bodies\n(field_declaration_list\n (field_declaration\n name: (field_identifier) @name) @definition.property)\n\n; Write access: obj.field = value\n(assignment_expression\n left: (field_expression\n value: (_) @assignment.receiver\n field: (field_identifier) @assignment.property)\n right: (_)) @assignment\n\n; Write access: obj.field += value (compound assignment)\n(compound_assignment_expr\n left: (field_expression\n value: (_) @assignment.receiver\n field: (field_identifier) @assignment.property)\n right: (_)) @assignment\n";
@@ -828,8 +828,9 @@ export const GO_QUERIES = `
828
828
  (call_expression function: (selector_expression field: (field_identifier) @call.name)) @call
829
829
 
830
830
  ; Const/var declarations
831
- (const_declaration (const_spec name: (identifier) @name)) @definition.const
832
- (var_declaration (var_spec name: (identifier) @name)) @definition.variable
831
+ (const_declaration (const_spec (identifier) @name)) @definition.const
832
+ (var_declaration (var_spec (identifier) @name)) @definition.variable
833
+ (var_declaration (var_spec_list (var_spec (identifier) @name))) @definition.variable
833
834
 
834
835
  ; Short variable declaration: x := 5
835
836
  (short_var_declaration left: (expression_list (identifier) @name)) @definition.variable
@@ -15,7 +15,69 @@ import { extractSimpleTypeName } from '../../type-extractors/shared.js';
15
15
  *
16
16
  * Visibility: uppercase first letter = exported (public), lowercase = unexported (package).
17
17
  */
18
+ function goVisibilityForName(name) {
19
+ const firstChar = name.charAt(0);
20
+ return firstChar === firstChar.toUpperCase() && firstChar !== firstChar.toLowerCase()
21
+ ? 'public'
22
+ : 'package';
23
+ }
24
+ function collectGoSpecNames(spec) {
25
+ const names = [];
26
+ for (let i = 0; i < spec.namedChildCount; i++) {
27
+ const child = spec.namedChild(i);
28
+ if (!child)
29
+ continue;
30
+ if (child.type === 'identifier') {
31
+ names.push(child.text);
32
+ continue;
33
+ }
34
+ break;
35
+ }
36
+ return names;
37
+ }
38
+ function collectGoSpecs(node) {
39
+ const specs = [];
40
+ for (let i = 0; i < node.namedChildCount; i++) {
41
+ const child = node.namedChild(i);
42
+ if (child?.type === 'var_spec' || child?.type === 'const_spec') {
43
+ specs.push(child);
44
+ continue;
45
+ }
46
+ if (child?.type === 'var_spec_list') {
47
+ specs.push(...collectGoSpecs(child));
48
+ }
49
+ }
50
+ return specs;
51
+ }
52
+ function collectGoDeclarationNames(node) {
53
+ if (node.type === 'short_var_declaration') {
54
+ const left = node.childForFieldName('left');
55
+ if (left?.type !== 'expression_list')
56
+ return [];
57
+ return left.namedChildren
58
+ .filter((child) => child.type === 'identifier')
59
+ .map((child) => child.text);
60
+ }
61
+ const names = [];
62
+ for (const spec of collectGoSpecs(node))
63
+ names.push(...collectGoSpecNames(spec));
64
+ return names;
65
+ }
66
+ function findGoSpecForName(node, name) {
67
+ for (const spec of collectGoSpecs(node)) {
68
+ if (collectGoSpecNames(spec).includes(name))
69
+ return spec;
70
+ }
71
+ return undefined;
72
+ }
73
+ function extractGoSpecType(spec) {
74
+ const typeNode = spec.childForFieldName('type');
75
+ return typeNode ? (extractSimpleTypeName(typeNode) ?? typeNode.text?.trim()) : undefined;
76
+ }
18
77
  function extractGoVarName(node) {
78
+ const firstName = collectGoDeclarationNames(node)[0];
79
+ if (firstName)
80
+ return firstName;
19
81
  // var_declaration/const_declaration → var_spec/const_spec → identifier
20
82
  for (let i = 0; i < node.namedChildCount; i++) {
21
83
  const child = node.namedChild(i);
@@ -43,13 +105,10 @@ function extractGoVarName(node) {
43
105
  return undefined;
44
106
  }
45
107
  function extractGoVarType(node) {
46
- for (let i = 0; i < node.namedChildCount; i++) {
47
- const child = node.namedChild(i);
48
- if (child?.type === 'var_spec' || child?.type === 'const_spec') {
49
- const typeNode = child.childForFieldName('type');
50
- if (typeNode)
51
- return extractSimpleTypeName(typeNode) ?? typeNode.text?.trim();
52
- }
108
+ for (const spec of collectGoSpecs(node)) {
109
+ const typeName = extractGoSpecType(spec);
110
+ if (typeName)
111
+ return typeName;
53
112
  }
54
113
  return undefined;
55
114
  }
@@ -60,6 +119,10 @@ export const goVariableConfig = {
60
119
  variableNodeTypes: ['var_declaration', 'short_var_declaration'],
61
120
  extractName: extractGoVarName,
62
121
  extractType: extractGoVarType,
122
+ extractTypeForName(node, name) {
123
+ const spec = findGoSpecForName(node, name);
124
+ return spec ? extractGoSpecType(spec) : undefined;
125
+ },
63
126
  extractVisibility(node) {
64
127
  const name = extractGoVarName(node);
65
128
  if (!name)
@@ -70,6 +133,10 @@ export const goVariableConfig = {
70
133
  ? 'public'
71
134
  : 'package';
72
135
  },
136
+ extractNames: collectGoDeclarationNames,
137
+ extractVisibilityForName(_node, name) {
138
+ return goVisibilityForName(name);
139
+ },
73
140
  isConst(node) {
74
141
  return node.type === 'const_declaration';
75
142
  },
@@ -50,13 +50,16 @@ export function createVariableExtractor(config) {
50
50
  return allNodeTypes.has(node.type);
51
51
  },
52
52
  extract(node, context) {
53
+ return this.extractAll(node, context)[0] ?? null;
54
+ },
55
+ extractAll(node, context) {
53
56
  if (!allNodeTypes.has(node.type))
54
- return null;
55
- const name = config.extractName(node);
56
- if (!name)
57
- return null;
58
- const type = config.extractType(node) ?? null;
59
- const visibility = config.extractVisibility(node);
57
+ return [];
58
+ const names = config.extractNames
59
+ ? config.extractNames(node)
60
+ : [config.extractName(node)].filter((name) => Boolean(name));
61
+ if (names.length === 0)
62
+ return [];
60
63
  // isConst/isStatic: node type membership is a hint, but config.isConst/isStatic
61
64
  // has final say. For languages where const and non-const share a node type
62
65
  // (e.g., TS lexical_declaration for both const and let), config.isConst disambiguates.
@@ -64,17 +67,17 @@ export function createVariableExtractor(config) {
64
67
  const isStatic = staticNodeSet.has(node.type) || config.isStatic(node);
65
68
  const isMutable = config.isMutable(node);
66
69
  const scope = determineScope(node);
67
- return {
70
+ return names.map((name) => ({
68
71
  name,
69
- type,
70
- visibility,
72
+ type: config.extractTypeForName?.(node, name) ?? config.extractType(node) ?? null,
73
+ visibility: config.extractVisibilityForName?.(node, name) ?? config.extractVisibility(node),
71
74
  isConst,
72
75
  isStatic,
73
76
  isMutable,
74
77
  scope,
75
78
  sourceFile: context.filePath,
76
79
  line: node.startPosition.row + 1,
77
- };
80
+ }));
78
81
  },
79
82
  };
80
83
  }
@@ -51,6 +51,9 @@ export interface VariableExtractor {
51
51
  /** Extract variable metadata from a declaration node.
52
52
  * Returns null if the node is not a recognized variable declaration. */
53
53
  extract(node: SyntaxNode, context: VariableExtractorContext): VariableInfo | null;
54
+ /** Extract every variable metadata entry from a declaration node.
55
+ * Returns [] if the node is not a recognized variable declaration. */
56
+ extractAll(node: SyntaxNode, context: VariableExtractorContext): VariableInfo[];
54
57
  /** Check if a node is a recognized variable declaration type. */
55
58
  isVariableDeclaration(node: SyntaxNode): boolean;
56
59
  }
@@ -69,10 +72,16 @@ export interface VariableExtractionConfig {
69
72
  variableNodeTypes: string[];
70
73
  /** Extract the variable name from a declaration node */
71
74
  extractName: (node: SyntaxNode) => string | undefined;
75
+ /** Extract multiple variable names from a declaration node. */
76
+ extractNames?: (node: SyntaxNode) => string[];
72
77
  /** Extract type annotation from a declaration node */
73
78
  extractType: (node: SyntaxNode) => string | undefined;
79
+ /** Extract type annotation for one variable name from a multi-name declaration. */
80
+ extractTypeForName?: (node: SyntaxNode, name: string) => string | undefined;
74
81
  /** Extract visibility from a declaration node */
75
82
  extractVisibility: (node: SyntaxNode) => VariableVisibility;
83
+ /** Extract visibility for one variable name from a multi-name declaration. */
84
+ extractVisibilityForName?: (node: SyntaxNode, name: string) => VariableVisibility;
76
85
  /** Check if a declaration is const/immutable */
77
86
  isConst: (node: SyntaxNode) => boolean;
78
87
  /** Check if a declaration is static */
@@ -830,6 +830,7 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
830
830
  // (e.g. @definition.function) to avoid duplicate nodes when @definition.const/@definition.variable
831
831
  // patterns overlap with the same source range.
832
832
  const processedDefinitionNodes = new Set();
833
+ const variableInfoCache = new Map();
833
834
  for (const match of matches) {
834
835
  const captureMap = {};
835
836
  for (const c of match.captures) {
@@ -1223,17 +1224,6 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
1223
1224
  }) === true) {
1224
1225
  continue;
1225
1226
  }
1226
- // Dedup: variable captures (Const/Static/Variable) may overlap with higher-priority
1227
- // captures (e.g. `const fn = () => {}` matches both @definition.function and @definition.const).
1228
- // Skip variable captures whose definition node was already processed.
1229
- if ((nodeLabel === 'Const' || nodeLabel === 'Static' || nodeLabel === 'Variable') &&
1230
- definitionNode &&
1231
- processedDefinitionNodes.has(definitionNode.startIndex)) {
1232
- continue;
1233
- }
1234
- if (definitionNode) {
1235
- processedDefinitionNodes.add(definitionNode.startIndex);
1236
- }
1237
1227
  const exportDefaultCall = nodeLabel === 'Function' && definitionNode?.type === 'export_statement'
1238
1228
  ? definitionNode.namedChildren.find((child) => child.type === 'call_expression')
1239
1229
  : undefined;
@@ -1263,6 +1253,23 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
1263
1253
  !defaultExportHocName)
1264
1254
  continue;
1265
1255
  const nodeName = extractedClassSymbol?.name ?? defaultExportHocName ?? (nameNode ? nameNode.text : 'init');
1256
+ // Dedup: variable captures (Const/Static/Variable) may overlap with higher-priority
1257
+ // captures (e.g. `const fn = () => {}` matches both @definition.function and @definition.const).
1258
+ // Multi-name declarations share the same definition node, so include the emitted name.
1259
+ if (definitionNode) {
1260
+ const definitionBaseKey = `${definitionNode.startIndex}`;
1261
+ if (nodeLabel === 'Const' || nodeLabel === 'Static' || nodeLabel === 'Variable') {
1262
+ const definitionNameKey = `${definitionBaseKey}:${nodeName}`;
1263
+ if (processedDefinitionNodes.has(definitionBaseKey) ||
1264
+ processedDefinitionNodes.has(definitionNameKey)) {
1265
+ continue;
1266
+ }
1267
+ processedDefinitionNodes.add(definitionNameKey);
1268
+ }
1269
+ else {
1270
+ processedDefinitionNodes.add(definitionBaseKey);
1271
+ }
1272
+ }
1266
1273
  const startLine = definitionNode
1267
1274
  ? definitionNode.startPosition.row + lineOffset
1268
1275
  : nameNode
@@ -1486,11 +1493,18 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
1486
1493
  if ((nodeLabel === 'Const' || nodeLabel === 'Static' || nodeLabel === 'Variable') &&
1487
1494
  definitionNode &&
1488
1495
  provider.variableExtractor) {
1489
- const varCtx = {
1490
- filePath: file.path,
1491
- language,
1492
- };
1493
- const varInfo = provider.variableExtractor.extract(definitionNode, varCtx);
1496
+ let variableInfoByName = variableInfoCache.get(definitionNode.startIndex);
1497
+ if (!variableInfoByName) {
1498
+ const varCtx = {
1499
+ filePath: file.path,
1500
+ language,
1501
+ };
1502
+ variableInfoByName = new Map(provider.variableExtractor
1503
+ .extractAll(definitionNode, varCtx)
1504
+ .map((info) => [info.name, info]));
1505
+ variableInfoCache.set(definitionNode.startIndex, variableInfoByName);
1506
+ }
1507
+ const varInfo = variableInfoByName.get(nodeName);
1494
1508
  if (varInfo) {
1495
1509
  if (varInfo.type)
1496
1510
  declaredType = varInfo.type;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.6-rc.149",
3
+ "version": "1.6.6-rc.150",
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",