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.
- package/.claude-plugin/marketplace.json +1 -1
- package/README.md +6 -2
- package/dist/commands/doctor.js +20 -5
- package/dist/commands/mcp.js +60 -15
- package/dist/commands/search-run.js +4 -3
- package/dist/commands/similar.js +2 -2
- package/dist/eval-graph-recovery-probe.js +2 -2
- package/dist/eval-graph-sanity.js +2 -2
- package/dist/lib/analysis/surprising-connections.js +2 -2
- package/dist/lib/daemon/daemon.js +1 -0
- package/dist/lib/index/batch-processor.js +49 -22
- package/dist/lib/index/chunker.js +616 -602
- package/dist/lib/index/syncer.js +1 -1
- package/dist/lib/index/watcher.js +14 -3
- package/dist/lib/search/searcher.js +2 -2
- package/dist/lib/skeleton/skeletonizer.js +9 -1
- package/dist/lib/store/ann-config.js +34 -0
- package/dist/lib/store/vector-db.js +184 -33
- package/dist/lib/workers/orchestrator.js +5 -35
- package/dist/lib/workers/pool.js +15 -32
- package/package.json +3 -8
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
|
@@ -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
|
|
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
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
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
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
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
|
|
452
|
-
|
|
453
|
-
const
|
|
454
|
-
if (
|
|
455
|
-
return
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
return
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
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
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
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 (
|
|
497
|
-
|
|
498
|
-
|
|
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
|
|
506
|
-
|
|
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
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
//
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
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
|
-
|
|
547
|
-
|
|
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
|
-
|
|
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
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
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
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
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
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
"
|
|
609
|
-
"
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
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
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
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
|
-
|
|
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
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
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
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
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 (
|
|
724
|
-
funcName =
|
|
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
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
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
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
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(
|
|
815
|
+
addRef(simpleRefName(right));
|
|
786
816
|
}
|
|
787
|
-
|
|
788
|
-
|
|
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
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
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
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
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 === "
|
|
809
|
-
|
|
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
|
-
|
|
816
|
-
|
|
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
|
-
|
|
824
|
-
|
|
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
|
-
|
|
837
|
-
|
|
838
|
-
//
|
|
839
|
-
//
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
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
|
-
|
|
851
|
-
|
|
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 (
|
|
877
|
-
|
|
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
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
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
|
-
|
|
909
|
-
|
|
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
|
-
|
|
913
|
-
|
|
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
|
-
|
|
979
|
-
|
|
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
|
-
|
|
982
|
-
|
|
983
|
-
|
|
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:
|
|
985
|
+
content: gapText,
|
|
986
986
|
startLine: cursorRow,
|
|
987
|
-
endLine:
|
|
987
|
+
endLine: child.startPosition.row,
|
|
988
988
|
type: "block",
|
|
989
989
|
context: [fileContext],
|
|
990
990
|
});
|
|
991
991
|
}
|
|
992
992
|
}
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
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
|