@colbymchenry/codegraph 0.7.3 → 0.7.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/README.md +57 -0
- package/dist/bin/codegraph.js +39 -4
- package/dist/bin/codegraph.js.map +1 -1
- package/dist/bin/node-version-check.d.ts +17 -0
- package/dist/bin/node-version-check.d.ts.map +1 -0
- package/dist/bin/node-version-check.js +39 -0
- package/dist/bin/node-version-check.js.map +1 -0
- package/dist/db/index.d.ts +9 -2
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +17 -7
- package/dist/db/index.js.map +1 -1
- package/dist/db/migrations.d.ts +1 -1
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +11 -1
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/queries.d.ts +16 -0
- package/dist/db/queries.d.ts.map +1 -1
- package/dist/db/queries.js +144 -7
- package/dist/db/queries.js.map +1 -1
- package/dist/db/schema.sql +6 -3
- package/dist/db/sqlite-adapter.d.ts +23 -4
- package/dist/db/sqlite-adapter.d.ts.map +1 -1
- package/dist/db/sqlite-adapter.js +51 -11
- package/dist/db/sqlite-adapter.js.map +1 -1
- package/dist/extraction/grammars.d.ts +1 -1
- package/dist/extraction/grammars.d.ts.map +1 -1
- package/dist/extraction/grammars.js +12 -4
- package/dist/extraction/grammars.js.map +1 -1
- package/dist/extraction/index.d.ts +20 -0
- package/dist/extraction/index.d.ts.map +1 -1
- package/dist/extraction/index.js +111 -7
- package/dist/extraction/index.js.map +1 -1
- package/dist/extraction/languages/index.d.ts.map +1 -1
- package/dist/extraction/languages/index.js +2 -0
- package/dist/extraction/languages/index.js.map +1 -1
- package/dist/extraction/languages/scala.d.ts +3 -0
- package/dist/extraction/languages/scala.d.ts.map +1 -0
- package/dist/extraction/languages/scala.js +139 -0
- package/dist/extraction/languages/scala.js.map +1 -0
- package/dist/extraction/parse-worker.js +39 -2
- package/dist/extraction/parse-worker.js.map +1 -1
- package/dist/extraction/tree-sitter.d.ts +32 -16
- package/dist/extraction/tree-sitter.d.ts.map +1 -1
- package/dist/extraction/tree-sitter.js +266 -67
- package/dist/extraction/tree-sitter.js.map +1 -1
- package/dist/extraction/vue-extractor.d.ts +36 -0
- package/dist/extraction/vue-extractor.d.ts.map +1 -0
- package/dist/extraction/vue-extractor.js +163 -0
- package/dist/extraction/vue-extractor.js.map +1 -0
- package/dist/extraction/wasm/tree-sitter-scala.wasm +0 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +6 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/server-instructions.d.ts +19 -0
- package/dist/mcp/server-instructions.d.ts.map +1 -0
- package/dist/mcp/server-instructions.js +59 -0
- package/dist/mcp/server-instructions.js.map +1 -0
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +13 -2
- package/dist/mcp/tools.js.map +1 -1
- package/dist/resolution/frameworks/cargo-workspace.d.ts +18 -0
- package/dist/resolution/frameworks/cargo-workspace.d.ts.map +1 -0
- package/dist/resolution/frameworks/cargo-workspace.js +225 -0
- package/dist/resolution/frameworks/cargo-workspace.js.map +1 -0
- package/dist/resolution/frameworks/csharp.d.ts.map +1 -1
- package/dist/resolution/frameworks/csharp.js +72 -78
- package/dist/resolution/frameworks/csharp.js.map +1 -1
- package/dist/resolution/frameworks/express.d.ts.map +1 -1
- package/dist/resolution/frameworks/express.js +47 -26
- package/dist/resolution/frameworks/express.js.map +1 -1
- package/dist/resolution/frameworks/go.d.ts.map +1 -1
- package/dist/resolution/frameworks/go.js +41 -72
- package/dist/resolution/frameworks/go.js.map +1 -1
- package/dist/resolution/frameworks/index.d.ts +7 -0
- package/dist/resolution/frameworks/index.d.ts.map +1 -1
- package/dist/resolution/frameworks/index.js +13 -1
- package/dist/resolution/frameworks/index.js.map +1 -1
- package/dist/resolution/frameworks/java.d.ts.map +1 -1
- package/dist/resolution/frameworks/java.js +36 -40
- package/dist/resolution/frameworks/java.js.map +1 -1
- package/dist/resolution/frameworks/laravel.d.ts.map +1 -1
- package/dist/resolution/frameworks/laravel.js +94 -44
- package/dist/resolution/frameworks/laravel.js.map +1 -1
- package/dist/resolution/frameworks/python.d.ts.map +1 -1
- package/dist/resolution/frameworks/python.js +163 -151
- package/dist/resolution/frameworks/python.js.map +1 -1
- package/dist/resolution/frameworks/react.d.ts.map +1 -1
- package/dist/resolution/frameworks/react.js +3 -2
- package/dist/resolution/frameworks/react.js.map +1 -1
- package/dist/resolution/frameworks/ruby.d.ts.map +1 -1
- package/dist/resolution/frameworks/ruby.js +39 -91
- package/dist/resolution/frameworks/ruby.js.map +1 -1
- package/dist/resolution/frameworks/rust.d.ts.map +1 -1
- package/dist/resolution/frameworks/rust.js +85 -60
- package/dist/resolution/frameworks/rust.js.map +1 -1
- package/dist/resolution/frameworks/svelte.d.ts.map +1 -1
- package/dist/resolution/frameworks/svelte.js +3 -2
- package/dist/resolution/frameworks/svelte.js.map +1 -1
- package/dist/resolution/frameworks/swift.d.ts.map +1 -1
- package/dist/resolution/frameworks/swift.js +54 -46
- package/dist/resolution/frameworks/swift.js.map +1 -1
- package/dist/resolution/frameworks/vue.d.ts +9 -0
- package/dist/resolution/frameworks/vue.d.ts.map +1 -0
- package/dist/resolution/frameworks/vue.js +306 -0
- package/dist/resolution/frameworks/vue.js.map +1 -0
- package/dist/resolution/import-resolver.d.ts +17 -1
- package/dist/resolution/import-resolver.d.ts.map +1 -1
- package/dist/resolution/import-resolver.js +256 -46
- package/dist/resolution/import-resolver.js.map +1 -1
- package/dist/resolution/index.d.ts +8 -0
- package/dist/resolution/index.d.ts.map +1 -1
- package/dist/resolution/index.js +78 -1
- package/dist/resolution/index.js.map +1 -1
- package/dist/resolution/name-matcher.d.ts.map +1 -1
- package/dist/resolution/name-matcher.js +21 -0
- package/dist/resolution/name-matcher.js.map +1 -1
- package/dist/resolution/path-aliases.d.ts +68 -0
- package/dist/resolution/path-aliases.d.ts.map +1 -0
- package/dist/resolution/path-aliases.js +238 -0
- package/dist/resolution/path-aliases.js.map +1 -0
- package/dist/resolution/strip-comments.d.ts +27 -0
- package/dist/resolution/strip-comments.d.ts.map +1 -0
- package/dist/resolution/strip-comments.js +441 -0
- package/dist/resolution/strip-comments.js.map +1 -0
- package/dist/resolution/types.d.ts +63 -3
- package/dist/resolution/types.d.ts.map +1 -1
- package/dist/search/query-parser.d.ts +57 -0
- package/dist/search/query-parser.d.ts.map +1 -0
- package/dist/search/query-parser.js +177 -0
- package/dist/search/query-parser.js.map +1 -0
- package/dist/types.d.ts +11 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +68 -1
- package/dist/types.js.map +1 -1
- package/package.json +6 -3
- package/dist/installer/banner.d.ts +0 -40
- package/dist/installer/banner.d.ts.map +0 -1
- package/dist/installer/banner.js +0 -165
- package/dist/installer/banner.js.map +0 -1
- package/dist/installer/prompts.d.ts +0 -18
- package/dist/installer/prompts.d.ts.map +0 -1
- package/dist/installer/prompts.js +0 -113
- package/dist/installer/prompts.js.map +0 -1
- package/dist/sentry.d.ts +0 -24
- package/dist/sentry.d.ts.map +0 -1
- package/dist/sentry.js +0 -166
- package/dist/sentry.js.map +0 -1
- package/dist/sync/git-hooks.d.ts +0 -66
- package/dist/sync/git-hooks.d.ts.map +0 -1
- package/dist/sync/git-hooks.js +0 -281
- package/dist/sync/git-hooks.js.map +0 -1
- package/dist/vectors/embedder.d.ts +0 -140
- package/dist/vectors/embedder.d.ts.map +0 -1
- package/dist/vectors/embedder.js +0 -338
- package/dist/vectors/embedder.js.map +0 -1
- package/dist/vectors/index.d.ts +0 -9
- package/dist/vectors/index.d.ts.map +0 -1
- package/dist/vectors/index.js +0 -20
- package/dist/vectors/index.js.map +0 -1
- package/dist/vectors/manager.d.ts +0 -119
- package/dist/vectors/manager.d.ts.map +0 -1
- package/dist/vectors/manager.js +0 -274
- package/dist/vectors/manager.js.map +0 -1
- package/dist/vectors/search.d.ts +0 -134
- package/dist/vectors/search.d.ts.map +0 -1
- package/dist/vectors/search.js +0 -411
- package/dist/vectors/search.js.map +0 -1
- package/dist/visualizer/public/index.html +0 -1994
- package/dist/visualizer/server.d.ts +0 -46
- package/dist/visualizer/server.d.ts.map +0 -1
- package/dist/visualizer/server.js +0 -491
- package/dist/visualizer/server.js.map +0 -1
|
@@ -47,6 +47,8 @@ const languages_1 = require("./languages");
|
|
|
47
47
|
const liquid_extractor_1 = require("./liquid-extractor");
|
|
48
48
|
const svelte_extractor_1 = require("./svelte-extractor");
|
|
49
49
|
const dfm_extractor_1 = require("./dfm-extractor");
|
|
50
|
+
const vue_extractor_1 = require("./vue-extractor");
|
|
51
|
+
const frameworks_1 = require("../resolution/frameworks");
|
|
50
52
|
// Re-export for backward compatibility
|
|
51
53
|
var tree_sitter_helpers_2 = require("./tree-sitter-helpers");
|
|
52
54
|
Object.defineProperty(exports, "generateNodeId", { enumerable: true, get: function () { return tree_sitter_helpers_2.generateNodeId; } });
|
|
@@ -111,6 +113,16 @@ function extractName(node, source, extractor) {
|
|
|
111
113
|
}
|
|
112
114
|
return '<anonymous>';
|
|
113
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Tree-sitter node kinds that represent constructor invocations
|
|
118
|
+
* (`new Foo()` and friends). Used by extractInstantiation to emit
|
|
119
|
+
* an `instantiates` reference targeting the class name.
|
|
120
|
+
*/
|
|
121
|
+
const INSTANTIATION_KINDS = new Set([
|
|
122
|
+
'new_expression', // typescript / javascript / tsx / jsx
|
|
123
|
+
'object_creation_expression', // java / c#
|
|
124
|
+
'instance_creation_expression', // some grammars
|
|
125
|
+
]);
|
|
114
126
|
/**
|
|
115
127
|
* TreeSitterExtractor - Main extraction class
|
|
116
128
|
*/
|
|
@@ -331,12 +343,19 @@ class TreeSitterExtractor {
|
|
|
331
343
|
this.extractVariable(node);
|
|
332
344
|
skipChildren = true; // extractVariable handles children
|
|
333
345
|
}
|
|
334
|
-
//
|
|
335
|
-
//
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
346
|
+
// `export_statement` itself is not extracted — the walker descends
|
|
347
|
+
// into children, where the inner declaration (lexical_declaration,
|
|
348
|
+
// function_declaration, class_declaration, etc.) is dispatched to
|
|
349
|
+
// its own extractor. `isExported` walks the parent chain, so the
|
|
350
|
+
// exported flag is preserved automatically.
|
|
351
|
+
//
|
|
352
|
+
// Calling extractExportedVariables here AND descending caused every
|
|
353
|
+
// `export const X = ...` to produce two nodes for the same symbol —
|
|
354
|
+
// one kind:'variable' from extractExportedVariables and one
|
|
355
|
+
// kind:'constant' from extractVariable. The dedicated dispatch is
|
|
356
|
+
// the correct one (it picks kind from isConst, captures the
|
|
357
|
+
// initializer signature, and walks type annotations); the
|
|
358
|
+
// export-statement helper was redundant.
|
|
340
359
|
// Check for imports
|
|
341
360
|
else if (this.extractor.importTypes.includes(nodeType)) {
|
|
342
361
|
this.extractImport(node);
|
|
@@ -345,6 +364,17 @@ class TreeSitterExtractor {
|
|
|
345
364
|
else if (this.extractor.callTypes.includes(nodeType)) {
|
|
346
365
|
this.extractCall(node);
|
|
347
366
|
}
|
|
367
|
+
// `new Foo(...)` / `Foo::new(...)` / object_creation_expression —
|
|
368
|
+
// produce an `instantiates` reference. Children still walked so
|
|
369
|
+
// nested calls inside the constructor args (`new Foo(bar())`) get
|
|
370
|
+
// their own `calls` refs.
|
|
371
|
+
else if (INSTANTIATION_KINDS.has(nodeType)) {
|
|
372
|
+
this.extractInstantiation(node);
|
|
373
|
+
}
|
|
374
|
+
// (Decorator handling lives inside the symbol-creating extractors
|
|
375
|
+
// — extractClass / extractFunction / extractProperty — because the
|
|
376
|
+
// decorator node sits BEFORE the symbol in the AST and the walker
|
|
377
|
+
// would otherwise see the wrong nodeStack head.)
|
|
348
378
|
// Rust: `impl Trait for Type { ... }` — creates implements edge from Type to Trait
|
|
349
379
|
else if (nodeType === 'impl_item') {
|
|
350
380
|
this.extractRustImplItem(node);
|
|
@@ -521,6 +551,10 @@ class TreeSitterExtractor {
|
|
|
521
551
|
return;
|
|
522
552
|
// Extract type annotations (parameter types and return type)
|
|
523
553
|
this.extractTypeAnnotations(node, funcNode.id);
|
|
554
|
+
// Extract decorators applied to the function (rare in JS/TS but
|
|
555
|
+
// present in Python `@decorator def f():` and Java/Kotlin
|
|
556
|
+
// annotations on free functions).
|
|
557
|
+
this.extractDecoratorsFor(node, funcNode.id);
|
|
524
558
|
// Push to stack and visit body
|
|
525
559
|
this.nodeStack.push(funcNode.id);
|
|
526
560
|
const body = this.extractor.resolveBody?.(node, this.extractor.bodyField)
|
|
@@ -549,6 +583,8 @@ class TreeSitterExtractor {
|
|
|
549
583
|
return;
|
|
550
584
|
// Extract extends/implements
|
|
551
585
|
this.extractInheritance(node, classNode.id);
|
|
586
|
+
// Extract decorators applied to the class (`@Foo class X {}`).
|
|
587
|
+
this.extractDecoratorsFor(node, classNode.id);
|
|
552
588
|
// Push to stack and visit body
|
|
553
589
|
this.nodeStack.push(classNode.id);
|
|
554
590
|
let body = this.extractor.resolveBody?.(node, this.extractor.bodyField)
|
|
@@ -631,6 +667,8 @@ class TreeSitterExtractor {
|
|
|
631
667
|
}
|
|
632
668
|
// Extract type annotations (parameter types and return type)
|
|
633
669
|
this.extractTypeAnnotations(node, methodNode.id);
|
|
670
|
+
// Extract decorators (`@Get('/list') list() {}`).
|
|
671
|
+
this.extractDecoratorsFor(node, methodNode.id);
|
|
634
672
|
// Push to stack and visit body
|
|
635
673
|
this.nodeStack.push(methodNode.id);
|
|
636
674
|
const body = this.extractor.resolveBody?.(node, this.extractor.bodyField)
|
|
@@ -792,12 +830,17 @@ class TreeSitterExtractor {
|
|
|
792
830
|
&& c.type !== 'accessors' && c.type !== 'equals_value_clause');
|
|
793
831
|
const typeText = typeNode ? (0, tree_sitter_helpers_1.getNodeText)(typeNode, this.source) : undefined;
|
|
794
832
|
const signature = typeText ? `${typeText} ${name}` : name;
|
|
795
|
-
this.createNode('property', name, node, {
|
|
833
|
+
const propNode = this.createNode('property', name, node, {
|
|
796
834
|
docstring,
|
|
797
835
|
signature,
|
|
798
836
|
visibility,
|
|
799
837
|
isStatic,
|
|
800
838
|
});
|
|
839
|
+
// `@Inject() private svc: Foo` and similar — capture the
|
|
840
|
+
// decorator->target relationship for class properties too.
|
|
841
|
+
if (propNode) {
|
|
842
|
+
this.extractDecoratorsFor(node, propNode.id);
|
|
843
|
+
}
|
|
801
844
|
}
|
|
802
845
|
/**
|
|
803
846
|
* Extract a class field declaration (e.g. Java field_declaration, C# field_declaration).
|
|
@@ -861,12 +904,16 @@ class TreeSitterExtractor {
|
|
|
861
904
|
continue;
|
|
862
905
|
const name = (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source);
|
|
863
906
|
const signature = typeText ? `${typeText} ${name}` : name;
|
|
864
|
-
this.createNode('field', name, decl, {
|
|
907
|
+
const fieldNode = this.createNode('field', name, decl, {
|
|
865
908
|
docstring,
|
|
866
909
|
signature,
|
|
867
910
|
visibility,
|
|
868
911
|
isStatic,
|
|
869
912
|
});
|
|
913
|
+
// Java/Kotlin annotations / TS field decorators sit on the
|
|
914
|
+
// outer field_declaration, not on the individual declarator.
|
|
915
|
+
if (fieldNode)
|
|
916
|
+
this.extractDecoratorsFor(node, fieldNode.id);
|
|
870
917
|
}
|
|
871
918
|
}
|
|
872
919
|
else {
|
|
@@ -1105,54 +1152,11 @@ class TreeSitterExtractor {
|
|
|
1105
1152
|
}
|
|
1106
1153
|
return false;
|
|
1107
1154
|
}
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
* export const X = [...]
|
|
1114
|
-
* export const X = "value"
|
|
1115
|
-
*
|
|
1116
|
-
* This is called for `export_statement` nodes that contain a
|
|
1117
|
-
* `lexical_declaration` with `variable_declarator` children whose
|
|
1118
|
-
* values are NOT already handled by functionTypes (arrow_function,
|
|
1119
|
-
* function_expression).
|
|
1120
|
-
*/
|
|
1121
|
-
extractExportedVariables(exportNode) {
|
|
1122
|
-
if (!this.extractor)
|
|
1123
|
-
return;
|
|
1124
|
-
// Find the lexical_declaration or variable_declaration child
|
|
1125
|
-
for (let i = 0; i < exportNode.namedChildCount; i++) {
|
|
1126
|
-
const decl = exportNode.namedChild(i);
|
|
1127
|
-
if (!decl || (decl.type !== 'lexical_declaration' && decl.type !== 'variable_declaration')) {
|
|
1128
|
-
continue;
|
|
1129
|
-
}
|
|
1130
|
-
// Iterate over each variable_declarator in the declaration
|
|
1131
|
-
for (let j = 0; j < decl.namedChildCount; j++) {
|
|
1132
|
-
const declarator = decl.namedChild(j);
|
|
1133
|
-
if (!declarator || declarator.type !== 'variable_declarator')
|
|
1134
|
-
continue;
|
|
1135
|
-
const nameNode = (0, tree_sitter_helpers_1.getChildByField)(declarator, 'name');
|
|
1136
|
-
if (!nameNode)
|
|
1137
|
-
continue;
|
|
1138
|
-
const name = (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source);
|
|
1139
|
-
// Skip if the value is a function type — those are already handled
|
|
1140
|
-
// by extractFunction via the functionTypes dispatch
|
|
1141
|
-
const value = (0, tree_sitter_helpers_1.getChildByField)(declarator, 'value');
|
|
1142
|
-
if (value) {
|
|
1143
|
-
const valueType = value.type;
|
|
1144
|
-
if (this.extractor.functionTypes.includes(valueType)) {
|
|
1145
|
-
continue; // Already handled by extractFunction
|
|
1146
|
-
}
|
|
1147
|
-
}
|
|
1148
|
-
const docstring = (0, tree_sitter_helpers_1.getPrecedingDocstring)(exportNode, this.source);
|
|
1149
|
-
this.createNode('variable', name, declarator, {
|
|
1150
|
-
docstring,
|
|
1151
|
-
isExported: true,
|
|
1152
|
-
});
|
|
1153
|
-
}
|
|
1154
|
-
}
|
|
1155
|
-
}
|
|
1155
|
+
// extractExportedVariables removed — the walker now descends into
|
|
1156
|
+
// export_statement children and the inner declaration's dedicated
|
|
1157
|
+
// extractor (extractVariable, extractFunction, extractClass, etc.)
|
|
1158
|
+
// handles the symbol with isExported=true via parent-walk in the
|
|
1159
|
+
// language extractor's isExported predicate.
|
|
1156
1160
|
/**
|
|
1157
1161
|
* Extract an import
|
|
1158
1162
|
*
|
|
@@ -1369,6 +1373,160 @@ class TreeSitterExtractor {
|
|
|
1369
1373
|
});
|
|
1370
1374
|
}
|
|
1371
1375
|
}
|
|
1376
|
+
/**
|
|
1377
|
+
* `new Foo(...)` / `Foo::new(...)` / object_creation_expression —
|
|
1378
|
+
* emit an `instantiates` reference to the class name. The resolver
|
|
1379
|
+
* then links it to the class node, producing the `instantiates`
|
|
1380
|
+
* edge that powers "what creates instances of X" queries.
|
|
1381
|
+
*
|
|
1382
|
+
* Children are still walked so nested calls inside the constructor
|
|
1383
|
+
* arguments (`new Foo(bar())`) get their own `calls` references.
|
|
1384
|
+
*/
|
|
1385
|
+
extractInstantiation(node) {
|
|
1386
|
+
if (this.nodeStack.length === 0)
|
|
1387
|
+
return;
|
|
1388
|
+
const fromId = this.nodeStack[this.nodeStack.length - 1];
|
|
1389
|
+
if (!fromId)
|
|
1390
|
+
return;
|
|
1391
|
+
// The class name is in the `constructor`/`type`/first-named-child
|
|
1392
|
+
// depending on grammar.
|
|
1393
|
+
const ctor = (0, tree_sitter_helpers_1.getChildByField)(node, 'constructor') ||
|
|
1394
|
+
(0, tree_sitter_helpers_1.getChildByField)(node, 'type') ||
|
|
1395
|
+
(0, tree_sitter_helpers_1.getChildByField)(node, 'name') ||
|
|
1396
|
+
node.namedChild(0);
|
|
1397
|
+
if (!ctor)
|
|
1398
|
+
return;
|
|
1399
|
+
let className = (0, tree_sitter_helpers_1.getNodeText)(ctor, this.source);
|
|
1400
|
+
// Strip type-argument suffix first: `new Map<K, V>()` would
|
|
1401
|
+
// otherwise produce className 'Map<K, V>' (the constructor
|
|
1402
|
+
// field is a `generic_type` node) and resolution would fail
|
|
1403
|
+
// because no class is named with the angle-bracket suffix.
|
|
1404
|
+
const ltIdx = className.indexOf('<');
|
|
1405
|
+
if (ltIdx > 0)
|
|
1406
|
+
className = className.slice(0, ltIdx);
|
|
1407
|
+
// For namespaced/qualified constructors (`new ns.Foo()`,
|
|
1408
|
+
// `new ns::Foo()`) keep the trailing identifier — that's what
|
|
1409
|
+
// matches a class node in the index.
|
|
1410
|
+
const lastDot = Math.max(className.lastIndexOf('.'), className.lastIndexOf('::'));
|
|
1411
|
+
if (lastDot >= 0)
|
|
1412
|
+
className = className.slice(lastDot + 1).replace(/^[:.]/, '');
|
|
1413
|
+
className = className.trim();
|
|
1414
|
+
if (className) {
|
|
1415
|
+
this.unresolvedReferences.push({
|
|
1416
|
+
fromNodeId: fromId,
|
|
1417
|
+
referenceName: className,
|
|
1418
|
+
referenceKind: 'instantiates',
|
|
1419
|
+
line: node.startPosition.row + 1,
|
|
1420
|
+
column: node.startPosition.column,
|
|
1421
|
+
});
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
/**
|
|
1425
|
+
* Scan `declNode` and its preceding siblings (within the parent's
|
|
1426
|
+
* named children) for decorator nodes, emitting a `decorates`
|
|
1427
|
+
* reference from `decoratedId` to each decorator's function name.
|
|
1428
|
+
*
|
|
1429
|
+
* Why preceding siblings: in TypeScript, `@Foo class Bar {}` parses
|
|
1430
|
+
* as an `export_statement` (or top-level wrapper) with the
|
|
1431
|
+
* `decorator` as a child *before* the `class_declaration` — so the
|
|
1432
|
+
* decorator isn't a child of the class itself. For methods/
|
|
1433
|
+
* properties, the decorator IS a direct child of the declaration,
|
|
1434
|
+
* so we also scan declNode.namedChildren.
|
|
1435
|
+
*
|
|
1436
|
+
* Idempotent across grammars: if neither location yields decorators
|
|
1437
|
+
* (most non-decorator-using languages), the function is a no-op.
|
|
1438
|
+
*/
|
|
1439
|
+
extractDecoratorsFor(declNode, decoratedId) {
|
|
1440
|
+
const consider = (n) => {
|
|
1441
|
+
if (!n)
|
|
1442
|
+
return;
|
|
1443
|
+
// `marker_annotation` is Java's grammar for arg-less annotations
|
|
1444
|
+
// (`@Override`, `@Deprecated`); without including it, every
|
|
1445
|
+
// such Java annotation would be silently skipped.
|
|
1446
|
+
if (n.type !== 'decorator' &&
|
|
1447
|
+
n.type !== 'annotation' &&
|
|
1448
|
+
n.type !== 'marker_annotation') {
|
|
1449
|
+
return;
|
|
1450
|
+
}
|
|
1451
|
+
// Find the leading identifier: skip the `@` punct, unwrap
|
|
1452
|
+
// a call_expression if the decorator is invoked with args.
|
|
1453
|
+
let target = null;
|
|
1454
|
+
for (let i = 0; i < n.namedChildCount; i++) {
|
|
1455
|
+
const child = n.namedChild(i);
|
|
1456
|
+
if (!child)
|
|
1457
|
+
continue;
|
|
1458
|
+
if (child.type === 'call_expression') {
|
|
1459
|
+
const fn = (0, tree_sitter_helpers_1.getChildByField)(child, 'function') ?? child.namedChild(0);
|
|
1460
|
+
if (fn)
|
|
1461
|
+
target = fn;
|
|
1462
|
+
if (target)
|
|
1463
|
+
break;
|
|
1464
|
+
}
|
|
1465
|
+
if (child.type === 'identifier' ||
|
|
1466
|
+
child.type === 'member_expression' ||
|
|
1467
|
+
child.type === 'scoped_identifier' ||
|
|
1468
|
+
child.type === 'navigation_expression') {
|
|
1469
|
+
target = child;
|
|
1470
|
+
break;
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
if (!target)
|
|
1474
|
+
return;
|
|
1475
|
+
let name = (0, tree_sitter_helpers_1.getNodeText)(target, this.source);
|
|
1476
|
+
const lastDot = Math.max(name.lastIndexOf('.'), name.lastIndexOf('::'));
|
|
1477
|
+
if (lastDot >= 0)
|
|
1478
|
+
name = name.slice(lastDot + 1).replace(/^[:.]/, '');
|
|
1479
|
+
if (!name)
|
|
1480
|
+
return;
|
|
1481
|
+
this.unresolvedReferences.push({
|
|
1482
|
+
fromNodeId: decoratedId,
|
|
1483
|
+
referenceName: name,
|
|
1484
|
+
referenceKind: 'decorates',
|
|
1485
|
+
line: n.startPosition.row + 1,
|
|
1486
|
+
column: n.startPosition.column,
|
|
1487
|
+
});
|
|
1488
|
+
};
|
|
1489
|
+
// 1. Decorators that are direct children of the declaration
|
|
1490
|
+
// (method/property style, also some grammars for class).
|
|
1491
|
+
for (let i = 0; i < declNode.namedChildCount; i++) {
|
|
1492
|
+
consider(declNode.namedChild(i));
|
|
1493
|
+
}
|
|
1494
|
+
// 2. Decorators that are PRECEDING siblings of the declaration
|
|
1495
|
+
// inside the parent's children (TypeScript class style).
|
|
1496
|
+
// Walk BACKWARDS from the declaration and stop at the first
|
|
1497
|
+
// non-decorator sibling — without that stop, decorators
|
|
1498
|
+
// belonging to an EARLIER unrelated declaration leak in
|
|
1499
|
+
// (e.g. `@A class Foo {} @B class Bar {}` would otherwise
|
|
1500
|
+
// attribute @A to Bar).
|
|
1501
|
+
//
|
|
1502
|
+
// Note on identity: tree-sitter web bindings return fresh JS
|
|
1503
|
+
// wrapper objects from `parent`/`namedChild` navigation, so
|
|
1504
|
+
// `sibling === declNode` is unreliable — `startIndex` does
|
|
1505
|
+
// the matching instead.
|
|
1506
|
+
const parent = declNode.parent;
|
|
1507
|
+
if (parent) {
|
|
1508
|
+
const declStart = declNode.startIndex;
|
|
1509
|
+
let declIdx = -1;
|
|
1510
|
+
for (let i = 0; i < parent.namedChildCount; i++) {
|
|
1511
|
+
const sibling = parent.namedChild(i);
|
|
1512
|
+
if (sibling && sibling.startIndex === declStart) {
|
|
1513
|
+
declIdx = i;
|
|
1514
|
+
break;
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
if (declIdx > 0) {
|
|
1518
|
+
for (let j = declIdx - 1; j >= 0; j--) {
|
|
1519
|
+
const sibling = parent.namedChild(j);
|
|
1520
|
+
if (!sibling)
|
|
1521
|
+
continue;
|
|
1522
|
+
if (sibling.type !== 'decorator' && sibling.type !== 'annotation' && sibling.type !== 'marker_annotation') {
|
|
1523
|
+
break; // non-decorator separator → stop consuming
|
|
1524
|
+
}
|
|
1525
|
+
consider(sibling);
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1372
1530
|
/**
|
|
1373
1531
|
* Visit function body and extract calls (and structural nodes).
|
|
1374
1532
|
*
|
|
@@ -1387,6 +1545,13 @@ class TreeSitterExtractor {
|
|
|
1387
1545
|
if (this.extractor.callTypes.includes(nodeType)) {
|
|
1388
1546
|
this.extractCall(node);
|
|
1389
1547
|
}
|
|
1548
|
+
else if (INSTANTIATION_KINDS.has(nodeType)) {
|
|
1549
|
+
// `new Foo()` inside a function body — emit an `instantiates`
|
|
1550
|
+
// reference. Without this branch the body walker only knew
|
|
1551
|
+
// about `call_expression`, so constructor invocations
|
|
1552
|
+
// produced no graph edges at all.
|
|
1553
|
+
this.extractInstantiation(node);
|
|
1554
|
+
}
|
|
1390
1555
|
else if (this.extractor.extractBareCall) {
|
|
1391
1556
|
const calleeName = this.extractor.extractBareCall(node, this.source);
|
|
1392
1557
|
if (calleeName && this.nodeStack.length > 0) {
|
|
@@ -2167,28 +2332,62 @@ class TreeSitterExtractor {
|
|
|
2167
2332
|
}
|
|
2168
2333
|
exports.TreeSitterExtractor = TreeSitterExtractor;
|
|
2169
2334
|
/**
|
|
2170
|
-
* Extract nodes and edges from source code
|
|
2335
|
+
* Extract nodes and edges from source code.
|
|
2336
|
+
*
|
|
2337
|
+
* If `frameworkNames` is provided, framework-specific extractors matching
|
|
2338
|
+
* those names and the file's language are run after the tree-sitter pass.
|
|
2339
|
+
* Their nodes/references/errors are merged into the returned result.
|
|
2171
2340
|
*/
|
|
2172
|
-
function extractFromSource(filePath, source, language) {
|
|
2341
|
+
function extractFromSource(filePath, source, language, frameworkNames) {
|
|
2173
2342
|
const detectedLanguage = language || (0, grammars_1.detectLanguage)(filePath, source);
|
|
2174
2343
|
const fileExtension = path.extname(filePath).toLowerCase();
|
|
2344
|
+
let result;
|
|
2175
2345
|
// Use custom extractor for Svelte
|
|
2176
2346
|
if (detectedLanguage === 'svelte') {
|
|
2177
2347
|
const extractor = new svelte_extractor_1.SvelteExtractor(filePath, source);
|
|
2178
|
-
|
|
2348
|
+
result = extractor.extract();
|
|
2349
|
+
}
|
|
2350
|
+
else if (detectedLanguage === 'vue') {
|
|
2351
|
+
// Use custom extractor for Vue
|
|
2352
|
+
const extractor = new vue_extractor_1.VueExtractor(filePath, source);
|
|
2353
|
+
result = extractor.extract();
|
|
2179
2354
|
}
|
|
2180
|
-
|
|
2181
|
-
|
|
2355
|
+
else if (detectedLanguage === 'liquid') {
|
|
2356
|
+
// Use custom extractor for Liquid
|
|
2182
2357
|
const extractor = new liquid_extractor_1.LiquidExtractor(filePath, source);
|
|
2183
|
-
|
|
2358
|
+
result = extractor.extract();
|
|
2184
2359
|
}
|
|
2185
|
-
|
|
2186
|
-
if (detectedLanguage === 'pascal' &&
|
|
2360
|
+
else if (detectedLanguage === 'pascal' &&
|
|
2187
2361
|
(fileExtension === '.dfm' || fileExtension === '.fmx')) {
|
|
2362
|
+
// Use custom extractor for DFM/FMX form files
|
|
2188
2363
|
const extractor = new dfm_extractor_1.DfmExtractor(filePath, source);
|
|
2189
|
-
|
|
2364
|
+
result = extractor.extract();
|
|
2365
|
+
}
|
|
2366
|
+
else {
|
|
2367
|
+
const extractor = new TreeSitterExtractor(filePath, source, detectedLanguage);
|
|
2368
|
+
result = extractor.extract();
|
|
2369
|
+
}
|
|
2370
|
+
// Framework-specific extraction (routes, middleware, etc.)
|
|
2371
|
+
if (frameworkNames && frameworkNames.length > 0) {
|
|
2372
|
+
const allResolvers = (0, frameworks_1.getAllFrameworkResolvers)();
|
|
2373
|
+
const applicable = (0, frameworks_1.getApplicableFrameworks)(allResolvers.filter((r) => frameworkNames.includes(r.name)), detectedLanguage);
|
|
2374
|
+
for (const fw of applicable) {
|
|
2375
|
+
if (!fw.extract)
|
|
2376
|
+
continue;
|
|
2377
|
+
try {
|
|
2378
|
+
const fwResult = fw.extract(filePath, source);
|
|
2379
|
+
result.nodes.push(...fwResult.nodes);
|
|
2380
|
+
result.unresolvedReferences.push(...fwResult.references);
|
|
2381
|
+
}
|
|
2382
|
+
catch (err) {
|
|
2383
|
+
result.errors.push({
|
|
2384
|
+
message: `Framework extractor '${fw.name}' failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
2385
|
+
filePath,
|
|
2386
|
+
severity: 'warning',
|
|
2387
|
+
});
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2190
2390
|
}
|
|
2191
|
-
|
|
2192
|
-
return extractor.extract();
|
|
2391
|
+
return result;
|
|
2193
2392
|
}
|
|
2194
2393
|
//# sourceMappingURL=tree-sitter.js.map
|