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