grepmax 0.26.5 → 0.26.6

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.
@@ -316,7 +316,7 @@ class TreeSitterChunker {
316
316
  }
317
317
  chunkWithTreeSitter(filePath, content) {
318
318
  return __awaiter(this, void 0, void 0, function* () {
319
- var _a, _b;
319
+ var _a;
320
320
  const ext = path.extname(filePath);
321
321
  if (ext === ".json") {
322
322
  return {
@@ -339,662 +339,676 @@ class TreeSitterChunker {
339
339
  };
340
340
  this.parser.setLanguage(language);
341
341
  const tree = this.parser.parse(content);
342
- const root = tree.rootNode;
343
- const fileContext = `File: ${filePath}`;
344
- const chunks = [];
345
- const blockChunks = [];
346
- let cursorIndex = 0;
347
- let cursorRow = 0;
348
- let sawDefinition = false;
349
- const metadata = { imports: [], exports: [], comments: [] };
350
- const definitionTypes = (langDef === null || langDef === void 0 ? void 0 : langDef.definitionTypes) || [];
351
- const isDefType = (t) => definitionTypes.includes(t);
352
- const classify = (node) => {
353
- const t = node.type;
354
- // Classify strictly by the node's own type; avoid language-wide keyword inference
355
- if (t.includes("method"))
356
- return "method";
357
- if (t.includes("class"))
358
- return "class";
359
- if (t.includes("interface"))
360
- return "interface";
361
- if (t.includes("type_alias"))
362
- return "type_alias";
363
- if (isDefType(t) || isTopLevelValueDef(node))
364
- return "function";
365
- return "block";
366
- };
367
- const unwrapExport = (node) => {
368
- if (node.type === "export_statement" &&
369
- node.namedChildren &&
370
- node.namedChildren.length > 0) {
371
- return node.namedChildren[0];
372
- }
373
- return node;
374
- };
375
- const isTopLevelValueDef = (node) => {
376
- var _a;
377
- const t = node.type;
378
- if (t !== "lexical_declaration" && t !== "variable_declaration")
379
- return false;
380
- const parentType = ((_a = node.parent) === null || _a === void 0 ? void 0 : _a.type) || "";
381
- const allowedParents = [
382
- "program",
383
- "module",
384
- "source_file",
385
- "class_body",
386
- "export_statement",
387
- ];
388
- if (parentType && !allowedParents.includes(parentType))
389
- return false;
390
- // Exported declarations are part of the API surface, so always index
391
- // them regardless of RHS shape. Without this, files whose only export
392
- // is `export const typeDefs = gql\`...\`` (template literals, object
393
- // literals, or non-PascalCase consts) had no defined_symbols entry
394
- // and peek/extract returned "Symbol not found".
395
- if (parentType === "export_statement" ||
396
- parentType === "export_declaration") {
397
- return true;
398
- }
399
- const text = node.text || "";
400
- if (text.includes("=>"))
401
- return true;
402
- if (text.includes("function "))
403
- return true;
404
- if (text.includes("class "))
405
- return true;
406
- if (/(?:^|\n)\s*(?:export\s+)?const\s+[A-Z0-9_]+\s*=/.test(text))
407
- return true;
408
- return false;
409
- };
410
- const getNodeName = (node) => {
411
- var _a, _b, _c;
412
- const byField = (field) => {
413
- const child = typeof node.childForFieldName === "function"
414
- ? node.childForFieldName(field)
415
- : null;
416
- if (child === null || child === void 0 ? void 0 : child.text)
417
- return String(child.text);
418
- return null;
342
+ if (!tree) {
343
+ return {
344
+ chunks: [],
345
+ metadata: { imports: [], exports: [], comments: [] },
419
346
  };
420
- const fieldNames = ["name", "property", "identifier"];
421
- for (const field of fieldNames) {
422
- const name = byField(field);
423
- if (name)
424
- return name;
425
- }
426
- const identifierChild = ((_a = node.namedChildren) !== null && _a !== void 0 ? _a : []).find((c) => [
427
- "identifier",
428
- "property_identifier",
429
- "type_identifier",
430
- "field_identifier",
431
- "simple_identifier", // Swift, Kotlin
432
- "word", // Bash
433
- ].includes(c.type));
434
- if (identifierChild === null || identifierChild === void 0 ? void 0 : identifierChild.text)
435
- return String(identifierChild.text);
436
- for (const child of (_b = node.namedChildren) !== null && _b !== void 0 ? _b : []) {
437
- if (child.type === "variable_declarator") {
438
- const idChild = ((_c = child.namedChildren) !== null && _c !== void 0 ? _c : []).find((c) => ["identifier", "property_identifier", "type_identifier"].includes(c.type));
439
- if (idChild === null || idChild === void 0 ? void 0 : idChild.text)
440
- return String(idChild.text);
441
- }
442
- }
443
- const match = (node.text || "").match(/(?:class|function)\s+([A-Za-z0-9_$]+)/);
444
- if (match === null || match === void 0 ? void 0 : match[1])
445
- return match[1];
446
- const varMatch = (node.text || "").match(/(?:const|let|var)\s+([A-Za-z0-9_$]+)/);
447
- if (varMatch === null || varMatch === void 0 ? void 0 : varMatch[1])
448
- return varMatch[1];
347
+ }
348
+ try {
349
+ return this.buildChunksFromTree(filePath, content, (langDef === null || langDef === void 0 ? void 0 : langDef.definitionTypes) || [], lang, tree.rootNode);
350
+ }
351
+ finally {
352
+ // Nothing in the guarded block may retain a Node.
353
+ tree.delete();
354
+ }
355
+ });
356
+ }
357
+ buildChunksFromTree(filePath, content, definitionTypes, lang, root) {
358
+ var _a;
359
+ const fileContext = `File: ${filePath}`;
360
+ const chunks = [];
361
+ const blockChunks = [];
362
+ let cursorIndex = 0;
363
+ let cursorRow = 0;
364
+ let sawDefinition = false;
365
+ const metadata = { imports: [], exports: [], comments: [] };
366
+ const isDefType = (t) => definitionTypes.includes(t);
367
+ const classify = (node) => {
368
+ const t = node.type;
369
+ // Classify strictly by the node's own type; avoid language-wide keyword inference
370
+ if (t.includes("method"))
371
+ return "method";
372
+ if (t.includes("class"))
373
+ return "class";
374
+ if (t.includes("interface"))
375
+ return "interface";
376
+ if (t.includes("type_alias"))
377
+ return "type_alias";
378
+ if (isDefType(t) || isTopLevelValueDef(node))
379
+ return "function";
380
+ return "block";
381
+ };
382
+ const unwrapExport = (node) => {
383
+ if (node.type === "export_statement" &&
384
+ node.namedChildren &&
385
+ node.namedChildren.length > 0) {
386
+ return node.namedChildren[0];
387
+ }
388
+ return node;
389
+ };
390
+ const isTopLevelValueDef = (node) => {
391
+ var _a;
392
+ const t = node.type;
393
+ if (t !== "lexical_declaration" && t !== "variable_declaration")
394
+ return false;
395
+ const parentType = ((_a = node.parent) === null || _a === void 0 ? void 0 : _a.type) || "";
396
+ const allowedParents = [
397
+ "program",
398
+ "module",
399
+ "source_file",
400
+ "class_body",
401
+ "export_statement",
402
+ ];
403
+ if (parentType && !allowedParents.includes(parentType))
404
+ return false;
405
+ // Exported declarations are part of the API surface, so always index
406
+ // them regardless of RHS shape. Without this, files whose only export
407
+ // is `export const typeDefs = gql\`...\`` (template literals, object
408
+ // literals, or non-PascalCase consts) had no defined_symbols entry
409
+ // and peek/extract returned "Symbol not found".
410
+ if (parentType === "export_statement" ||
411
+ parentType === "export_declaration") {
412
+ return true;
413
+ }
414
+ const text = node.text || "";
415
+ if (text.includes("=>"))
416
+ return true;
417
+ if (text.includes("function "))
418
+ return true;
419
+ if (text.includes("class "))
420
+ return true;
421
+ if (/(?:^|\n)\s*(?:export\s+)?const\s+[A-Z0-9_]+\s*=/.test(text))
422
+ return true;
423
+ return false;
424
+ };
425
+ const getNodeName = (node) => {
426
+ var _a, _b, _c;
427
+ const byField = (field) => {
428
+ const child = typeof node.childForFieldName === "function"
429
+ ? node.childForFieldName(field)
430
+ : null;
431
+ if (child === null || child === void 0 ? void 0 : child.text)
432
+ return String(child.text);
449
433
  return null;
450
434
  };
451
- const labelForNode = (node) => {
452
- const name = getNodeName(node);
453
- const t = node.type;
454
- if (t.includes("class"))
455
- return `Class: ${name !== null && name !== void 0 ? name : "<anonymous class>"}`;
456
- if (t.includes("method"))
457
- return `Method: ${name !== null && name !== void 0 ? name : "<anonymous method>"}`;
458
- if (t.includes("interface"))
459
- return `Interface: ${name !== null && name !== void 0 ? name : "<anonymous interface>"}`;
460
- if (t.includes("type_alias"))
461
- return `Type: ${name !== null && name !== void 0 ? name : "<anonymous type>"}`;
462
- if (t.includes("function"))
463
- return `Function: ${name !== null && name !== void 0 ? name : "<anonymous function>"}`;
464
- if (isTopLevelValueDef(node))
465
- return `Function: ${name !== null && name !== void 0 ? name : "<anonymous function>"}`;
466
- return name ? `Symbol: ${name}` : null;
467
- };
468
- const getDocstring = (node) => {
469
- const comments = [];
470
- let current = node.previousSibling;
471
- while (current) {
472
- const t = current.type;
473
- if (t.includes("comment")) {
474
- comments.unshift(current.text);
475
- current = current.previousSibling;
476
- }
477
- else if (current.text.trim().length === 0) {
478
- // whitespace
479
- current = current.previousSibling;
480
- }
481
- else {
482
- break;
483
- }
435
+ const fieldNames = ["name", "property", "identifier"];
436
+ for (const field of fieldNames) {
437
+ const name = byField(field);
438
+ if (name)
439
+ return name;
440
+ }
441
+ const identifierChild = ((_a = node.namedChildren) !== null && _a !== void 0 ? _a : []).find((c) => [
442
+ "identifier",
443
+ "property_identifier",
444
+ "type_identifier",
445
+ "field_identifier",
446
+ "simple_identifier", // Swift, Kotlin
447
+ "word", // Bash
448
+ ].includes(c.type));
449
+ if (identifierChild === null || identifierChild === void 0 ? void 0 : identifierChild.text)
450
+ return String(identifierChild.text);
451
+ for (const child of (_b = node.namedChildren) !== null && _b !== void 0 ? _b : []) {
452
+ if (child.type === "variable_declarator") {
453
+ const idChild = ((_c = child.namedChildren) !== null && _c !== void 0 ? _c : []).find((c) => ["identifier", "property_identifier", "type_identifier"].includes(c.type));
454
+ if (idChild === null || idChild === void 0 ? void 0 : idChild.text)
455
+ return String(idChild.text);
484
456
  }
485
- return comments.length > 0 ? comments.join("\n") : undefined;
486
- };
487
- const visit = (node, stack) => {
488
- var _a;
489
- // Metadata extraction
490
- if (node.type === "import_statement" ||
491
- node.type === "import_declaration" ||
492
- node.type === "import_header" // Kotlin
493
- ) {
494
- metadata.imports.push(node.text.trim());
457
+ }
458
+ const match = (node.text || "").match(/(?:class|function)\s+([A-Za-z0-9_$]+)/);
459
+ if (match === null || match === void 0 ? void 0 : match[1])
460
+ return match[1];
461
+ const varMatch = (node.text || "").match(/(?:const|let|var)\s+([A-Za-z0-9_$]+)/);
462
+ if (varMatch === null || varMatch === void 0 ? void 0 : varMatch[1])
463
+ return varMatch[1];
464
+ return null;
465
+ };
466
+ const labelForNode = (node) => {
467
+ const name = getNodeName(node);
468
+ const t = node.type;
469
+ if (t.includes("class"))
470
+ return `Class: ${name !== null && name !== void 0 ? name : "<anonymous class>"}`;
471
+ if (t.includes("method"))
472
+ return `Method: ${name !== null && name !== void 0 ? name : "<anonymous method>"}`;
473
+ if (t.includes("interface"))
474
+ return `Interface: ${name !== null && name !== void 0 ? name : "<anonymous interface>"}`;
475
+ if (t.includes("type_alias"))
476
+ return `Type: ${name !== null && name !== void 0 ? name : "<anonymous type>"}`;
477
+ if (t.includes("function"))
478
+ return `Function: ${name !== null && name !== void 0 ? name : "<anonymous function>"}`;
479
+ if (isTopLevelValueDef(node))
480
+ return `Function: ${name !== null && name !== void 0 ? name : "<anonymous function>"}`;
481
+ return name ? `Symbol: ${name}` : null;
482
+ };
483
+ const getDocstring = (node) => {
484
+ const comments = [];
485
+ let current = node.previousSibling;
486
+ while (current) {
487
+ const t = current.type;
488
+ if (t.includes("comment")) {
489
+ comments.unshift(current.text);
490
+ current = current.previousSibling;
495
491
  }
496
- else if (node.type === "export_statement" ||
497
- node.type === "export_declaration") {
498
- // Extract exported identifier
499
- const effective = unwrapExport(node);
500
- const name = getNodeName(effective);
501
- if (name) {
502
- metadata.exports.push(name);
503
- }
492
+ else if (current.text.trim().length === 0) {
493
+ // whitespace
494
+ current = current.previousSibling;
504
495
  }
505
- else if (node.type.includes("comment")) {
506
- if (node.startPosition.row < 10) {
507
- // Only top comments
508
- metadata.comments.push(node.text.trim());
509
- }
496
+ else {
497
+ break;
510
498
  }
499
+ }
500
+ return comments.length > 0 ? comments.join("\n") : undefined;
501
+ };
502
+ const visit = (node, stack) => {
503
+ var _a;
504
+ // Metadata extraction
505
+ if (node.type === "import_statement" ||
506
+ node.type === "import_declaration" ||
507
+ node.type === "import_header" // Kotlin
508
+ ) {
509
+ metadata.imports.push(node.text.trim());
510
+ }
511
+ else if (node.type === "export_statement" ||
512
+ node.type === "export_declaration") {
513
+ // Extract exported identifier
511
514
  const effective = unwrapExport(node);
512
- const isDefinition = isDefType(effective.type) || isTopLevelValueDef(effective);
513
- let nextStack = stack;
514
- if (isDefinition) {
515
- sawDefinition = true;
516
- const label = labelForNode(effective);
517
- const context = [...stack, ...(label ? [label] : [])];
518
- const docstring = getDocstring(node);
519
- // Calculate complexity
520
- const getComplexity = (n) => {
521
- let complexity = 1;
522
- const complexTypes = [
523
- "if_statement",
524
- "for_statement",
525
- "while_statement",
526
- "switch_statement",
527
- "catch_clause",
528
- "conditional_expression",
529
- "binary_expression", // simplistic, but counts logical ops usually
530
- ];
531
- const countComplexity = (curr) => {
532
- var _a;
533
- if (complexTypes.includes(curr.type)) {
534
- if (curr.type === "binary_expression") {
535
- const op = curr.childForFieldName
536
- ? curr.childForFieldName("operator")
537
- : null;
538
- if (["&&", "||", "??"].includes((op === null || op === void 0 ? void 0 : op.text) || "")) {
539
- complexity++;
540
- }
541
- }
542
- else {
515
+ const name = getNodeName(effective);
516
+ if (name) {
517
+ metadata.exports.push(name);
518
+ }
519
+ }
520
+ else if (node.type.includes("comment")) {
521
+ if (node.startPosition.row < 10) {
522
+ // Only top comments
523
+ metadata.comments.push(node.text.trim());
524
+ }
525
+ }
526
+ const effective = unwrapExport(node);
527
+ const isDefinition = isDefType(effective.type) || isTopLevelValueDef(effective);
528
+ let nextStack = stack;
529
+ if (isDefinition) {
530
+ sawDefinition = true;
531
+ const label = labelForNode(effective);
532
+ const context = [...stack, ...(label ? [label] : [])];
533
+ const docstring = getDocstring(node);
534
+ // Calculate complexity
535
+ const getComplexity = (n) => {
536
+ let complexity = 1;
537
+ const complexTypes = [
538
+ "if_statement",
539
+ "for_statement",
540
+ "while_statement",
541
+ "switch_statement",
542
+ "catch_clause",
543
+ "conditional_expression",
544
+ "binary_expression", // simplistic, but counts logical ops usually
545
+ ];
546
+ const countComplexity = (curr) => {
547
+ var _a;
548
+ if (complexTypes.includes(curr.type)) {
549
+ if (curr.type === "binary_expression") {
550
+ const op = curr.childForFieldName
551
+ ? curr.childForFieldName("operator")
552
+ : null;
553
+ if (["&&", "||", "??"].includes((op === null || op === void 0 ? void 0 : op.text) || "")) {
543
554
  complexity++;
544
555
  }
545
556
  }
546
- for (const child of (_a = curr.namedChildren) !== null && _a !== void 0 ? _a : []) {
547
- countComplexity(child);
557
+ else {
558
+ complexity++;
548
559
  }
549
- };
550
- countComplexity(n);
551
- return complexity;
552
- };
553
- const complexity = getComplexity(effective);
554
- // Check if exported
555
- const name = getNodeName(effective);
556
- const isExported = name ? metadata.exports.includes(name) : false;
557
- // Extract symbols
558
- const definedSymbols = [];
559
- if (name)
560
- definedSymbols.push(name);
561
- const referencedSymbols = [];
562
- // Reduce a constructor / instanceof operand to a simple symbol name:
563
- // bare identifier -> its text; `ns.ClassName` member -> the rightmost
564
- // property (`ClassName`). Returns null for shapes we can't name.
565
- const simpleRefName = (node) => {
566
- var _a, _b;
567
- if (!node)
568
- return null;
569
- if (node.type === "member_expression") {
570
- const prop = node.childForFieldName
571
- ? node.childForFieldName("property")
572
- : null;
573
- return (_a = prop === null || prop === void 0 ? void 0 : prop.text) !== null && _a !== void 0 ? _a : null;
574
560
  }
575
- return (_b = node.text) !== null && _b !== void 0 ? _b : null;
576
- };
577
- const addRef = (name) => {
578
- if (name && !referencedSymbols.includes(name)) {
579
- referencedSymbols.push(name);
561
+ for (const child of (_a = curr.namedChildren) !== null && _a !== void 0 ? _a : []) {
562
+ countComplexity(child);
580
563
  }
581
564
  };
582
- // Type-position references go in a SEPARATE list so they never inflate
583
- // referencedSymbols.length (which drives role classification below and
584
- // the search structural boost). Navigation consumers union the two.
585
- const typeReferencedSymbols = [];
586
- const addTypeRef = (n) => {
587
- if (n && !typeReferencedSymbols.includes(n)) {
588
- typeReferencedSymbols.push(n);
565
+ countComplexity(n);
566
+ return complexity;
567
+ };
568
+ const complexity = getComplexity(effective);
569
+ // Check if exported
570
+ const name = getNodeName(effective);
571
+ const isExported = name ? metadata.exports.includes(name) : false;
572
+ // Extract symbols
573
+ const definedSymbols = [];
574
+ if (name)
575
+ definedSymbols.push(name);
576
+ const referencedSymbols = [];
577
+ // Reduce a constructor / instanceof operand to a simple symbol name:
578
+ // bare identifier -> its text; `ns.ClassName` member -> the rightmost
579
+ // property (`ClassName`). Returns null for shapes we can't name.
580
+ const simpleRefName = (node) => {
581
+ var _a, _b;
582
+ if (!node)
583
+ return null;
584
+ if (node.type === "member_expression") {
585
+ const prop = node.childForFieldName
586
+ ? node.childForFieldName("property")
587
+ : null;
588
+ return (_a = prop === null || prop === void 0 ? void 0 : prop.text) !== null && _a !== void 0 ? _a : null;
589
+ }
590
+ return (_b = node.text) !== null && _b !== void 0 ? _b : null;
591
+ };
592
+ const addRef = (name) => {
593
+ if (name && !referencedSymbols.includes(name)) {
594
+ referencedSymbols.push(name);
595
+ }
596
+ };
597
+ // Type-position references go in a SEPARATE list so they never inflate
598
+ // referencedSymbols.length (which drives role classification below and
599
+ // the search structural boost). Navigation consumers union the two.
600
+ const typeReferencedSymbols = [];
601
+ const addTypeRef = (n) => {
602
+ if (n && !typeReferencedSymbols.includes(n)) {
603
+ typeReferencedSymbols.push(n);
604
+ }
605
+ };
606
+ // Member-call names (`obj.method()`), recorded additively alongside
607
+ // referencedSymbols (see Chunk.memberReferencedSymbols). Deduped, like
608
+ // type refs — a future resolver queries membership, not occurrence count.
609
+ const memberReferencedSymbols = [];
610
+ const addMemberRef = (n) => {
611
+ if (n && !memberReferencedSymbols.includes(n)) {
612
+ memberReferencedSymbols.push(n);
613
+ }
614
+ };
615
+ // Leaf identifier node types across grammars (a bare name with no
616
+ // named children — `ErrorCodes`, not `a.ErrorCodes`).
617
+ const LEAF_ID_TYPES = new Set([
618
+ "identifier",
619
+ "type_identifier",
620
+ "constant", // Ruby
621
+ "name", // PHP
622
+ "simple_identifier", // Kotlin, Swift
623
+ "property_identifier",
624
+ "field_identifier", // Go
625
+ ]);
626
+ const isLeafId = (n) => {
627
+ var _a, _b;
628
+ return !!n &&
629
+ LEAF_ID_TYPES.has(n.type) &&
630
+ ((_b = (_a = n.namedChildren) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) === 0;
631
+ };
632
+ const firstNamed = (n) => { var _a, _b; return (_b = ((_a = n.namedChildren) !== null && _a !== void 0 ? _a : [])[0]) !== null && _b !== void 0 ? _b : null; };
633
+ // Resolve the type name out of an instantiation node (`new Foo`,
634
+ // `Foo{}`, `new Foo()`), preferring an explicit `type` field and
635
+ // falling back to the first named child (qualified names reduce to
636
+ // their rightmost segment via simpleRefName).
637
+ const instantiatedTypeName = (n) => {
638
+ var _a;
639
+ const typed = (_a = (n.childForFieldName ? n.childForFieldName("type") : null)) !== null && _a !== void 0 ? _a : firstNamed(n);
640
+ if (!typed)
641
+ return null;
642
+ if (isLeafId(typed))
643
+ return typed.text;
644
+ return simpleRefName(typed);
645
+ };
646
+ // First `type_identifier` reachable directly or via a `user_type`
647
+ // wrapper — covers Java `instanceof_expression` and Kotlin/Swift
648
+ // `check_expression` (`x is T`).
649
+ const firstTypeIdent = (n) => {
650
+ var _a, _b;
651
+ for (const c of (_a = n.namedChildren) !== null && _a !== void 0 ? _a : []) {
652
+ if (c.type === "type_identifier")
653
+ return c.text;
654
+ if (c.type === "user_type") {
655
+ const t = ((_b = c.namedChildren) !== null && _b !== void 0 ? _b : []).find((x) => x.type === "type_identifier");
656
+ if (t === null || t === void 0 ? void 0 : t.text)
657
+ return t.text;
589
658
  }
590
- };
591
- // Member-call names (`obj.method()`), recorded additively alongside
592
- // referencedSymbols (see Chunk.memberReferencedSymbols). Deduped, like
593
- // type refs — a future resolver queries membership, not occurrence count.
594
- const memberReferencedSymbols = [];
595
- const addMemberRef = (n) => {
596
- if (n && !memberReferencedSymbols.includes(n)) {
597
- memberReferencedSymbols.push(n);
659
+ }
660
+ return null;
661
+ };
662
+ // Member / scope access node types, one per grammar. We capture the
663
+ // head (object/scope) only when it is a Capitalized leaf identifier,
664
+ // so `ErrorCodes.VALIDATION` / `ErrorCodes::NOT_FOUND` yield an edge
665
+ // to `ErrorCodes` while `this.x` / `req.body` / lowercase locals do not.
666
+ const MEMBER_ACCESS_TYPES = new Set([
667
+ "member_expression", // TS/JS
668
+ "attribute", // Python
669
+ "selector_expression", // Go
670
+ "field_access", // Java
671
+ "member_access_expression", // C#
672
+ "scoped_identifier", // Rust
673
+ "scope_resolution", // Ruby
674
+ "navigation_expression", // Kotlin, Swift
675
+ "field_expression", // Scala
676
+ "class_constant_access_expression", // PHP
677
+ ]);
678
+ // Instantiation node types whose first/`type` child names a type.
679
+ const INSTANTIATION_TYPES = new Set([
680
+ "object_creation_expression", // Java, C#, PHP
681
+ "composite_literal", // Go
682
+ "struct_expression", // Rust
683
+ "instance_expression", // Scala
684
+ ]);
685
+ // Harvest Capitalized type names out of an annotation subtree, for the
686
+ // grammars whose type names are NOT `type_identifier` nodes (so Shape 4
687
+ // can't see them): Python/C# spell them `identifier`, PHP spells them
688
+ // `name`. We walk the WHOLE subtree and keep every Capitalized leaf of
689
+ // those kinds — safe because we only ever enter from a type position (a
690
+ // `type` / `return_type` / `returns` field, or a base/heritage list).
691
+ // Excludes the chunk's own name; lowercase builtins (`list`, `int`,
692
+ // `string`) and non-name leaves (`predefined_type`, `string_content`
693
+ // in `Literal["x"]`) fall out via the kind + Capitalized gates.
694
+ const TYPE_NAME_LEAF_TYPES = new Set(["identifier", "name"]);
695
+ const harvestTypeLeaves = (node) => {
696
+ var _a, _b, _c;
697
+ if (!node)
698
+ return;
699
+ if (((_b = (_a = node.namedChildren) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) === 0) {
700
+ if (TYPE_NAME_LEAF_TYPES.has(node.type) &&
701
+ /^[A-Z]/.test(node.text) &&
702
+ node.text !== name) {
703
+ addTypeRef(node.text);
598
704
  }
599
- };
600
- // Leaf identifier node types across grammars (a bare name with no
601
- // named children — `ErrorCodes`, not `a.ErrorCodes`).
602
- const LEAF_ID_TYPES = new Set([
603
- "identifier",
604
- "type_identifier",
605
- "constant", // Ruby
606
- "name", // PHP
607
- "simple_identifier", // Kotlin, Swift
608
- "property_identifier",
609
- "field_identifier", // Go
610
- ]);
611
- const isLeafId = (n) => {
612
- var _a, _b;
613
- return !!n &&
614
- LEAF_ID_TYPES.has(n.type) &&
615
- ((_b = (_a = n.namedChildren) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) === 0;
616
- };
617
- const firstNamed = (n) => { var _a, _b; return (_b = ((_a = n.namedChildren) !== null && _a !== void 0 ? _a : [])[0]) !== null && _b !== void 0 ? _b : null; };
618
- // Resolve the type name out of an instantiation node (`new Foo`,
619
- // `Foo{}`, `new Foo()`), preferring an explicit `type` field and
620
- // falling back to the first named child (qualified names reduce to
621
- // their rightmost segment via simpleRefName).
622
- const instantiatedTypeName = (n) => {
623
- var _a;
624
- const typed = (_a = (n.childForFieldName ? n.childForFieldName("type") : null)) !== null && _a !== void 0 ? _a : firstNamed(n);
625
- if (!typed)
626
- return null;
627
- if (isLeafId(typed))
628
- return typed.text;
629
- return simpleRefName(typed);
630
- };
631
- // First `type_identifier` reachable directly or via a `user_type`
632
- // wrapper — covers Java `instanceof_expression` and Kotlin/Swift
633
- // `check_expression` (`x is T`).
634
- const firstTypeIdent = (n) => {
635
- var _a, _b;
636
- for (const c of (_a = n.namedChildren) !== null && _a !== void 0 ? _a : []) {
637
- if (c.type === "type_identifier")
638
- return c.text;
639
- if (c.type === "user_type") {
640
- const t = ((_b = c.namedChildren) !== null && _b !== void 0 ? _b : []).find((x) => x.type === "type_identifier");
641
- if (t === null || t === void 0 ? void 0 : t.text)
642
- return t.text;
705
+ return;
706
+ }
707
+ for (const c of (_c = node.namedChildren) !== null && _c !== void 0 ? _c : [])
708
+ harvestTypeLeaves(c);
709
+ };
710
+ const extractRefs = (n) => {
711
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1;
712
+ // Handle JS/TS (call_expression), Python (call), Lua (function_call)
713
+ if (n.type === "call_expression" ||
714
+ n.type === "call" ||
715
+ n.type === "function_call") {
716
+ const func = n.childForFieldName
717
+ ? n.childForFieldName("function")
718
+ : null;
719
+ if (func) {
720
+ let funcName = func.text;
721
+ let isMemberCall = false;
722
+ // Handle member access (obj.method) to extract just 'method'
723
+ if (func.type === "member_expression") {
724
+ // JS/TS: object.property
725
+ const prop = func.childForFieldName
726
+ ? func.childForFieldName("property")
727
+ : null;
728
+ if (prop) {
729
+ funcName = prop.text;
730
+ isMemberCall = true;
731
+ }
643
732
  }
644
- }
645
- return null;
646
- };
647
- // Member / scope access node types, one per grammar. We capture the
648
- // head (object/scope) only when it is a Capitalized leaf identifier,
649
- // so `ErrorCodes.VALIDATION` / `ErrorCodes::NOT_FOUND` yield an edge
650
- // to `ErrorCodes` while `this.x` / `req.body` / lowercase locals do not.
651
- const MEMBER_ACCESS_TYPES = new Set([
652
- "member_expression", // TS/JS
653
- "attribute", // Python
654
- "selector_expression", // Go
655
- "field_access", // Java
656
- "member_access_expression", // C#
657
- "scoped_identifier", // Rust
658
- "scope_resolution", // Ruby
659
- "navigation_expression", // Kotlin, Swift
660
- "field_expression", // Scala
661
- "class_constant_access_expression", // PHP
662
- ]);
663
- // Instantiation node types whose first/`type` child names a type.
664
- const INSTANTIATION_TYPES = new Set([
665
- "object_creation_expression", // Java, C#, PHP
666
- "composite_literal", // Go
667
- "struct_expression", // Rust
668
- "instance_expression", // Scala
669
- ]);
670
- // Harvest Capitalized type names out of an annotation subtree, for the
671
- // grammars whose type names are NOT `type_identifier` nodes (so Shape 4
672
- // can't see them): Python/C# spell them `identifier`, PHP spells them
673
- // `name`. We walk the WHOLE subtree and keep every Capitalized leaf of
674
- // those kinds — safe because we only ever enter from a type position (a
675
- // `type` / `return_type` / `returns` field, or a base/heritage list).
676
- // Excludes the chunk's own name; lowercase builtins (`list`, `int`,
677
- // `string`) and non-name leaves (`predefined_type`, `string_content`
678
- // in `Literal["x"]`) fall out via the kind + Capitalized gates.
679
- const TYPE_NAME_LEAF_TYPES = new Set(["identifier", "name"]);
680
- const harvestTypeLeaves = (node) => {
681
- var _a, _b, _c;
682
- if (!node)
683
- return;
684
- if (((_b = (_a = node.namedChildren) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) === 0) {
685
- if (TYPE_NAME_LEAF_TYPES.has(node.type) &&
686
- /^[A-Z]/.test(node.text) &&
687
- node.text !== name) {
688
- addTypeRef(node.text);
733
+ else if (func.type === "attribute") {
734
+ // Python: object.attribute
735
+ const attr = func.childForFieldName
736
+ ? func.childForFieldName("attribute")
737
+ : null;
738
+ if (attr) {
739
+ funcName = attr.text;
740
+ isMemberCall = true;
741
+ }
689
742
  }
690
- return;
743
+ referencedSymbols.push(funcName);
744
+ // Additive: member calls ALSO go here. referencedSymbols is left
745
+ // untouched (no recall loss); this just tags which were members.
746
+ if (isMemberCall)
747
+ addMemberRef(funcName);
691
748
  }
692
- for (const c of (_c = node.namedChildren) !== null && _c !== void 0 ? _c : [])
693
- harvestTypeLeaves(c);
694
- };
695
- const extractRefs = (n) => {
696
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1;
697
- // Handle JS/TS (call_expression), Python (call), Lua (function_call)
698
- if (n.type === "call_expression" ||
699
- n.type === "call" ||
700
- n.type === "function_call") {
701
- const func = n.childForFieldName
702
- ? n.childForFieldName("function")
703
- : null;
704
- if (func) {
705
- let funcName = func.text;
749
+ else {
750
+ // Swift/Kotlin: call_expression has no "function" field;
751
+ // the callable is a positional child
752
+ const firstChild = ((_a = n.namedChildren) !== null && _a !== void 0 ? _a : [])[0];
753
+ if (firstChild) {
754
+ let funcName = firstChild.text;
706
755
  let isMemberCall = false;
707
- // Handle member access (obj.method) to extract just 'method'
708
- if (func.type === "member_expression") {
709
- // JS/TS: object.property
710
- const prop = func.childForFieldName
711
- ? func.childForFieldName("property")
712
- : null;
713
- if (prop) {
714
- funcName = prop.text;
715
- isMemberCall = true;
716
- }
717
- }
718
- else if (func.type === "attribute") {
719
- // Python: object.attribute
720
- const attr = func.childForFieldName
721
- ? func.childForFieldName("attribute")
756
+ if (firstChild.type === "navigation_expression") {
757
+ const suffix = ((_b = firstChild.namedChildren) !== null && _b !== void 0 ? _b : []).find((c) => c.type === "navigation_suffix");
758
+ const methodId = suffix
759
+ ? ((_c = suffix.namedChildren) !== null && _c !== void 0 ? _c : []).find((c) => c.type === "simple_identifier")
722
760
  : null;
723
- if (attr) {
724
- funcName = attr.text;
761
+ if (methodId) {
762
+ funcName = methodId.text;
725
763
  isMemberCall = true;
726
764
  }
727
765
  }
728
766
  referencedSymbols.push(funcName);
729
- // Additive: member calls ALSO go here. referencedSymbols is left
730
- // untouched (no recall loss); this just tags which were members.
731
767
  if (isMemberCall)
732
768
  addMemberRef(funcName);
733
769
  }
734
- else {
735
- // Swift/Kotlin: call_expression has no "function" field;
736
- // the callable is a positional child
737
- const firstChild = ((_a = n.namedChildren) !== null && _a !== void 0 ? _a : [])[0];
738
- if (firstChild) {
739
- let funcName = firstChild.text;
740
- let isMemberCall = false;
741
- if (firstChild.type === "navigation_expression") {
742
- const suffix = ((_b = firstChild.namedChildren) !== null && _b !== void 0 ? _b : []).find((c) => c.type === "navigation_suffix");
743
- const methodId = suffix
744
- ? ((_c = suffix.namedChildren) !== null && _c !== void 0 ? _c : []).find((c) => c.type === "simple_identifier")
745
- : null;
746
- if (methodId) {
747
- funcName = methodId.text;
748
- isMemberCall = true;
749
- }
750
- }
751
- referencedSymbols.push(funcName);
752
- if (isMemberCall)
753
- addMemberRef(funcName);
754
- }
755
- }
756
770
  }
757
- // JSX elements: <Component /> or <Component>
758
- if (n.type === "jsx_self_closing_element" ||
759
- n.type === "jsx_opening_element") {
760
- const nameChild = ((_d = n.namedChildren) !== null && _d !== void 0 ? _d : []).find((c) => c.type === "identifier" ||
761
- c.type === "member_expression" ||
762
- c.type === "nested_identifier");
763
- if (nameChild) {
764
- // Only capture PascalCase components (skip HTML tags like div, span)
765
- const name = nameChild.type === "member_expression"
766
- ? ((_g = (_f = (_e = nameChild.childForFieldName) === null || _e === void 0 ? void 0 : _e.call(nameChild, "property")) === null || _f === void 0 ? void 0 : _f.text) !== null && _g !== void 0 ? _g : nameChild.text)
767
- : nameChild.text;
768
- if (name && /^[A-Z]/.test(name)) {
769
- referencedSymbols.push(name);
770
- }
771
+ }
772
+ // JSX elements: <Component /> or <Component>
773
+ if (n.type === "jsx_self_closing_element" ||
774
+ n.type === "jsx_opening_element") {
775
+ const nameChild = ((_d = n.namedChildren) !== null && _d !== void 0 ? _d : []).find((c) => c.type === "identifier" ||
776
+ c.type === "member_expression" ||
777
+ c.type === "nested_identifier");
778
+ if (nameChild) {
779
+ // Only capture PascalCase components (skip HTML tags like div, span)
780
+ const name = nameChild.type === "member_expression"
781
+ ? ((_g = (_f = (_e = nameChild.childForFieldName) === null || _e === void 0 ? void 0 : _e.call(nameChild, "property")) === null || _f === void 0 ? void 0 : _f.text) !== null && _g !== void 0 ? _g : nameChild.text)
782
+ : nameChild.text;
783
+ if (name && /^[A-Z]/.test(name)) {
784
+ referencedSymbols.push(name);
771
785
  }
772
786
  }
773
- // Identifier-as-value references: edges the call-expression capture
774
- // above misses. These feed the graph-walk consumers (PPR,
775
- // `gmax dead <ClassName>`, audit) that need class/enum references,
776
- // not just method-call names. Node types are grammar-specific but
777
- // each falls into one of three shapes — instantiation, type-test, or
778
- // member/scope access — handled uniformly across the 14 grammars.
779
- // Shape 1 — instantiation: `new ClassName(...)`, `ClassName{...}`.
780
- if (n.type === "new_expression") {
781
- // TS/JS — constructor may be qualified (`ns.ClassName`).
782
- const ctor = n.childForFieldName
783
- ? n.childForFieldName("constructor")
787
+ }
788
+ // Identifier-as-value references: edges the call-expression capture
789
+ // above misses. These feed the graph-walk consumers (PPR,
790
+ // `gmax dead <ClassName>`, audit) that need class/enum references,
791
+ // not just method-call names. Node types are grammar-specific but
792
+ // each falls into one of three shapes — instantiation, type-test, or
793
+ // member/scope access — handled uniformly across the 14 grammars.
794
+ // Shape 1 — instantiation: `new ClassName(...)`, `ClassName{...}`.
795
+ if (n.type === "new_expression") {
796
+ // TS/JS — constructor may be qualified (`ns.ClassName`).
797
+ const ctor = n.childForFieldName
798
+ ? n.childForFieldName("constructor")
799
+ : null;
800
+ addRef(simpleRefName(ctor));
801
+ }
802
+ else if (INSTANTIATION_TYPES.has(n.type)) {
803
+ addRef(instantiatedTypeName(n));
804
+ }
805
+ // Shape 2 — type-test: `x instanceof T`, `x is T`.
806
+ if (n.type === "binary_expression") {
807
+ // TS/JS, PHP — instanceof is a binary operator.
808
+ const op = n.childForFieldName
809
+ ? n.childForFieldName("operator")
810
+ : null;
811
+ if ((op === null || op === void 0 ? void 0 : op.text) === "instanceof") {
812
+ const right = n.childForFieldName
813
+ ? n.childForFieldName("right")
784
814
  : null;
785
- addRef(simpleRefName(ctor));
815
+ addRef(simpleRefName(right));
786
816
  }
787
- else if (INSTANTIATION_TYPES.has(n.type)) {
788
- addRef(instantiatedTypeName(n));
817
+ }
818
+ else if (n.type === "instanceof_expression" || // Java
819
+ n.type === "check_expression" // Kotlin, Swift (`x is T`)
820
+ ) {
821
+ addRef(firstTypeIdent(n));
822
+ }
823
+ else if (n.type === "is_pattern_expression") {
824
+ // C# — `x is BeyondError`: the type sits in a constant_pattern.
825
+ const cp = ((_h = n.namedChildren) !== null && _h !== void 0 ? _h : []).find((c) => c.type === "constant_pattern");
826
+ const id = cp ? firstNamed(cp) : null;
827
+ if (isLeafId(id) && id && /^[A-Z]/.test(id.text))
828
+ addRef(id.text);
829
+ }
830
+ // Shape 3 — member / scope access: `ErrorCodes.MEMBER`,
831
+ // `ErrorCodes::MEMBER`. Capitalized head only (skip `this.x`).
832
+ if (MEMBER_ACCESS_TYPES.has(n.type)) {
833
+ const head = firstNamed(n);
834
+ if (head && isLeafId(head) && /^[A-Z]/.test(head.text)) {
835
+ addRef(head.text);
789
836
  }
790
- // Shape 2 — type-test: `x instanceof T`, `x is T`.
791
- if (n.type === "binary_expression") {
792
- // TS/JS, PHP — instanceof is a binary operator.
793
- const op = n.childForFieldName
794
- ? n.childForFieldName("operator")
795
- : null;
796
- if ((op === null || op === void 0 ? void 0 : op.text) === "instanceof") {
797
- const right = n.childForFieldName
798
- ? n.childForFieldName("right")
799
- : null;
800
- addRef(simpleRefName(right));
801
- }
837
+ }
838
+ // Shape 4 — type-position reference (TS/TSX): `: T`, `<T>`, `T[]`,
839
+ // `as T`, `interface X extends T`, type aliases. TS uses a distinct
840
+ // `type_identifier` node for type names (primitives are
841
+ // `predefined_type`, so they never reach here). Capture Capitalized
842
+ // ones, skipping the chunk's own name and any locally-declared type
843
+ // parameter (`<T>` and its uses `value: T`). Constraints
844
+ // (`T extends Foo`) still yield `Foo`. Type list, never referencedSymbols.
845
+ if (n.type === "type_identifier" &&
846
+ /^[A-Z]/.test(n.text) &&
847
+ n.text !== name &&
848
+ !declaredTypeParams.has(n.text)) {
849
+ addTypeRef(n.text);
850
+ }
851
+ // Shape 5 — class heritage `class A extends B`: the superclass is an
852
+ // `identifier` (a runtime value), not a `type_identifier`, so Shape 4
853
+ // misses it. `implements I` and `interface X extends Y` use
854
+ // type_identifier and are already covered. Reduce `extends ns.Base`
855
+ // to `Base`; skip type arguments (Shape 4 handles those).
856
+ if (n.type === "extends_clause") {
857
+ for (const c of (_j = n.namedChildren) !== null && _j !== void 0 ? _j : []) {
858
+ if (c.type === "type_arguments")
859
+ continue;
860
+ const sup = simpleRefName(c);
861
+ if (sup && /^[A-Z]/.test(sup) && sup !== name)
862
+ addTypeRef(sup);
802
863
  }
803
- else if (n.type === "instanceof_expression" || // Java
804
- n.type === "check_expression" // Kotlin, Swift (`x is T`)
805
- ) {
806
- addRef(firstTypeIdent(n));
864
+ }
865
+ // Shape 6 — type-position references for grammars whose type names
866
+ // are plain `identifier` / `name` nodes (not `type_identifier`), so
867
+ // Shape 4 can't reach them. Read the annotation off the carrier
868
+ // node's type field and harvest from THAT subtree only — never the
869
+ // node as a whole — so value expressions stay out of the type list.
870
+ // Each grammar is gated by `lang` because the carrier node/field
871
+ // names collide across grammars (`function_definition`,
872
+ // `method_declaration`, `assignment`, …). The other typed grammars
873
+ // (Go/Rust/Java/Kotlin/Scala/Swift) spell type names as
874
+ // `type_identifier` and are already covered by Shape 4.
875
+ if (lang === "python") {
876
+ // `x: Foo`, `-> Bar`, `v: Baz = …`, and `class C(Base)` bases.
877
+ if (n.type === "typed_parameter" ||
878
+ n.type === "typed_default_parameter") {
879
+ harvestTypeLeaves((_l = (_k = n.childForFieldName) === null || _k === void 0 ? void 0 : _k.call(n, "type")) !== null && _l !== void 0 ? _l : null);
807
880
  }
808
- else if (n.type === "is_pattern_expression") {
809
- // C# — `x is BeyondError`: the type sits in a constant_pattern.
810
- const cp = ((_h = n.namedChildren) !== null && _h !== void 0 ? _h : []).find((c) => c.type === "constant_pattern");
811
- const id = cp ? firstNamed(cp) : null;
812
- if (isLeafId(id) && id && /^[A-Z]/.test(id.text))
813
- addRef(id.text);
881
+ else if (n.type === "function_definition") {
882
+ harvestTypeLeaves((_o = (_m = n.childForFieldName) === null || _m === void 0 ? void 0 : _m.call(n, "return_type")) !== null && _o !== void 0 ? _o : null);
814
883
  }
815
- // Shape 3 — member / scope access: `ErrorCodes.MEMBER`,
816
- // `ErrorCodes::MEMBER`. Capitalized head only (skip `this.x`).
817
- if (MEMBER_ACCESS_TYPES.has(n.type)) {
818
- const head = firstNamed(n);
819
- if (head && isLeafId(head) && /^[A-Z]/.test(head.text)) {
820
- addRef(head.text);
821
- }
884
+ else if (n.type === "assignment") {
885
+ harvestTypeLeaves((_q = (_p = n.childForFieldName) === null || _p === void 0 ? void 0 : _p.call(n, "type")) !== null && _q !== void 0 ? _q : null);
822
886
  }
823
- // Shape 4 — type-position reference (TS/TSX): `: T`, `<T>`, `T[]`,
824
- // `as T`, `interface X extends T`, type aliases. TS uses a distinct
825
- // `type_identifier` node for type names (primitives are
826
- // `predefined_type`, so they never reach here). Capture Capitalized
827
- // ones, skipping the chunk's own name and any locally-declared type
828
- // parameter (`<T>` and its uses `value: T`). Constraints
829
- // (`T extends Foo`) still yield `Foo`. Type list, never referencedSymbols.
830
- if (n.type === "type_identifier" &&
831
- /^[A-Z]/.test(n.text) &&
832
- n.text !== name &&
833
- !declaredTypeParams.has(n.text)) {
834
- addTypeRef(n.text);
887
+ else if (n.type === "class_definition") {
888
+ harvestTypeLeaves((_s = (_r = n.childForFieldName) === null || _r === void 0 ? void 0 : _r.call(n, "superclasses")) !== null && _s !== void 0 ? _s : null);
835
889
  }
836
- // Shape 5 — class heritage `class A extends B`: the superclass is an
837
- // `identifier` (a runtime value), not a `type_identifier`, so Shape 4
838
- // misses it. `implements I` and `interface X extends Y` use
839
- // type_identifier and are already covered. Reduce `extends ns.Base`
840
- // to `Base`; skip type arguments (Shape 4 handles those).
841
- if (n.type === "extends_clause") {
842
- for (const c of (_j = n.namedChildren) !== null && _j !== void 0 ? _j : []) {
843
- if (c.type === "type_arguments")
844
- continue;
845
- const sup = simpleRefName(c);
846
- if (sup && /^[A-Z]/.test(sup) && sup !== name)
847
- addTypeRef(sup);
848
- }
890
+ }
891
+ else if (lang === "c_sharp") {
892
+ // Method return (`returns`), parameter / property / variable
893
+ // (`type`), and the base/interface list.
894
+ if (n.type === "parameter" ||
895
+ n.type === "property_declaration" ||
896
+ n.type === "variable_declaration") {
897
+ harvestTypeLeaves((_u = (_t = n.childForFieldName) === null || _t === void 0 ? void 0 : _t.call(n, "type")) !== null && _u !== void 0 ? _u : null);
849
898
  }
850
- // Shape 6 — type-position references for grammars whose type names
851
- // are plain `identifier` / `name` nodes (not `type_identifier`), so
852
- // Shape 4 can't reach them. Read the annotation off the carrier
853
- // node's type field and harvest from THAT subtree only — never the
854
- // node as a whole — so value expressions stay out of the type list.
855
- // Each grammar is gated by `lang` because the carrier node/field
856
- // names collide across grammars (`function_definition`,
857
- // `method_declaration`, `assignment`, …). The other typed grammars
858
- // (Go/Rust/Java/Kotlin/Scala/Swift) spell type names as
859
- // `type_identifier` and are already covered by Shape 4.
860
- if (lang === "python") {
861
- // `x: Foo`, `-> Bar`, `v: Baz = …`, and `class C(Base)` bases.
862
- if (n.type === "typed_parameter" ||
863
- n.type === "typed_default_parameter") {
864
- harvestTypeLeaves((_l = (_k = n.childForFieldName) === null || _k === void 0 ? void 0 : _k.call(n, "type")) !== null && _l !== void 0 ? _l : null);
865
- }
866
- else if (n.type === "function_definition") {
867
- harvestTypeLeaves((_o = (_m = n.childForFieldName) === null || _m === void 0 ? void 0 : _m.call(n, "return_type")) !== null && _o !== void 0 ? _o : null);
868
- }
869
- else if (n.type === "assignment") {
870
- harvestTypeLeaves((_q = (_p = n.childForFieldName) === null || _p === void 0 ? void 0 : _p.call(n, "type")) !== null && _q !== void 0 ? _q : null);
871
- }
872
- else if (n.type === "class_definition") {
873
- harvestTypeLeaves((_s = (_r = n.childForFieldName) === null || _r === void 0 ? void 0 : _r.call(n, "superclasses")) !== null && _s !== void 0 ? _s : null);
874
- }
899
+ else if (n.type === "method_declaration") {
900
+ harvestTypeLeaves((_w = (_v = n.childForFieldName) === null || _v === void 0 ? void 0 : _v.call(n, "returns")) !== null && _w !== void 0 ? _w : null);
875
901
  }
876
- else if (lang === "c_sharp") {
877
- // Method return (`returns`), parameter / property / variable
878
- // (`type`), and the base/interface list.
879
- if (n.type === "parameter" ||
880
- n.type === "property_declaration" ||
881
- n.type === "variable_declaration") {
882
- harvestTypeLeaves((_u = (_t = n.childForFieldName) === null || _t === void 0 ? void 0 : _t.call(n, "type")) !== null && _u !== void 0 ? _u : null);
883
- }
884
- else if (n.type === "method_declaration") {
885
- harvestTypeLeaves((_w = (_v = n.childForFieldName) === null || _v === void 0 ? void 0 : _v.call(n, "returns")) !== null && _w !== void 0 ? _w : null);
886
- }
887
- else if (n.type === "base_list") {
888
- harvestTypeLeaves(n);
889
- }
902
+ else if (n.type === "base_list") {
903
+ harvestTypeLeaves(n);
890
904
  }
891
- else if (lang === "php") {
892
- // Types are `name` inside `named_type` / `optional_type`.
893
- // Parameter / property (`type`), function & method return
894
- // (`return_type`), and the extends / implements clauses.
895
- if (n.type === "simple_parameter" ||
896
- n.type === "property_declaration") {
897
- harvestTypeLeaves((_y = (_x = n.childForFieldName) === null || _x === void 0 ? void 0 : _x.call(n, "type")) !== null && _y !== void 0 ? _y : null);
898
- }
899
- else if (n.type === "function_definition" ||
900
- n.type === "method_declaration") {
901
- harvestTypeLeaves((_0 = (_z = n.childForFieldName) === null || _z === void 0 ? void 0 : _z.call(n, "return_type")) !== null && _0 !== void 0 ? _0 : null);
902
- }
903
- else if (n.type === "base_clause" ||
904
- n.type === "class_interface_clause") {
905
- harvestTypeLeaves(n);
906
- }
905
+ }
906
+ else if (lang === "php") {
907
+ // Types are `name` inside `named_type` / `optional_type`.
908
+ // Parameter / property (`type`), function & method return
909
+ // (`return_type`), and the extends / implements clauses.
910
+ if (n.type === "simple_parameter" ||
911
+ n.type === "property_declaration") {
912
+ harvestTypeLeaves((_y = (_x = n.childForFieldName) === null || _x === void 0 ? void 0 : _x.call(n, "type")) !== null && _y !== void 0 ? _y : null);
907
913
  }
908
- for (const child of (_1 = n.namedChildren) !== null && _1 !== void 0 ? _1 : []) {
909
- extractRefs(child);
914
+ else if (n.type === "function_definition" ||
915
+ n.type === "method_declaration") {
916
+ harvestTypeLeaves((_0 = (_z = n.childForFieldName) === null || _z === void 0 ? void 0 : _z.call(n, "return_type")) !== null && _0 !== void 0 ? _0 : null);
910
917
  }
911
- };
912
- // Collect locally-declared type-parameter names (`<T, K>`) so their
913
- // *uses* (`value: T`) are excluded from type refs, not just their
914
- // declarations. Chunk-scoped, which matches single-definition chunks.
915
- const declaredTypeParams = new Set();
916
- const collectTypeParams = (n) => {
917
- var _a;
918
- if (n.type === "type_parameter") {
919
- const nm = firstNamed(n);
920
- if ((nm === null || nm === void 0 ? void 0 : nm.type) === "type_identifier")
921
- declaredTypeParams.add(nm.text);
918
+ else if (n.type === "base_clause" ||
919
+ n.type === "class_interface_clause") {
920
+ harvestTypeLeaves(n);
922
921
  }
923
- for (const child of (_a = n.namedChildren) !== null && _a !== void 0 ? _a : [])
924
- collectTypeParams(child);
925
- };
926
- collectTypeParams(effective);
927
- extractRefs(effective);
928
- // Classify role
929
- let role = "IMPLEMENTATION";
930
- if (isDefinition)
931
- role = "DEFINITION";
932
- if (complexity > 5 && referencedSymbols.length > 5)
933
- role = "ORCHESTRATION";
934
- if (effective.type.includes("import"))
935
- role = "IMPORT";
936
- chunks.push({
937
- content: node.text,
938
- startLine: node.startPosition.row,
939
- endLine: node.endPosition.row,
940
- type: classify(effective),
941
- context,
942
- docstring,
943
- complexity,
944
- isExported,
945
- definedSymbols,
946
- referencedSymbols,
947
- typeReferencedSymbols,
948
- memberReferencedSymbols,
949
- role,
950
- parentSymbol: stack.length > 1
951
- ? stack[stack.length - 1].replace(/^(Class|Method|Function|Interface|Type): /, "")
952
- : undefined,
953
- });
954
- nextStack = context;
955
- }
956
- for (const child of (_a = effective.namedChildren) !== null && _a !== void 0 ? _a : []) {
957
- visit(child, nextStack);
958
- }
959
- };
960
- for (const child of (_b = root.namedChildren) !== null && _b !== void 0 ? _b : []) {
961
- visit(child, [fileContext]);
962
- const effective = unwrapExport(child);
963
- const isDefinition = isDefType(effective.type) || isTopLevelValueDef(effective);
964
- if (!isDefinition)
965
- continue;
966
- if (child.startIndex > cursorIndex) {
967
- const gapText = content.slice(cursorIndex, child.startIndex);
968
- if (gapText.trim().length > 0) {
969
- blockChunks.push({
970
- content: gapText,
971
- startLine: cursorRow,
972
- endLine: child.startPosition.row,
973
- type: "block",
974
- context: [fileContext],
975
- });
976
922
  }
977
- }
978
- cursorIndex = child.endIndex;
979
- cursorRow = child.endPosition.row;
923
+ for (const child of (_1 = n.namedChildren) !== null && _1 !== void 0 ? _1 : []) {
924
+ extractRefs(child);
925
+ }
926
+ };
927
+ // Collect locally-declared type-parameter names (`<T, K>`) so their
928
+ // *uses* (`value: T`) are excluded from type refs, not just their
929
+ // declarations. Chunk-scoped, which matches single-definition chunks.
930
+ const declaredTypeParams = new Set();
931
+ const collectTypeParams = (n) => {
932
+ var _a;
933
+ if (n.type === "type_parameter") {
934
+ const nm = firstNamed(n);
935
+ if ((nm === null || nm === void 0 ? void 0 : nm.type) === "type_identifier")
936
+ declaredTypeParams.add(nm.text);
937
+ }
938
+ for (const child of (_a = n.namedChildren) !== null && _a !== void 0 ? _a : [])
939
+ collectTypeParams(child);
940
+ };
941
+ collectTypeParams(effective);
942
+ extractRefs(effective);
943
+ // Classify role
944
+ let role = "IMPLEMENTATION";
945
+ if (isDefinition)
946
+ role = "DEFINITION";
947
+ if (complexity > 5 && referencedSymbols.length > 5)
948
+ role = "ORCHESTRATION";
949
+ if (effective.type.includes("import"))
950
+ role = "IMPORT";
951
+ chunks.push({
952
+ content: node.text,
953
+ startLine: node.startPosition.row,
954
+ endLine: node.endPosition.row,
955
+ type: classify(effective),
956
+ context,
957
+ docstring,
958
+ complexity,
959
+ isExported,
960
+ definedSymbols,
961
+ referencedSymbols,
962
+ typeReferencedSymbols,
963
+ memberReferencedSymbols,
964
+ role,
965
+ parentSymbol: stack.length > 1
966
+ ? stack[stack.length - 1].replace(/^(Class|Method|Function|Interface|Type): /, "")
967
+ : undefined,
968
+ });
969
+ nextStack = context;
970
+ }
971
+ for (const child of (_a = effective.namedChildren) !== null && _a !== void 0 ? _a : []) {
972
+ visit(child, nextStack);
980
973
  }
981
- if (cursorIndex < content.length) {
982
- const tailText = content.slice(cursorIndex);
983
- if (tailText.trim().length > 0) {
974
+ };
975
+ for (const child of (_a = root.namedChildren) !== null && _a !== void 0 ? _a : []) {
976
+ visit(child, [fileContext]);
977
+ const effective = unwrapExport(child);
978
+ const isDefinition = isDefType(effective.type) || isTopLevelValueDef(effective);
979
+ if (!isDefinition)
980
+ continue;
981
+ if (child.startIndex > cursorIndex) {
982
+ const gapText = content.slice(cursorIndex, child.startIndex);
983
+ if (gapText.trim().length > 0) {
984
984
  blockChunks.push({
985
- content: tailText,
985
+ content: gapText,
986
986
  startLine: cursorRow,
987
- endLine: root.endPosition.row,
987
+ endLine: child.startPosition.row,
988
988
  type: "block",
989
989
  context: [fileContext],
990
990
  });
991
991
  }
992
992
  }
993
- if (!sawDefinition)
994
- return { chunks: [], metadata };
995
- const combined = [...blockChunks, ...chunks].sort((a, b) => a.startLine - b.startLine || a.endLine - b.endLine);
996
- return { chunks: combined, metadata };
997
- });
993
+ cursorIndex = child.endIndex;
994
+ cursorRow = child.endPosition.row;
995
+ }
996
+ if (cursorIndex < content.length) {
997
+ const tailText = content.slice(cursorIndex);
998
+ if (tailText.trim().length > 0) {
999
+ blockChunks.push({
1000
+ content: tailText,
1001
+ startLine: cursorRow,
1002
+ endLine: root.endPosition.row,
1003
+ type: "block",
1004
+ context: [fileContext],
1005
+ });
1006
+ }
1007
+ }
1008
+ if (!sawDefinition)
1009
+ return { chunks: [], metadata };
1010
+ const combined = [...blockChunks, ...chunks].sort((a, b) => a.startLine - b.startLine || a.endLine - b.endLine);
1011
+ return { chunks: combined, metadata };
998
1012
  }
999
1013
  /**
1000
1014
  * Restrict a sub-chunk's symbol lists to names that actually occur in its