gitnexus 1.5.3 → 1.6.1
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 +10 -0
- package/dist/_shared/graph/types.d.ts +1 -1
- package/dist/_shared/graph/types.d.ts.map +1 -1
- package/dist/_shared/index.d.ts +1 -0
- package/dist/_shared/index.d.ts.map +1 -1
- package/dist/_shared/language-detection.d.ts.map +1 -1
- package/dist/_shared/language-detection.js +2 -0
- package/dist/_shared/language-detection.js.map +1 -1
- package/dist/_shared/languages.d.ts +1 -0
- package/dist/_shared/languages.d.ts.map +1 -1
- package/dist/_shared/languages.js +1 -0
- package/dist/_shared/languages.js.map +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
- package/dist/_shared/lbug/schema-constants.js +3 -1
- package/dist/_shared/lbug/schema-constants.js.map +1 -1
- package/dist/_shared/mro-strategy.d.ts +19 -0
- package/dist/_shared/mro-strategy.d.ts.map +1 -0
- package/dist/_shared/mro-strategy.js +2 -0
- package/dist/_shared/mro-strategy.js.map +1 -0
- package/dist/cli/ai-context.d.ts +1 -0
- package/dist/cli/ai-context.js +28 -4
- package/dist/cli/analyze.d.ts +2 -0
- package/dist/cli/analyze.js +30 -4
- package/dist/cli/group.d.ts +2 -0
- package/dist/cli/group.js +233 -0
- package/dist/cli/index.js +3 -0
- package/dist/cli/serve.js +4 -1
- package/dist/cli/setup.js +34 -3
- package/dist/config/ignore-service.js +8 -3
- package/dist/core/augmentation/engine.js +1 -1
- package/dist/core/git-staleness.d.ts +13 -0
- package/dist/core/git-staleness.js +29 -0
- package/dist/core/group/bridge-db.d.ts +82 -0
- package/dist/core/group/bridge-db.js +460 -0
- package/dist/core/group/bridge-schema.d.ts +27 -0
- package/dist/core/group/bridge-schema.js +55 -0
- package/dist/core/group/config-parser.d.ts +3 -0
- package/dist/core/group/config-parser.js +83 -0
- package/dist/core/group/contract-extractor.d.ts +7 -0
- package/dist/core/group/contract-extractor.js +1 -0
- package/dist/core/group/extractors/fs-utils.d.ts +10 -0
- package/dist/core/group/extractors/fs-utils.js +24 -0
- package/dist/core/group/extractors/grpc-extractor.d.ts +25 -0
- package/dist/core/group/extractors/grpc-extractor.js +386 -0
- package/dist/core/group/extractors/grpc-patterns/go.d.ts +2 -0
- package/dist/core/group/extractors/grpc-patterns/go.js +97 -0
- package/dist/core/group/extractors/grpc-patterns/index.d.ts +19 -0
- package/dist/core/group/extractors/grpc-patterns/index.js +46 -0
- package/dist/core/group/extractors/grpc-patterns/java.d.ts +2 -0
- package/dist/core/group/extractors/grpc-patterns/java.js +173 -0
- package/dist/core/group/extractors/grpc-patterns/node.d.ts +4 -0
- package/dist/core/group/extractors/grpc-patterns/node.js +290 -0
- package/dist/core/group/extractors/grpc-patterns/proto.d.ts +9 -0
- package/dist/core/group/extractors/grpc-patterns/proto.js +134 -0
- package/dist/core/group/extractors/grpc-patterns/python.d.ts +2 -0
- package/dist/core/group/extractors/grpc-patterns/python.js +67 -0
- package/dist/core/group/extractors/grpc-patterns/types.d.ts +50 -0
- package/dist/core/group/extractors/grpc-patterns/types.js +1 -0
- package/dist/core/group/extractors/http-patterns/go.d.ts +2 -0
- package/dist/core/group/extractors/http-patterns/go.js +215 -0
- package/dist/core/group/extractors/http-patterns/index.d.ts +17 -0
- package/dist/core/group/extractors/http-patterns/index.js +44 -0
- package/dist/core/group/extractors/http-patterns/java.d.ts +2 -0
- package/dist/core/group/extractors/http-patterns/java.js +253 -0
- package/dist/core/group/extractors/http-patterns/node.d.ts +4 -0
- package/dist/core/group/extractors/http-patterns/node.js +354 -0
- package/dist/core/group/extractors/http-patterns/php.d.ts +2 -0
- package/dist/core/group/extractors/http-patterns/php.js +70 -0
- package/dist/core/group/extractors/http-patterns/python.d.ts +2 -0
- package/dist/core/group/extractors/http-patterns/python.js +133 -0
- package/dist/core/group/extractors/http-patterns/types.d.ts +61 -0
- package/dist/core/group/extractors/http-patterns/types.js +1 -0
- package/dist/core/group/extractors/http-route-extractor.d.ts +21 -0
- package/dist/core/group/extractors/http-route-extractor.js +391 -0
- package/dist/core/group/extractors/manifest-extractor.d.ts +54 -0
- package/dist/core/group/extractors/manifest-extractor.js +235 -0
- package/dist/core/group/extractors/topic-extractor.d.ts +8 -0
- package/dist/core/group/extractors/topic-extractor.js +97 -0
- package/dist/core/group/extractors/topic-patterns/go.d.ts +2 -0
- package/dist/core/group/extractors/topic-patterns/go.js +120 -0
- package/dist/core/group/extractors/topic-patterns/index.d.ts +14 -0
- package/dist/core/group/extractors/topic-patterns/index.js +38 -0
- package/dist/core/group/extractors/topic-patterns/java.d.ts +2 -0
- package/dist/core/group/extractors/topic-patterns/java.js +80 -0
- package/dist/core/group/extractors/topic-patterns/node.d.ts +4 -0
- package/dist/core/group/extractors/topic-patterns/node.js +155 -0
- package/dist/core/group/extractors/topic-patterns/python.d.ts +2 -0
- package/dist/core/group/extractors/topic-patterns/python.js +116 -0
- package/dist/core/group/extractors/topic-patterns/types.d.ts +25 -0
- package/dist/core/group/extractors/topic-patterns/types.js +10 -0
- package/dist/core/group/extractors/tree-sitter-scanner.d.ts +113 -0
- package/dist/core/group/extractors/tree-sitter-scanner.js +94 -0
- package/dist/core/group/matching.d.ts +13 -0
- package/dist/core/group/matching.js +198 -0
- package/dist/core/group/normalization.d.ts +3 -0
- package/dist/core/group/normalization.js +115 -0
- package/dist/core/group/service-boundary-detector.d.ts +8 -0
- package/dist/core/group/service-boundary-detector.js +155 -0
- package/dist/core/group/service.d.ts +46 -0
- package/dist/core/group/service.js +160 -0
- package/dist/core/group/storage.d.ts +9 -0
- package/dist/core/group/storage.js +91 -0
- package/dist/core/group/sync.d.ts +21 -0
- package/dist/core/group/sync.js +148 -0
- package/dist/core/group/types.d.ts +130 -0
- package/dist/core/group/types.js +1 -0
- package/dist/core/ingestion/binding-accumulator.d.ts +212 -0
- package/dist/core/ingestion/binding-accumulator.js +336 -0
- package/dist/core/ingestion/call-processor.d.ts +155 -24
- package/dist/core/ingestion/call-processor.js +1129 -247
- package/dist/core/ingestion/class-extractors/generic.d.ts +2 -0
- package/dist/core/ingestion/class-extractors/generic.js +135 -0
- package/dist/core/ingestion/class-types.d.ts +34 -0
- package/dist/core/ingestion/class-types.js +1 -0
- package/dist/core/ingestion/cobol-processor.d.ts +1 -1
- package/dist/core/ingestion/entry-point-scoring.d.ts +1 -0
- package/dist/core/ingestion/entry-point-scoring.js +1 -0
- package/dist/core/ingestion/field-types.d.ts +2 -2
- package/dist/core/ingestion/filesystem-walker.js +8 -0
- package/dist/core/ingestion/framework-detection.d.ts +1 -0
- package/dist/core/ingestion/framework-detection.js +1 -0
- package/dist/core/ingestion/heritage-processor.d.ts +8 -15
- package/dist/core/ingestion/heritage-processor.js +15 -28
- package/dist/core/ingestion/import-processor.d.ts +1 -11
- package/dist/core/ingestion/import-processor.js +1 -13
- package/dist/core/ingestion/import-resolvers/utils.js +1 -0
- package/dist/core/ingestion/import-resolvers/vue.d.ts +8 -0
- package/dist/core/ingestion/import-resolvers/vue.js +9 -0
- package/dist/core/ingestion/language-config.js +1 -1
- package/dist/core/ingestion/language-provider.d.ts +14 -3
- package/dist/core/ingestion/languages/c-cpp.js +168 -1
- package/dist/core/ingestion/languages/csharp.js +20 -0
- package/dist/core/ingestion/languages/dart.js +26 -4
- package/dist/core/ingestion/languages/go.js +22 -0
- package/dist/core/ingestion/languages/index.d.ts +1 -0
- package/dist/core/ingestion/languages/index.js +2 -0
- package/dist/core/ingestion/languages/java.js +17 -0
- package/dist/core/ingestion/languages/kotlin.js +24 -1
- package/dist/core/ingestion/languages/php.js +23 -11
- package/dist/core/ingestion/languages/python.js +9 -0
- package/dist/core/ingestion/languages/ruby.js +43 -0
- package/dist/core/ingestion/languages/rust.js +38 -0
- package/dist/core/ingestion/languages/swift.js +31 -0
- package/dist/core/ingestion/languages/typescript.d.ts +1 -0
- package/dist/core/ingestion/languages/typescript.js +52 -3
- package/dist/core/ingestion/languages/vue.d.ts +13 -0
- package/dist/core/ingestion/languages/vue.js +81 -0
- package/dist/core/ingestion/markdown-processor.d.ts +1 -1
- package/dist/core/ingestion/method-extractors/configs/c-cpp.d.ts +3 -0
- package/dist/core/ingestion/method-extractors/configs/c-cpp.js +387 -0
- package/dist/core/ingestion/method-extractors/configs/csharp.js +5 -1
- package/dist/core/ingestion/method-extractors/configs/dart.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/dart.js +376 -0
- package/dist/core/ingestion/method-extractors/configs/go.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/go.js +176 -0
- package/dist/core/ingestion/method-extractors/configs/jvm.js +14 -4
- package/dist/core/ingestion/method-extractors/configs/php.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/php.js +304 -0
- package/dist/core/ingestion/method-extractors/configs/python.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/python.js +309 -0
- package/dist/core/ingestion/method-extractors/configs/ruby.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/ruby.js +286 -0
- package/dist/core/ingestion/method-extractors/configs/rust.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/rust.js +195 -0
- package/dist/core/ingestion/method-extractors/configs/swift.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/swift.js +277 -0
- package/dist/core/ingestion/method-extractors/configs/typescript-javascript.js +85 -8
- package/dist/core/ingestion/method-extractors/generic.d.ts +6 -0
- package/dist/core/ingestion/method-extractors/generic.js +84 -17
- package/dist/core/ingestion/method-types.d.ts +29 -0
- package/dist/core/ingestion/model/field-registry.d.ts +18 -0
- package/dist/core/ingestion/model/field-registry.js +22 -0
- package/dist/core/ingestion/model/heritage-map.d.ts +70 -0
- package/dist/core/ingestion/model/heritage-map.js +159 -0
- package/dist/core/ingestion/model/index.d.ts +20 -0
- package/dist/core/ingestion/model/index.js +41 -0
- package/dist/core/ingestion/model/method-registry.d.ts +62 -0
- package/dist/core/ingestion/model/method-registry.js +130 -0
- package/dist/core/ingestion/model/registration-table.d.ts +139 -0
- package/dist/core/ingestion/model/registration-table.js +224 -0
- package/dist/core/ingestion/model/resolution-context.d.ts +93 -0
- package/dist/core/ingestion/model/resolution-context.js +337 -0
- package/dist/core/ingestion/model/resolve.d.ts +56 -0
- package/dist/core/ingestion/model/resolve.js +297 -0
- package/dist/core/ingestion/model/semantic-model.d.ts +86 -0
- package/dist/core/ingestion/model/semantic-model.js +120 -0
- package/dist/core/ingestion/model/symbol-table.d.ts +222 -0
- package/dist/core/ingestion/model/symbol-table.js +206 -0
- package/dist/core/ingestion/model/type-registry.d.ts +39 -0
- package/dist/core/ingestion/model/type-registry.js +62 -0
- package/dist/core/ingestion/mro-processor.d.ts +5 -4
- package/dist/core/ingestion/mro-processor.js +311 -107
- package/dist/core/ingestion/parsing-processor.d.ts +5 -4
- package/dist/core/ingestion/parsing-processor.js +224 -87
- package/dist/core/ingestion/pipeline-phases/cobol.d.ts +16 -0
- package/dist/core/ingestion/pipeline-phases/cobol.js +45 -0
- package/dist/core/ingestion/pipeline-phases/communities.d.ts +16 -0
- package/dist/core/ingestion/pipeline-phases/communities.js +62 -0
- package/dist/core/ingestion/pipeline-phases/cross-file-impl.d.ts +17 -0
- package/dist/core/ingestion/pipeline-phases/cross-file-impl.js +156 -0
- package/dist/core/ingestion/pipeline-phases/cross-file.d.ts +37 -0
- package/dist/core/ingestion/pipeline-phases/cross-file.js +63 -0
- package/dist/core/ingestion/pipeline-phases/index.d.ts +21 -0
- package/dist/core/ingestion/pipeline-phases/index.js +22 -0
- package/dist/core/ingestion/pipeline-phases/markdown.d.ts +17 -0
- package/dist/core/ingestion/pipeline-phases/markdown.js +33 -0
- package/dist/core/ingestion/pipeline-phases/mro.d.ts +18 -0
- package/dist/core/ingestion/pipeline-phases/mro.js +36 -0
- package/dist/core/ingestion/pipeline-phases/orm-extraction.d.ts +22 -0
- package/dist/core/ingestion/pipeline-phases/orm-extraction.js +92 -0
- package/dist/core/ingestion/pipeline-phases/orm.d.ts +15 -0
- package/dist/core/ingestion/pipeline-phases/orm.js +74 -0
- package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +47 -0
- package/dist/core/ingestion/pipeline-phases/parse-impl.js +437 -0
- package/dist/core/ingestion/pipeline-phases/parse.d.ts +49 -0
- package/dist/core/ingestion/pipeline-phases/parse.js +33 -0
- package/dist/core/ingestion/pipeline-phases/processes.d.ts +16 -0
- package/dist/core/ingestion/pipeline-phases/processes.js +143 -0
- package/dist/core/ingestion/pipeline-phases/routes.d.ts +21 -0
- package/dist/core/ingestion/pipeline-phases/routes.js +243 -0
- package/dist/core/ingestion/pipeline-phases/runner.d.ts +22 -0
- package/dist/core/ingestion/pipeline-phases/runner.js +203 -0
- package/dist/core/ingestion/pipeline-phases/scan.d.ts +21 -0
- package/dist/core/ingestion/pipeline-phases/scan.js +46 -0
- package/dist/core/ingestion/pipeline-phases/structure.d.ts +27 -0
- package/dist/core/ingestion/pipeline-phases/structure.js +35 -0
- package/dist/core/ingestion/pipeline-phases/tools.d.ts +20 -0
- package/dist/core/ingestion/pipeline-phases/tools.js +79 -0
- package/dist/core/ingestion/pipeline-phases/types.d.ts +79 -0
- package/dist/core/ingestion/pipeline-phases/types.js +37 -0
- package/dist/core/ingestion/pipeline-phases/wildcard-synthesis.d.ts +35 -0
- package/dist/core/ingestion/pipeline-phases/wildcard-synthesis.js +174 -0
- package/dist/core/ingestion/pipeline.d.ts +18 -10
- package/dist/core/ingestion/pipeline.js +66 -1410
- package/dist/core/ingestion/process-processor.js +1 -1
- package/dist/core/ingestion/tree-sitter-queries.d.ts +5 -5
- package/dist/core/ingestion/tree-sitter-queries.js +90 -0
- package/dist/core/ingestion/type-env.d.ts +15 -2
- package/dist/core/ingestion/type-env.js +163 -102
- package/dist/core/ingestion/type-extractors/csharp.js +17 -0
- package/dist/core/ingestion/type-extractors/jvm.js +11 -0
- package/dist/core/ingestion/type-extractors/php.js +0 -55
- package/dist/core/ingestion/type-extractors/ruby.js +0 -32
- package/dist/core/ingestion/type-extractors/swift.js +13 -0
- package/dist/core/ingestion/type-extractors/types.d.ts +8 -8
- package/dist/core/ingestion/type-extractors/typescript.js +66 -69
- package/dist/core/ingestion/utils/ast-helpers.d.ts +32 -44
- package/dist/core/ingestion/utils/ast-helpers.js +157 -573
- package/dist/core/ingestion/utils/env.d.ts +10 -0
- package/dist/core/ingestion/utils/env.js +10 -0
- package/dist/core/ingestion/utils/graph-sort.d.ts +58 -0
- package/dist/core/ingestion/utils/graph-sort.js +100 -0
- package/dist/core/ingestion/utils/method-props.d.ts +32 -0
- package/dist/core/ingestion/utils/method-props.js +147 -0
- package/dist/core/ingestion/vue-sfc-extractor.d.ts +44 -0
- package/dist/core/ingestion/vue-sfc-extractor.js +94 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +31 -19
- package/dist/core/ingestion/workers/parse-worker.js +469 -200
- package/dist/core/lbug/lbug-adapter.d.ts +6 -0
- package/dist/core/lbug/lbug-adapter.js +134 -27
- package/dist/core/lbug/pool-adapter.d.ts +76 -0
- package/dist/core/lbug/pool-adapter.js +522 -0
- package/dist/core/run-analyze.d.ts +2 -0
- package/dist/core/run-analyze.js +1 -1
- package/dist/core/search/bm25-index.js +1 -1
- package/dist/core/tree-sitter/parser-loader.js +1 -0
- package/dist/core/wiki/graph-queries.js +1 -1
- package/dist/mcp/core/embedder.js +6 -5
- package/dist/mcp/core/lbug-adapter.d.ts +3 -63
- package/dist/mcp/core/lbug-adapter.js +3 -484
- package/dist/mcp/local/local-backend.d.ts +31 -2
- package/dist/mcp/local/local-backend.js +255 -46
- package/dist/mcp/resources.js +5 -4
- package/dist/mcp/staleness.d.ts +3 -13
- package/dist/mcp/staleness.js +2 -31
- package/dist/mcp/tools.js +80 -4
- package/dist/server/analyze-job.d.ts +2 -0
- package/dist/server/analyze-job.js +4 -0
- package/dist/server/api.d.ts +20 -1
- package/dist/server/api.js +306 -71
- package/dist/server/git-clone.d.ts +2 -1
- package/dist/server/git-clone.js +98 -5
- package/dist/storage/git.d.ts +13 -0
- package/dist/storage/git.js +25 -0
- package/dist/storage/repo-manager.js +1 -1
- package/package.json +9 -3
- package/scripts/patch-tree-sitter-swift.cjs +78 -0
- package/vendor/tree-sitter-proto/binding.gyp +30 -0
- package/vendor/tree-sitter-proto/bindings/node/binding.cc +20 -0
- package/vendor/tree-sitter-proto/bindings/node/index.d.ts +28 -0
- package/vendor/tree-sitter-proto/bindings/node/index.js +7 -0
- package/vendor/tree-sitter-proto/package.json +18 -0
- package/vendor/tree-sitter-proto/src/node-types.json +1145 -0
- package/vendor/tree-sitter-proto/src/parser.c +10149 -0
- package/vendor/tree-sitter-proto/src/tree_sitter/alloc.h +54 -0
- package/vendor/tree-sitter-proto/src/tree_sitter/array.h +291 -0
- package/vendor/tree-sitter-proto/src/tree_sitter/parser.h +266 -0
- package/dist/core/ingestion/named-binding-processor.d.ts +0 -18
- package/dist/core/ingestion/named-binding-processor.js +0 -42
- package/dist/core/ingestion/resolution-context.d.ts +0 -58
- package/dist/core/ingestion/resolution-context.js +0 -135
- package/dist/core/ingestion/symbol-table.d.ts +0 -79
- package/dist/core/ingestion/symbol-table.js +0 -115
|
@@ -35,14 +35,15 @@ try {
|
|
|
35
35
|
}
|
|
36
36
|
catch { }
|
|
37
37
|
import { getLanguageFromFilename } from '../../../_shared/index.js';
|
|
38
|
-
import { FUNCTION_NODE_TYPES,
|
|
38
|
+
import { FUNCTION_NODE_TYPES, getDefinitionNodeFromCaptures, findEnclosingClassInfo, getLabelFromCaptures, findDescendant, extractStringContent, genericFuncName, inferFunctionLabel, CLASS_CONTAINER_TYPES, } from '../utils/ast-helpers.js';
|
|
39
39
|
import { countCallArguments, inferCallForm, extractReceiverName, extractReceiverNode, extractMixedChain, extractCallArgTypes, } from '../utils/call-analysis.js';
|
|
40
40
|
import { extractParsedCallSite } from '../call-sites/extract-language-call-site.js';
|
|
41
41
|
import { buildTypeEnv } from '../type-env.js';
|
|
42
42
|
import { detectFrameworkFromAST } from '../framework-detection.js';
|
|
43
43
|
import { generateId } from '../../../lib/utils.js';
|
|
44
44
|
import { preprocessImportPath } from '../import-processor.js';
|
|
45
|
-
import {
|
|
45
|
+
import { extractVueScript, extractTemplateComponents, isVueSetupTopLevel, } from '../vue-sfc-extractor.js';
|
|
46
|
+
import { buildMethodProps, arityForIdFromInfo, typeTagForId, constTagForId, buildCollisionGroups, } from '../utils/method-props.js';
|
|
46
47
|
// ============================================================================
|
|
47
48
|
// Worker-local parser + language map
|
|
48
49
|
// ============================================================================
|
|
@@ -61,6 +62,7 @@ const languageMap = {
|
|
|
61
62
|
...(Kotlin ? { [SupportedLanguages.Kotlin]: Kotlin } : {}),
|
|
62
63
|
[SupportedLanguages.PHP]: PHP.php_only,
|
|
63
64
|
[SupportedLanguages.Ruby]: Ruby,
|
|
65
|
+
[SupportedLanguages.Vue]: TypeScript.typescript,
|
|
64
66
|
...(Dart ? { [SupportedLanguages.Dart]: Dart } : {}),
|
|
65
67
|
...(Swift ? { [SupportedLanguages.Swift]: Swift } : {}),
|
|
66
68
|
};
|
|
@@ -114,21 +116,100 @@ function findEnclosingClassNode(node) {
|
|
|
114
116
|
let current = node.parent;
|
|
115
117
|
while (current) {
|
|
116
118
|
if (CLASS_CONTAINER_TYPES.has(current.type)) {
|
|
119
|
+
// Return singleton_class directly so the method extractor sees it as
|
|
120
|
+
// the owner node and correctly marks methods as static. Name resolution
|
|
121
|
+
// for qualified names is handled separately by findEnclosingClassInfo.
|
|
117
122
|
return current;
|
|
118
123
|
}
|
|
119
124
|
current = current.parent;
|
|
120
125
|
}
|
|
121
126
|
return null;
|
|
122
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* For C++ out-of-class method definitions (e.g. `void Foo::bar() {}`), extract the
|
|
130
|
+
* class name from the qualified_identifier scope and find the class declaration in the
|
|
131
|
+
* file's AST. Returns the class SyntaxNode or null if not found.
|
|
132
|
+
*
|
|
133
|
+
* Handles pointer/reference return types where function_declarator is nested inside
|
|
134
|
+
* pointer_declarator or reference_declarator.
|
|
135
|
+
*/
|
|
136
|
+
function findClassNodeByQualifiedName(node) {
|
|
137
|
+
const declarator = node.childForFieldName('declarator');
|
|
138
|
+
if (!declarator)
|
|
139
|
+
return null;
|
|
140
|
+
// Find the function_declarator, recursively unwrapping pointer_declarator /
|
|
141
|
+
// reference_declarator chains (e.g. int** Foo::bar() has
|
|
142
|
+
// pointer_declarator → pointer_declarator → function_declarator).
|
|
143
|
+
let funcDecl = null;
|
|
144
|
+
if (declarator.type === 'function_declarator') {
|
|
145
|
+
funcDecl = declarator;
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
let current = declarator;
|
|
149
|
+
while (current && !funcDecl) {
|
|
150
|
+
for (let i = 0; i < current.namedChildCount; i++) {
|
|
151
|
+
const child = current.namedChild(i);
|
|
152
|
+
if (child?.type === 'function_declarator') {
|
|
153
|
+
funcDecl = child;
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (!funcDecl) {
|
|
158
|
+
const next = current.namedChildren.find((c) => c.type === 'pointer_declarator' || c.type === 'reference_declarator');
|
|
159
|
+
current = next ?? null;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (!funcDecl)
|
|
164
|
+
return null;
|
|
165
|
+
// Check if the inner declarator is a qualified_identifier (Foo::bar)
|
|
166
|
+
const innerDecl = funcDecl.childForFieldName('declarator');
|
|
167
|
+
if (!innerDecl || innerDecl.type !== 'qualified_identifier')
|
|
168
|
+
return null;
|
|
169
|
+
const scope = innerDecl.childForFieldName('scope');
|
|
170
|
+
if (!scope)
|
|
171
|
+
return null;
|
|
172
|
+
const className = scope.text;
|
|
173
|
+
// Search the file for a matching class/struct specifier, including inside
|
|
174
|
+
// namespace_definition blocks (the majority of production C++ uses namespaces).
|
|
175
|
+
const root = node.tree.rootNode;
|
|
176
|
+
const classTypes = new Set(['class_specifier', 'struct_specifier']);
|
|
177
|
+
const searchIn = (parent) => {
|
|
178
|
+
for (let i = 0; i < parent.namedChildCount; i++) {
|
|
179
|
+
const child = parent.namedChild(i);
|
|
180
|
+
if (!child)
|
|
181
|
+
continue;
|
|
182
|
+
if (classTypes.has(child.type)) {
|
|
183
|
+
const nameNode = child.childForFieldName('name');
|
|
184
|
+
if (nameNode?.text === className)
|
|
185
|
+
return child;
|
|
186
|
+
}
|
|
187
|
+
// Recurse into namespace blocks
|
|
188
|
+
if (child.type === 'namespace_definition') {
|
|
189
|
+
const found = searchIn(child);
|
|
190
|
+
if (found)
|
|
191
|
+
return found;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return null;
|
|
195
|
+
};
|
|
196
|
+
return searchIn(root);
|
|
197
|
+
}
|
|
123
198
|
/**
|
|
124
199
|
* Minimal no-op SymbolTable stub for FieldExtractorContext in the worker.
|
|
125
|
-
* Field extraction only uses symbolTable.lookupExactAll for optional type
|
|
126
|
-
* returning [] causes the extractor to use the raw type
|
|
200
|
+
* Field extraction only uses symbolTable.lookupExactAll for optional type
|
|
201
|
+
* resolution — returning [] causes the extractor to use the raw type
|
|
202
|
+
* string, which is fine for us. Every other method is a no-op so the
|
|
203
|
+
* stub remains safe if a future FieldExtractor consults it through the
|
|
204
|
+
* full {@link SymbolTableReader} surface.
|
|
127
205
|
*/
|
|
128
206
|
const NOOP_SYMBOL_TABLE = {
|
|
129
|
-
lookupExactAll: () => [],
|
|
130
207
|
lookupExact: () => undefined,
|
|
131
208
|
lookupExactFull: () => undefined,
|
|
209
|
+
lookupExactAll: () => [],
|
|
210
|
+
lookupCallableByName: () => [],
|
|
211
|
+
getFiles: () => [][Symbol.iterator](),
|
|
212
|
+
getStats: () => ({ fileCount: 0 }),
|
|
132
213
|
};
|
|
133
214
|
/**
|
|
134
215
|
* Get (or extract and cache) field info for a class node.
|
|
@@ -180,6 +261,9 @@ function getMethodInfo(classNode, provider, context) {
|
|
|
180
261
|
methodInfoCache.set(cacheKey, cached);
|
|
181
262
|
return cached;
|
|
182
263
|
}
|
|
264
|
+
// ============================================================================
|
|
265
|
+
// Enclosing function detection (for call extraction) — cached
|
|
266
|
+
// ============================================================================
|
|
183
267
|
/** Walk up AST to find enclosing function, return its generateId or null for top-level.
|
|
184
268
|
* Applies provider.labelOverride so the label matches the definition phase (single source of truth). */
|
|
185
269
|
const findEnclosingFunctionId = (node, filePath, provider) => {
|
|
@@ -189,7 +273,9 @@ const findEnclosingFunctionId = (node, filePath, provider) => {
|
|
|
189
273
|
let current = node.parent;
|
|
190
274
|
while (current) {
|
|
191
275
|
if (FUNCTION_NODE_TYPES.has(current.type)) {
|
|
192
|
-
const
|
|
276
|
+
const efnResult = provider.methodExtractor?.extractFunctionName?.(current);
|
|
277
|
+
const funcName = efnResult?.funcName ?? genericFuncName(current);
|
|
278
|
+
const label = efnResult?.label ?? inferFunctionLabel(current.type);
|
|
193
279
|
if (funcName) {
|
|
194
280
|
// Apply labelOverride so label matches definition phase (e.g., Kotlin Function→Method).
|
|
195
281
|
// null means "skip as definition" — keep original label for scope identification.
|
|
@@ -199,7 +285,39 @@ const findEnclosingFunctionId = (node, filePath, provider) => {
|
|
|
199
285
|
if (override !== null)
|
|
200
286
|
finalLabel = override;
|
|
201
287
|
}
|
|
202
|
-
|
|
288
|
+
// Qualify with enclosing class to match definition-phase node IDs
|
|
289
|
+
const classInfo = cachedFindEnclosingClassInfo(current, filePath, provider.resolveEnclosingOwner);
|
|
290
|
+
const qualifiedName = classInfo ? `${classInfo.className}.${funcName}` : funcName;
|
|
291
|
+
// Include #<arity> suffix to match definition-phase Method/Constructor IDs.
|
|
292
|
+
// Use the same MethodExtractor (getMethodInfo) as the definition phase.
|
|
293
|
+
// When same-arity collisions exist, also append ~type1,type2.
|
|
294
|
+
let arity;
|
|
295
|
+
let encTypeTag = '';
|
|
296
|
+
if (finalLabel === 'Method' || finalLabel === 'Constructor') {
|
|
297
|
+
const encLang = getLanguageFromFilename(filePath);
|
|
298
|
+
const classNode = findEnclosingClassNode(current) ?? findClassNodeByQualifiedName(current);
|
|
299
|
+
if (classNode && encLang) {
|
|
300
|
+
const methodMap = getMethodInfo(classNode, provider, {
|
|
301
|
+
filePath,
|
|
302
|
+
language: encLang,
|
|
303
|
+
});
|
|
304
|
+
const defLine = current.startPosition.row + 1;
|
|
305
|
+
const info = methodMap?.get(`${funcName}:${defLine}`);
|
|
306
|
+
if (info) {
|
|
307
|
+
arity = info.parameters.some((p) => p.isVariadic)
|
|
308
|
+
? undefined
|
|
309
|
+
: info.parameters.length;
|
|
310
|
+
if (methodMap && arity !== undefined) {
|
|
311
|
+
const g = buildCollisionGroups(methodMap);
|
|
312
|
+
encTypeTag =
|
|
313
|
+
typeTagForId(methodMap, funcName, arity, info, encLang, g) +
|
|
314
|
+
constTagForId(methodMap, funcName, arity, info, g);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
const arityTag = arity !== undefined ? `#${arity}${encTypeTag}` : '';
|
|
320
|
+
const result = generateId(finalLabel, `${filePath}:${qualifiedName}${arityTag}`);
|
|
203
321
|
functionIdCache.set(node, result);
|
|
204
322
|
return result;
|
|
205
323
|
}
|
|
@@ -215,7 +333,41 @@ const findEnclosingFunctionId = (node, filePath, provider) => {
|
|
|
215
333
|
if (override !== null)
|
|
216
334
|
finalLabel = override;
|
|
217
335
|
}
|
|
218
|
-
|
|
336
|
+
// Qualify custom result with enclosing class
|
|
337
|
+
const classInfo = cachedFindEnclosingClassInfo(current.previousSibling ?? current, filePath, provider.resolveEnclosingOwner);
|
|
338
|
+
const qualifiedName = classInfo
|
|
339
|
+
? `${classInfo.className}.${customResult.funcName}`
|
|
340
|
+
: customResult.funcName;
|
|
341
|
+
// Include #<arity> suffix to match definition-phase Method/Constructor IDs.
|
|
342
|
+
// When same-arity collisions exist, also append ~type1,type2.
|
|
343
|
+
const sigNode = current.previousSibling ?? current;
|
|
344
|
+
let arity2;
|
|
345
|
+
let encTypeTag2 = '';
|
|
346
|
+
if (finalLabel === 'Method' || finalLabel === 'Constructor') {
|
|
347
|
+
const encLang2 = getLanguageFromFilename(filePath);
|
|
348
|
+
const classNode2 = findEnclosingClassNode(sigNode) ?? findClassNodeByQualifiedName(sigNode);
|
|
349
|
+
if (classNode2 && encLang2) {
|
|
350
|
+
const methodMap2 = getMethodInfo(classNode2, provider, {
|
|
351
|
+
filePath,
|
|
352
|
+
language: encLang2,
|
|
353
|
+
});
|
|
354
|
+
const defLine2 = sigNode.startPosition.row + 1;
|
|
355
|
+
const info2 = methodMap2?.get(`${customResult.funcName}:${defLine2}`);
|
|
356
|
+
if (info2) {
|
|
357
|
+
arity2 = info2.parameters.some((p) => p.isVariadic)
|
|
358
|
+
? undefined
|
|
359
|
+
: info2.parameters.length;
|
|
360
|
+
if (methodMap2 && arity2 !== undefined) {
|
|
361
|
+
const g2 = buildCollisionGroups(methodMap2);
|
|
362
|
+
encTypeTag2 =
|
|
363
|
+
typeTagForId(methodMap2, customResult.funcName, arity2, info2, encLang2, g2) +
|
|
364
|
+
constTagForId(methodMap2, customResult.funcName, arity2, info2, g2);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
const arityTag2 = arity2 !== undefined ? `#${arity2}${encTypeTag2}` : '';
|
|
370
|
+
const result = generateId(finalLabel, `${filePath}:${qualifiedName}${arityTag2}`);
|
|
219
371
|
functionIdCache.set(node, result);
|
|
220
372
|
return result;
|
|
221
373
|
}
|
|
@@ -225,12 +377,12 @@ const findEnclosingFunctionId = (node, filePath, provider) => {
|
|
|
225
377
|
functionIdCache.set(node, null);
|
|
226
378
|
return null;
|
|
227
379
|
};
|
|
228
|
-
/** Cached wrapper for
|
|
229
|
-
const
|
|
380
|
+
/** Cached wrapper for findEnclosingClassInfo — avoids repeated parent walks. */
|
|
381
|
+
const cachedFindEnclosingClassInfo = (node, filePath, resolveEnclosingOwner) => {
|
|
230
382
|
const cached = classIdCache.get(node);
|
|
231
383
|
if (cached !== undefined)
|
|
232
384
|
return cached;
|
|
233
|
-
const result =
|
|
385
|
+
const result = findEnclosingClassInfo(node, filePath, resolveEnclosingOwner);
|
|
234
386
|
classIdCache.set(node, result);
|
|
235
387
|
return result;
|
|
236
388
|
};
|
|
@@ -263,7 +415,7 @@ const processBatch = (files, onProgress) => {
|
|
|
263
415
|
toolDefs: [],
|
|
264
416
|
ormQueries: [],
|
|
265
417
|
constructorBindings: [],
|
|
266
|
-
|
|
418
|
+
fileScopeBindings: [],
|
|
267
419
|
skippedLanguages: {},
|
|
268
420
|
fileCount: 0,
|
|
269
421
|
};
|
|
@@ -311,7 +463,10 @@ const processBatch = (files, onProgress) => {
|
|
|
311
463
|
}
|
|
312
464
|
}
|
|
313
465
|
else {
|
|
314
|
-
|
|
466
|
+
// Manual loop (not spread) — `push(...arr)` blows the stack on very
|
|
467
|
+
// large arrays when langFiles has tens of thousands of entries.
|
|
468
|
+
for (const f of langFiles)
|
|
469
|
+
regularFiles.push(f);
|
|
315
470
|
}
|
|
316
471
|
// Process regular files for this language
|
|
317
472
|
if (regularFiles.length > 0) {
|
|
@@ -375,6 +530,27 @@ const EXPRESS_ROUTE_METHODS = new Set([
|
|
|
375
530
|
// the express_route handler as route definitions, not consumers. The fetch() global
|
|
376
531
|
// function is captured separately by the route.fetch query.
|
|
377
532
|
const HTTP_CLIENT_ONLY_METHODS = new Set(['head', 'options', 'request', 'ajax']);
|
|
533
|
+
// Known HTTP client receivers u2014 skip these, they're API consumers not routes
|
|
534
|
+
const HTTP_CLIENT_RECEIVERS = new Set([
|
|
535
|
+
'axios',
|
|
536
|
+
'request',
|
|
537
|
+
'fetch',
|
|
538
|
+
'http',
|
|
539
|
+
'https',
|
|
540
|
+
'got',
|
|
541
|
+
'ky',
|
|
542
|
+
'superagent',
|
|
543
|
+
'needle',
|
|
544
|
+
'undici',
|
|
545
|
+
'apiclient',
|
|
546
|
+
'client',
|
|
547
|
+
'httpclient',
|
|
548
|
+
'api',
|
|
549
|
+
'$http',
|
|
550
|
+
'session',
|
|
551
|
+
'httpservice',
|
|
552
|
+
'conn',
|
|
553
|
+
]);
|
|
378
554
|
// Decorator names that indicate HTTP route handlers (NestJS, Flask, FastAPI, Spring)
|
|
379
555
|
const ROUTE_DECORATOR_NAMES = new Set([
|
|
380
556
|
'Get',
|
|
@@ -684,24 +860,28 @@ function extractLaravelRoutes(tree, filePath) {
|
|
|
684
860
|
});
|
|
685
861
|
}
|
|
686
862
|
}
|
|
687
|
-
|
|
863
|
+
const walkStack = [{ node: tree.rootNode, groupSnapshot: [] }];
|
|
864
|
+
while (walkStack.length > 0) {
|
|
865
|
+
const { node, groupSnapshot } = walkStack.pop();
|
|
688
866
|
// Case 1: Simple Route::get(...), Route::post(...), etc.
|
|
689
867
|
if (isRouteStaticCall(node)) {
|
|
690
868
|
const method = getCallMethodName(node);
|
|
691
869
|
if (method && (ROUTE_HTTP_METHODS.has(method) || ROUTE_RESOURCE_METHODS.has(method))) {
|
|
692
|
-
emitRoute(method, getArguments(node), node.startPosition.row,
|
|
693
|
-
|
|
870
|
+
emitRoute(method, getArguments(node), node.startPosition.row, groupSnapshot, []);
|
|
871
|
+
continue;
|
|
694
872
|
}
|
|
695
873
|
if (method === 'group') {
|
|
696
874
|
const argsNode = getArguments(node);
|
|
697
875
|
const groupCtx = parseArrayGroupArgs(argsNode);
|
|
698
876
|
const body = findClosureBody(argsNode);
|
|
699
877
|
if (body) {
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
878
|
+
const childSnapshot = [...groupSnapshot, groupCtx];
|
|
879
|
+
const children = body.children ?? [];
|
|
880
|
+
for (let i = children.length - 1; i >= 0; i--) {
|
|
881
|
+
walkStack.push({ node: children[i], groupSnapshot: childSnapshot });
|
|
882
|
+
}
|
|
703
883
|
}
|
|
704
|
-
|
|
884
|
+
continue;
|
|
705
885
|
}
|
|
706
886
|
}
|
|
707
887
|
// Case 2: Fluent chain — Route::middleware(...)->group(...) or Route::middleware(...)->get(...)
|
|
@@ -719,27 +899,26 @@ function extractLaravelRoutes(tree, filePath) {
|
|
|
719
899
|
}
|
|
720
900
|
const body = findClosureBody(chain.terminalArgs);
|
|
721
901
|
if (body) {
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
902
|
+
const childSnapshot = [...groupSnapshot, groupCtx];
|
|
903
|
+
const children = body.children ?? [];
|
|
904
|
+
for (let i = children.length - 1; i >= 0; i--) {
|
|
905
|
+
walkStack.push({ node: children[i], groupSnapshot: childSnapshot });
|
|
906
|
+
}
|
|
725
907
|
}
|
|
726
|
-
|
|
908
|
+
continue;
|
|
727
909
|
}
|
|
728
910
|
if (ROUTE_HTTP_METHODS.has(chain.terminalMethod) ||
|
|
729
911
|
ROUTE_RESOURCE_METHODS.has(chain.terminalMethod)) {
|
|
730
|
-
emitRoute(chain.terminalMethod, chain.terminalArgs, node.startPosition.row,
|
|
731
|
-
|
|
912
|
+
emitRoute(chain.terminalMethod, chain.terminalArgs, node.startPosition.row, groupSnapshot, chain.attributes);
|
|
913
|
+
continue;
|
|
732
914
|
}
|
|
733
915
|
}
|
|
734
|
-
// Default:
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
for (const child of node.children ?? []) {
|
|
739
|
-
walk(child, groupStack);
|
|
916
|
+
// Default: push children in reverse so leftmost is processed first
|
|
917
|
+
const children = node.children ?? [];
|
|
918
|
+
for (let i = children.length - 1; i >= 0; i--) {
|
|
919
|
+
walkStack.push({ node: children[i], groupSnapshot });
|
|
740
920
|
}
|
|
741
921
|
}
|
|
742
|
-
walk(tree.rootNode, []);
|
|
743
922
|
return routes;
|
|
744
923
|
}
|
|
745
924
|
// ============================================================================
|
|
@@ -806,11 +985,23 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
806
985
|
// Skip files larger than the max tree-sitter buffer (32 MB)
|
|
807
986
|
if (file.content.length > TREE_SITTER_MAX_BUFFER)
|
|
808
987
|
continue;
|
|
988
|
+
// Vue SFC preprocessing: extract <script> block content
|
|
989
|
+
let parseContent = file.content;
|
|
990
|
+
let lineOffset = 0;
|
|
991
|
+
let isVueSetup = false;
|
|
992
|
+
if (language === SupportedLanguages.Vue) {
|
|
993
|
+
const extracted = extractVueScript(file.content);
|
|
994
|
+
if (!extracted)
|
|
995
|
+
continue; // skip .vue files with no script block
|
|
996
|
+
parseContent = extracted.scriptContent;
|
|
997
|
+
lineOffset = extracted.lineOffset;
|
|
998
|
+
isVueSetup = extracted.isSetup;
|
|
999
|
+
}
|
|
809
1000
|
clearCaches(); // Reset memoization before each new file
|
|
810
1001
|
let tree;
|
|
811
1002
|
try {
|
|
812
|
-
tree = parser.parse(
|
|
813
|
-
bufferSize: getTreeSitterBufferSize(
|
|
1003
|
+
tree = parser.parse(parseContent, undefined, {
|
|
1004
|
+
bufferSize: getTreeSitterBufferSize(parseContent.length),
|
|
814
1005
|
});
|
|
815
1006
|
}
|
|
816
1007
|
catch (err) {
|
|
@@ -861,6 +1052,7 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
861
1052
|
const typeEnv = buildTypeEnv(tree, language, {
|
|
862
1053
|
parentMap,
|
|
863
1054
|
enclosingFunctionFinder: provider?.enclosingFunctionFinder,
|
|
1055
|
+
extractFunctionName: provider?.methodExtractor?.extractFunctionName,
|
|
864
1056
|
});
|
|
865
1057
|
const callRouter = provider.callRouter;
|
|
866
1058
|
if (typeEnv.constructorBindings.length > 0) {
|
|
@@ -869,15 +1061,23 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
869
1061
|
bindings: [...typeEnv.constructorBindings],
|
|
870
1062
|
});
|
|
871
1063
|
}
|
|
872
|
-
//
|
|
873
|
-
//
|
|
874
|
-
//
|
|
1064
|
+
// Serialize file-scope bindings for BindingAccumulator. These feed the
|
|
1065
|
+
// ExportedTypeMap enrichment loop in pipeline.ts — the only current
|
|
1066
|
+
// consumer of worker-path binding data.
|
|
1067
|
+
//
|
|
1068
|
+
// Historical note: we previously serialized all scopes
|
|
1069
|
+
// (`typeEnv.allScopes()`), which pushed ~4.9 MB of function-scope
|
|
1070
|
+
// bindings across the IPC boundary on every worker batch with zero
|
|
1071
|
+
// downstream readers. Narrowing to `fileScope()` recovers that cost.
|
|
1072
|
+
// See the `FileScopeBindings` JSDoc above for the Phase 9 reversion
|
|
1073
|
+
// path when a function-scope consumer lands.
|
|
875
1074
|
const fileScope = typeEnv.fileScope();
|
|
876
1075
|
if (fileScope.size > 0) {
|
|
877
|
-
const
|
|
878
|
-
for (const [
|
|
879
|
-
|
|
880
|
-
|
|
1076
|
+
const scopeBindings = [];
|
|
1077
|
+
for (const [varName, typeName] of fileScope) {
|
|
1078
|
+
scopeBindings.push([varName, typeName]);
|
|
1079
|
+
}
|
|
1080
|
+
result.fileScopeBindings.push({ filePath: file.path, bindings: scopeBindings });
|
|
881
1081
|
}
|
|
882
1082
|
// Per-file map: decorator end-line → decorator info, for associating with definitions
|
|
883
1083
|
const fileDecorators = new Map();
|
|
@@ -946,7 +1146,7 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
946
1146
|
routePath,
|
|
947
1147
|
httpMethod,
|
|
948
1148
|
decoratorName,
|
|
949
|
-
lineNumber: decoratorNode.startPosition.row,
|
|
1149
|
+
lineNumber: decoratorNode.startPosition.row + lineOffset,
|
|
950
1150
|
});
|
|
951
1151
|
}
|
|
952
1152
|
// MCP/RPC tool detection: @mcp.tool(), @app.tool(), @server.tool()
|
|
@@ -967,7 +1167,7 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
967
1167
|
result.fetchCalls.push({
|
|
968
1168
|
filePath: file.path,
|
|
969
1169
|
fetchURL: urlNode.text,
|
|
970
|
-
lineNumber: captureMap['route.fetch'].startPosition.row,
|
|
1170
|
+
lineNumber: captureMap['route.fetch'].startPosition.row + lineOffset,
|
|
971
1171
|
});
|
|
972
1172
|
}
|
|
973
1173
|
continue;
|
|
@@ -982,7 +1182,7 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
982
1182
|
result.fetchCalls.push({
|
|
983
1183
|
filePath: file.path,
|
|
984
1184
|
fetchURL: url,
|
|
985
|
-
lineNumber: captureMap['http_client'].startPosition.row,
|
|
1185
|
+
lineNumber: captureMap['http_client'].startPosition.row + lineOffset,
|
|
986
1186
|
});
|
|
987
1187
|
}
|
|
988
1188
|
continue;
|
|
@@ -994,6 +1194,45 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
994
1194
|
const method = captureMap['express_route.method'].text;
|
|
995
1195
|
const routePath = captureMap['express_route.path'].text;
|
|
996
1196
|
if (EXPRESS_ROUTE_METHODS.has(method) && routePath.startsWith('/')) {
|
|
1197
|
+
// Extract the receiver (the object the method is called on) to filter out
|
|
1198
|
+
// HTTP client calls like axios.get('/api/users') that match the same pattern
|
|
1199
|
+
// as Express route registrations.
|
|
1200
|
+
const callNode = captureMap['express_route'];
|
|
1201
|
+
const funcNode = callNode.childForFieldName?.('function') ?? callNode.children?.[0];
|
|
1202
|
+
// Walk through nested member_expressions and call_expressions to
|
|
1203
|
+
// reach the innermost receiver identifier. Handles chains like:
|
|
1204
|
+
// this.httpService.get('/path') -> member chain -> 'httpservice'
|
|
1205
|
+
// getClient().get('/path') -> call_expression -> 'getclient'
|
|
1206
|
+
// axios.get('/path') -> bare identifier -> 'axios'
|
|
1207
|
+
let receiverNode = funcNode?.childForFieldName?.('object') ?? funcNode?.children?.[0];
|
|
1208
|
+
while (receiverNode?.type === 'member_expression' ||
|
|
1209
|
+
receiverNode?.type === 'call_expression') {
|
|
1210
|
+
if (receiverNode.type === 'member_expression') {
|
|
1211
|
+
// Drill into the property (rightmost part) of the member expression
|
|
1212
|
+
const propNode = receiverNode.childForFieldName?.('property');
|
|
1213
|
+
if (propNode) {
|
|
1214
|
+
receiverNode = propNode;
|
|
1215
|
+
}
|
|
1216
|
+
else {
|
|
1217
|
+
break;
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
else {
|
|
1221
|
+
// call_expression: unwrap to the function being called
|
|
1222
|
+
const innerFunc = receiverNode.childForFieldName?.('function') ?? receiverNode.children?.[0];
|
|
1223
|
+
if (innerFunc && innerFunc !== receiverNode) {
|
|
1224
|
+
receiverNode = innerFunc;
|
|
1225
|
+
}
|
|
1226
|
+
else {
|
|
1227
|
+
break;
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
const receiverText = receiverNode?.text?.toLowerCase() ?? '';
|
|
1232
|
+
if (HTTP_CLIENT_RECEIVERS.has(receiverText)) {
|
|
1233
|
+
// This is an HTTP client call, not a route definition u2014 skip it
|
|
1234
|
+
continue;
|
|
1235
|
+
}
|
|
997
1236
|
const httpMethod = method === 'all' || method === 'use' || method === 'route'
|
|
998
1237
|
? 'GET'
|
|
999
1238
|
: method.toUpperCase();
|
|
@@ -1002,7 +1241,7 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1002
1241
|
routePath,
|
|
1003
1242
|
httpMethod,
|
|
1004
1243
|
decoratorName: `express.${method}`,
|
|
1005
|
-
lineNumber: captureMap['express_route'].startPosition.row,
|
|
1244
|
+
lineNumber: captureMap['express_route'].startPosition.row + lineOffset,
|
|
1006
1245
|
});
|
|
1007
1246
|
}
|
|
1008
1247
|
continue;
|
|
@@ -1069,7 +1308,8 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1069
1308
|
continue;
|
|
1070
1309
|
}
|
|
1071
1310
|
if (routed.kind === 'properties') {
|
|
1072
|
-
const
|
|
1311
|
+
const propEnclosingInfo = cachedFindEnclosingClassInfo(captureMap['call'], file.path, provider.resolveEnclosingOwner);
|
|
1312
|
+
const propEnclosingClassId = propEnclosingInfo?.classId ?? null;
|
|
1073
1313
|
// Enrich routed properties with FieldExtractor metadata
|
|
1074
1314
|
let routedFieldMap;
|
|
1075
1315
|
if (provider.fieldExtractor && typeEnv) {
|
|
@@ -1085,7 +1325,10 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1085
1325
|
}
|
|
1086
1326
|
for (const item of routed.items) {
|
|
1087
1327
|
const routedFieldInfo = routedFieldMap?.get(item.propName);
|
|
1088
|
-
const
|
|
1328
|
+
const propQualifiedName = propEnclosingInfo
|
|
1329
|
+
? `${propEnclosingInfo.className}.${item.propName}`
|
|
1330
|
+
: item.propName;
|
|
1331
|
+
const nodeId = generateId('Property', `${file.path}:${propQualifiedName}`);
|
|
1089
1332
|
result.nodes.push({
|
|
1090
1333
|
id: nodeId,
|
|
1091
1334
|
label: 'Property',
|
|
@@ -1250,25 +1493,119 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1250
1493
|
continue;
|
|
1251
1494
|
}
|
|
1252
1495
|
}
|
|
1253
|
-
const
|
|
1254
|
-
|
|
1496
|
+
const definitionNode = getDefinitionNodeFromCaptures(captureMap);
|
|
1497
|
+
const defaultNodeLabel = getLabelFromCaptures(captureMap, provider);
|
|
1498
|
+
if (!defaultNodeLabel)
|
|
1255
1499
|
continue;
|
|
1256
1500
|
const nameNode = captureMap['name'];
|
|
1501
|
+
const extractedClassSymbol = definitionNode && provider.classExtractor?.isTypeDeclaration(definitionNode)
|
|
1502
|
+
? provider.classExtractor.extract(definitionNode, {
|
|
1503
|
+
name: nameNode?.text,
|
|
1504
|
+
type: defaultNodeLabel,
|
|
1505
|
+
})
|
|
1506
|
+
: null;
|
|
1507
|
+
const nodeLabel = extractedClassSymbol?.type ?? defaultNodeLabel;
|
|
1257
1508
|
// Synthesize name for constructors without explicit @name capture (e.g. Swift init)
|
|
1258
|
-
if (!nameNode && nodeLabel !== 'Constructor')
|
|
1509
|
+
if (!nameNode && nodeLabel !== 'Constructor' && !extractedClassSymbol)
|
|
1259
1510
|
continue;
|
|
1260
|
-
const nodeName = nameNode ? nameNode.text : 'init';
|
|
1261
|
-
const definitionNode = getDefinitionNodeFromCaptures(captureMap);
|
|
1511
|
+
const nodeName = extractedClassSymbol?.name ?? (nameNode ? nameNode.text : 'init');
|
|
1262
1512
|
const startLine = definitionNode
|
|
1263
|
-
? definitionNode.startPosition.row
|
|
1513
|
+
? definitionNode.startPosition.row + lineOffset
|
|
1264
1514
|
: nameNode
|
|
1265
|
-
? nameNode.startPosition.row
|
|
1266
|
-
:
|
|
1267
|
-
|
|
1515
|
+
? nameNode.startPosition.row + lineOffset
|
|
1516
|
+
: lineOffset;
|
|
1517
|
+
// Compute enclosing class BEFORE node ID — needed to qualify method IDs
|
|
1518
|
+
const needsOwner = nodeLabel === 'Method' ||
|
|
1519
|
+
nodeLabel === 'Constructor' ||
|
|
1520
|
+
nodeLabel === 'Property' ||
|
|
1521
|
+
nodeLabel === 'Function';
|
|
1522
|
+
const enclosingClassInfo = needsOwner
|
|
1523
|
+
? cachedFindEnclosingClassInfo(nameNode || definitionNode, file.path, provider.resolveEnclosingOwner)
|
|
1524
|
+
: null;
|
|
1525
|
+
const enclosingClassId = enclosingClassInfo?.classId ?? null;
|
|
1526
|
+
// Qualify method/property IDs with enclosing class name to avoid collisions
|
|
1527
|
+
const qualifiedName = enclosingClassInfo
|
|
1528
|
+
? `${enclosingClassInfo.className}.${nodeName}`
|
|
1529
|
+
: nodeName;
|
|
1530
|
+
// Extract method metadata BEFORE generating node ID — parameterCount is needed
|
|
1531
|
+
// to disambiguate overloaded methods via #<arity> suffix in the ID.
|
|
1532
|
+
let declaredType;
|
|
1533
|
+
let methodProps = {};
|
|
1534
|
+
let arityForId; // raw param count for ID, even for variadic
|
|
1535
|
+
let defMethodMap;
|
|
1536
|
+
let defMethodInfo;
|
|
1537
|
+
if (nodeLabel === 'Function' || nodeLabel === 'Method' || nodeLabel === 'Constructor') {
|
|
1538
|
+
// Use MethodExtractor for method metadata — provides parameterCount, parameterTypes,
|
|
1539
|
+
// returnType, isAbstract/isFinal/annotations, visibility, and more.
|
|
1540
|
+
let enrichedByMethodExtractor = false;
|
|
1541
|
+
if (provider.methodExtractor && definitionNode) {
|
|
1542
|
+
const classNode = findEnclosingClassNode(definitionNode) ?? findClassNodeByQualifiedName(definitionNode);
|
|
1543
|
+
if (classNode) {
|
|
1544
|
+
const methodMap = getMethodInfo(classNode, provider, {
|
|
1545
|
+
filePath: file.path,
|
|
1546
|
+
language,
|
|
1547
|
+
});
|
|
1548
|
+
const defLine = definitionNode.startPosition.row + 1;
|
|
1549
|
+
const info = methodMap?.get(`${nodeName}:${defLine}`);
|
|
1550
|
+
if (info) {
|
|
1551
|
+
enrichedByMethodExtractor = true;
|
|
1552
|
+
arityForId = arityForIdFromInfo(info);
|
|
1553
|
+
methodProps = buildMethodProps(info);
|
|
1554
|
+
defMethodMap = methodMap;
|
|
1555
|
+
defMethodInfo = info;
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
// For top-level methods (e.g. Go method_declaration), try extractFromNode
|
|
1560
|
+
if (!enrichedByMethodExtractor &&
|
|
1561
|
+
provider.methodExtractor?.extractFromNode &&
|
|
1562
|
+
definitionNode) {
|
|
1563
|
+
const info = provider.methodExtractor.extractFromNode(definitionNode, {
|
|
1564
|
+
filePath: file.path,
|
|
1565
|
+
language,
|
|
1566
|
+
});
|
|
1567
|
+
if (info) {
|
|
1568
|
+
enrichedByMethodExtractor = true;
|
|
1569
|
+
arityForId = arityForIdFromInfo(info);
|
|
1570
|
+
methodProps = buildMethodProps(info);
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
// Append #<paramCount> to Method/Constructor IDs to disambiguate overloads.
|
|
1575
|
+
// Functions are not suffixed — they don't overload by name in the same scope.
|
|
1576
|
+
// When same-arity collisions exist, append ~type1,type2 for further disambiguation.
|
|
1577
|
+
const needsAritySuffix = nodeLabel === 'Method' || nodeLabel === 'Constructor';
|
|
1578
|
+
let arityTag = needsAritySuffix && arityForId !== undefined ? `#${arityForId}` : '';
|
|
1579
|
+
if (arityTag && defMethodMap && defMethodInfo) {
|
|
1580
|
+
const groups = buildCollisionGroups(defMethodMap);
|
|
1581
|
+
arityTag += typeTagForId(defMethodMap, nodeName, arityForId, defMethodInfo, language, groups);
|
|
1582
|
+
arityTag += constTagForId(defMethodMap, nodeName, arityForId, defMethodInfo, groups);
|
|
1583
|
+
}
|
|
1584
|
+
const nodeId = generateId(nodeLabel, `${file.path}:${qualifiedName}${arityTag}`);
|
|
1585
|
+
const classNodeForSymbol = definitionNode || nameNode;
|
|
1586
|
+
const qualifiedTypeName = extractedClassSymbol?.qualifiedName ??
|
|
1587
|
+
(classNodeForSymbol && provider.classExtractor?.isTypeDeclaration(classNodeForSymbol)
|
|
1588
|
+
? (provider.classExtractor.extractQualifiedName(classNodeForSymbol, nodeName) ?? nodeName)
|
|
1589
|
+
: undefined);
|
|
1268
1590
|
const description = provider.descriptionExtractor?.(nodeLabel, nodeName, captureMap);
|
|
1269
1591
|
let frameworkHint = definitionNode
|
|
1270
1592
|
? detectFrameworkFromAST(language, (definitionNode.text || '').slice(0, 300))
|
|
1271
1593
|
: null;
|
|
1594
|
+
// Suppress Spring framework hint for methods inside interfaces
|
|
1595
|
+
// (Feign clients, JAX-RS proxies are consumers, not providers)
|
|
1596
|
+
if (frameworkHint && definitionNode) {
|
|
1597
|
+
let classCheck = definitionNode.parent;
|
|
1598
|
+
while (classCheck) {
|
|
1599
|
+
if (classCheck.type === 'interface_declaration') {
|
|
1600
|
+
frameworkHint = null;
|
|
1601
|
+
break;
|
|
1602
|
+
}
|
|
1603
|
+
if (classCheck.type === 'class_declaration' || classCheck.type === 'program') {
|
|
1604
|
+
break;
|
|
1605
|
+
}
|
|
1606
|
+
classCheck = classCheck.parent;
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1272
1609
|
// Decorators appear on lines immediately before their definition; allow up to
|
|
1273
1610
|
// MAX_DECORATOR_SCAN_LINES gap for blank lines / multi-line decorator stacks.
|
|
1274
1611
|
const MAX_DECORATOR_SCAN_LINES = 5;
|
|
@@ -1291,94 +1628,15 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1291
1628
|
filePath: file.path,
|
|
1292
1629
|
toolName: nodeName,
|
|
1293
1630
|
description: dec.arg || '',
|
|
1294
|
-
lineNumber: definitionNode.startPosition.row,
|
|
1631
|
+
lineNumber: definitionNode.startPosition.row + lineOffset,
|
|
1295
1632
|
});
|
|
1296
1633
|
}
|
|
1297
1634
|
fileDecorators.delete(checkLine);
|
|
1298
1635
|
}
|
|
1299
1636
|
}
|
|
1300
1637
|
}
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
let parameterTypes;
|
|
1304
|
-
let returnType;
|
|
1305
|
-
let declaredType;
|
|
1306
|
-
let visibility;
|
|
1307
|
-
let isStatic;
|
|
1308
|
-
let isReadonly;
|
|
1309
|
-
let isAbstract;
|
|
1310
|
-
let isFinal;
|
|
1311
|
-
let isVirtual;
|
|
1312
|
-
let isOverride;
|
|
1313
|
-
let isAsync;
|
|
1314
|
-
let isPartial;
|
|
1315
|
-
let annotations;
|
|
1316
|
-
if (nodeLabel === 'Function' || nodeLabel === 'Method' || nodeLabel === 'Constructor') {
|
|
1317
|
-
// Try MethodExtractor first — it provides everything extractMethodSignature does, plus
|
|
1318
|
-
// isAbstract/isFinal/annotations. Only fall back to extractMethodSignature when no
|
|
1319
|
-
// MethodExtractor is available or the method isn't inside a class body.
|
|
1320
|
-
let enrichedByMethodExtractor = false;
|
|
1321
|
-
if (provider.methodExtractor && definitionNode) {
|
|
1322
|
-
const classNode = findEnclosingClassNode(definitionNode);
|
|
1323
|
-
if (classNode) {
|
|
1324
|
-
const methodMap = getMethodInfo(classNode, provider, {
|
|
1325
|
-
filePath: file.path,
|
|
1326
|
-
language,
|
|
1327
|
-
});
|
|
1328
|
-
const defLine = definitionNode.startPosition.row + 1;
|
|
1329
|
-
const info = methodMap?.get(`${nodeName}:${defLine}`);
|
|
1330
|
-
if (info) {
|
|
1331
|
-
enrichedByMethodExtractor = true;
|
|
1332
|
-
parameterCount = info.parameters.length;
|
|
1333
|
-
const types = [];
|
|
1334
|
-
let optionalCount = 0;
|
|
1335
|
-
for (const p of info.parameters) {
|
|
1336
|
-
if (p.type !== null)
|
|
1337
|
-
types.push(p.type);
|
|
1338
|
-
if (p.isOptional)
|
|
1339
|
-
optionalCount++;
|
|
1340
|
-
}
|
|
1341
|
-
parameterTypes = types.length > 0 ? types : undefined;
|
|
1342
|
-
requiredParameterCount =
|
|
1343
|
-
optionalCount > 0 ? parameterCount - optionalCount : undefined;
|
|
1344
|
-
returnType = info.returnType ?? undefined;
|
|
1345
|
-
visibility = info.visibility;
|
|
1346
|
-
isStatic = info.isStatic;
|
|
1347
|
-
isAbstract = info.isAbstract;
|
|
1348
|
-
isFinal = info.isFinal;
|
|
1349
|
-
if (info.isVirtual)
|
|
1350
|
-
isVirtual = info.isVirtual;
|
|
1351
|
-
if (info.isOverride)
|
|
1352
|
-
isOverride = info.isOverride;
|
|
1353
|
-
if (info.isAsync)
|
|
1354
|
-
isAsync = info.isAsync;
|
|
1355
|
-
if (info.isPartial)
|
|
1356
|
-
isPartial = info.isPartial;
|
|
1357
|
-
if (info.annotations.length > 0)
|
|
1358
|
-
annotations = info.annotations;
|
|
1359
|
-
}
|
|
1360
|
-
}
|
|
1361
|
-
}
|
|
1362
|
-
if (!enrichedByMethodExtractor) {
|
|
1363
|
-
const sig = extractMethodSignature(definitionNode);
|
|
1364
|
-
parameterCount = sig.parameterCount;
|
|
1365
|
-
requiredParameterCount = sig.requiredParameterCount;
|
|
1366
|
-
parameterTypes = sig.parameterTypes;
|
|
1367
|
-
returnType = sig.returnType;
|
|
1368
|
-
}
|
|
1369
|
-
// Language-specific return type fallback (e.g. Ruby YARD @return [Type])
|
|
1370
|
-
// Also upgrades uninformative AST types like PHP `array` with PHPDoc `@return User[]`
|
|
1371
|
-
if ((!returnType || returnType === 'array' || returnType === 'iterable') &&
|
|
1372
|
-
definitionNode) {
|
|
1373
|
-
const tc = provider.typeConfig;
|
|
1374
|
-
if (tc?.extractReturnType) {
|
|
1375
|
-
const docReturn = tc.extractReturnType(definitionNode);
|
|
1376
|
-
if (docReturn)
|
|
1377
|
-
returnType = docReturn;
|
|
1378
|
-
}
|
|
1379
|
-
}
|
|
1380
|
-
}
|
|
1381
|
-
else if (nodeLabel === 'Property' && definitionNode) {
|
|
1638
|
+
// Property metadata extraction (not needed before nodeId — Properties don't overload)
|
|
1639
|
+
if (nodeLabel === 'Property' && definitionNode) {
|
|
1382
1640
|
// FieldExtractor is the single source of truth when available
|
|
1383
1641
|
if (provider.fieldExtractor && typeEnv) {
|
|
1384
1642
|
const classNode = findEnclosingClassNode(definitionNode);
|
|
@@ -1392,9 +1650,9 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1392
1650
|
const info = fieldMap?.get(nodeName);
|
|
1393
1651
|
if (info) {
|
|
1394
1652
|
declaredType = info.type ?? undefined;
|
|
1395
|
-
visibility = info.visibility;
|
|
1396
|
-
isStatic = info.isStatic;
|
|
1397
|
-
isReadonly = info.isReadonly;
|
|
1653
|
+
methodProps.visibility = info.visibility;
|
|
1654
|
+
methodProps.isStatic = info.isStatic;
|
|
1655
|
+
methodProps.isReadonly = info.isReadonly;
|
|
1398
1656
|
}
|
|
1399
1657
|
}
|
|
1400
1658
|
}
|
|
@@ -1405,10 +1663,13 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1405
1663
|
properties: {
|
|
1406
1664
|
name: nodeName,
|
|
1407
1665
|
filePath: file.path,
|
|
1408
|
-
startLine: definitionNode ? definitionNode.startPosition.row : startLine,
|
|
1409
|
-
endLine: definitionNode ? definitionNode.endPosition.row : startLine,
|
|
1666
|
+
startLine: definitionNode ? definitionNode.startPosition.row + lineOffset : startLine,
|
|
1667
|
+
endLine: definitionNode ? definitionNode.endPosition.row + lineOffset : startLine,
|
|
1410
1668
|
language: language,
|
|
1411
|
-
isExported:
|
|
1669
|
+
isExported: language === SupportedLanguages.Vue && isVueSetup
|
|
1670
|
+
? isVueSetupTopLevel(nameNode || definitionNode)
|
|
1671
|
+
: cachedExportCheck(provider.exportChecker, nameNode || definitionNode, nodeName),
|
|
1672
|
+
...(qualifiedTypeName !== undefined ? { qualifiedName: qualifiedTypeName } : {}),
|
|
1412
1673
|
...(frameworkHint
|
|
1413
1674
|
? {
|
|
1414
1675
|
astFrameworkMultiplier: frameworkHint.entryPointMultiplier,
|
|
@@ -1416,53 +1677,41 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1416
1677
|
}
|
|
1417
1678
|
: {}),
|
|
1418
1679
|
...(description !== undefined ? { description } : {}),
|
|
1419
|
-
...
|
|
1420
|
-
...(requiredParameterCount !== undefined ? { requiredParameterCount } : {}),
|
|
1421
|
-
...(parameterTypes !== undefined ? { parameterTypes } : {}),
|
|
1422
|
-
...(returnType !== undefined ? { returnType } : {}),
|
|
1680
|
+
...methodProps,
|
|
1423
1681
|
...(declaredType !== undefined ? { declaredType } : {}),
|
|
1424
|
-
...(visibility !== undefined ? { visibility } : {}),
|
|
1425
|
-
...(isStatic !== undefined ? { isStatic } : {}),
|
|
1426
|
-
...(isReadonly !== undefined ? { isReadonly } : {}),
|
|
1427
|
-
...(isAbstract !== undefined ? { isAbstract } : {}),
|
|
1428
|
-
...(isFinal !== undefined ? { isFinal } : {}),
|
|
1429
|
-
...(isVirtual !== undefined ? { isVirtual } : {}),
|
|
1430
|
-
...(isOverride !== undefined ? { isOverride } : {}),
|
|
1431
|
-
...(isAsync !== undefined ? { isAsync } : {}),
|
|
1432
|
-
...(isPartial !== undefined ? { isPartial } : {}),
|
|
1433
|
-
...(annotations !== undefined ? { annotations } : {}),
|
|
1434
1682
|
},
|
|
1435
1683
|
});
|
|
1436
|
-
//
|
|
1437
|
-
// Function is included because Kotlin/Rust/Python capture class methods as Function nodes
|
|
1438
|
-
const needsOwner = nodeLabel === 'Method' ||
|
|
1439
|
-
nodeLabel === 'Constructor' ||
|
|
1440
|
-
nodeLabel === 'Property' ||
|
|
1441
|
-
nodeLabel === 'Function';
|
|
1442
|
-
const enclosingClassId = needsOwner
|
|
1443
|
-
? cachedFindEnclosingClassId(nameNode || definitionNode, file.path)
|
|
1444
|
-
: null;
|
|
1684
|
+
// enclosingClassId already computed above (before nodeId generation)
|
|
1445
1685
|
result.symbols.push({
|
|
1446
1686
|
filePath: file.path,
|
|
1447
1687
|
name: nodeName,
|
|
1448
1688
|
nodeId,
|
|
1449
1689
|
type: nodeLabel,
|
|
1450
|
-
...(
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1690
|
+
...(qualifiedTypeName !== undefined ? { qualifiedName: qualifiedTypeName } : {}),
|
|
1691
|
+
parameterCount: methodProps.parameterCount,
|
|
1692
|
+
requiredParameterCount: methodProps.requiredParameterCount,
|
|
1693
|
+
parameterTypes: methodProps.parameterTypes,
|
|
1694
|
+
returnType: methodProps.returnType,
|
|
1454
1695
|
...(declaredType !== undefined ? { declaredType } : {}),
|
|
1455
1696
|
...(enclosingClassId ? { ownerId: enclosingClassId } : {}),
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
...(isVirtual !== undefined
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
...(
|
|
1465
|
-
|
|
1697
|
+
visibility: methodProps.visibility,
|
|
1698
|
+
isStatic: methodProps.isStatic,
|
|
1699
|
+
isReadonly: methodProps.isReadonly,
|
|
1700
|
+
isAbstract: methodProps.isAbstract,
|
|
1701
|
+
isFinal: methodProps.isFinal,
|
|
1702
|
+
...(methodProps.isVirtual !== undefined
|
|
1703
|
+
? { isVirtual: methodProps.isVirtual }
|
|
1704
|
+
: {}),
|
|
1705
|
+
...(methodProps.isOverride !== undefined
|
|
1706
|
+
? { isOverride: methodProps.isOverride }
|
|
1707
|
+
: {}),
|
|
1708
|
+
...(methodProps.isAsync !== undefined ? { isAsync: methodProps.isAsync } : {}),
|
|
1709
|
+
...(methodProps.isPartial !== undefined
|
|
1710
|
+
? { isPartial: methodProps.isPartial }
|
|
1711
|
+
: {}),
|
|
1712
|
+
...(methodProps.annotations !== undefined
|
|
1713
|
+
? { annotations: methodProps.annotations }
|
|
1714
|
+
: {}),
|
|
1466
1715
|
});
|
|
1467
1716
|
const fileId = generateId('File', file.path);
|
|
1468
1717
|
const relId = generateId('DEFINES', `${fileId}->${nodeId}`);
|
|
@@ -1490,10 +1739,23 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1490
1739
|
// Extract framework routes via provider detection (e.g., Laravel routes.php)
|
|
1491
1740
|
if (provider.isRouteFile?.(file.path)) {
|
|
1492
1741
|
const extractedRoutes = extractLaravelRoutes(tree, file.path);
|
|
1493
|
-
|
|
1742
|
+
for (const r of extractedRoutes)
|
|
1743
|
+
result.routes.push(r);
|
|
1494
1744
|
}
|
|
1495
1745
|
// Extract ORM queries (Prisma, Supabase)
|
|
1496
|
-
extractORMQueries(file.path,
|
|
1746
|
+
extractORMQueries(file.path, parseContent, result.ormQueries);
|
|
1747
|
+
// Vue: emit CALLS edges for components used in <template>
|
|
1748
|
+
if (language === SupportedLanguages.Vue) {
|
|
1749
|
+
const templateComponents = extractTemplateComponents(file.content);
|
|
1750
|
+
for (const componentName of templateComponents) {
|
|
1751
|
+
result.calls.push({
|
|
1752
|
+
filePath: file.path,
|
|
1753
|
+
calledName: componentName,
|
|
1754
|
+
sourceId: generateId('File', file.path),
|
|
1755
|
+
callForm: 'free',
|
|
1756
|
+
});
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1497
1759
|
}
|
|
1498
1760
|
};
|
|
1499
1761
|
// ============================================================================
|
|
@@ -1514,26 +1776,33 @@ let accumulated = {
|
|
|
1514
1776
|
toolDefs: [],
|
|
1515
1777
|
ormQueries: [],
|
|
1516
1778
|
constructorBindings: [],
|
|
1517
|
-
|
|
1779
|
+
fileScopeBindings: [],
|
|
1518
1780
|
skippedLanguages: {},
|
|
1519
1781
|
fileCount: 0,
|
|
1520
1782
|
};
|
|
1521
1783
|
let cumulativeProcessed = 0;
|
|
1784
|
+
// Use a loop instead of push(...spread) to avoid hitting V8's argument limit
|
|
1785
|
+
// when merging large result sets (push(...arr) calls apply() under the hood
|
|
1786
|
+
// and blows the stack when arr has >~65k elements).
|
|
1787
|
+
const appendAll = (target, src) => {
|
|
1788
|
+
for (let i = 0; i < src.length; i++)
|
|
1789
|
+
target.push(src[i]);
|
|
1790
|
+
};
|
|
1522
1791
|
const mergeResult = (target, src) => {
|
|
1523
|
-
target.nodes
|
|
1524
|
-
target.relationships
|
|
1525
|
-
target.symbols
|
|
1526
|
-
target.imports
|
|
1527
|
-
target.calls
|
|
1528
|
-
target.assignments
|
|
1529
|
-
target.heritage
|
|
1530
|
-
target.routes
|
|
1531
|
-
target.fetchCalls
|
|
1532
|
-
target.decoratorRoutes
|
|
1533
|
-
target.toolDefs
|
|
1534
|
-
target.ormQueries
|
|
1535
|
-
target.constructorBindings
|
|
1536
|
-
target.
|
|
1792
|
+
appendAll(target.nodes, src.nodes);
|
|
1793
|
+
appendAll(target.relationships, src.relationships);
|
|
1794
|
+
appendAll(target.symbols, src.symbols);
|
|
1795
|
+
appendAll(target.imports, src.imports);
|
|
1796
|
+
appendAll(target.calls, src.calls);
|
|
1797
|
+
appendAll(target.assignments, src.assignments);
|
|
1798
|
+
appendAll(target.heritage, src.heritage);
|
|
1799
|
+
appendAll(target.routes, src.routes);
|
|
1800
|
+
appendAll(target.fetchCalls, src.fetchCalls);
|
|
1801
|
+
appendAll(target.decoratorRoutes, src.decoratorRoutes);
|
|
1802
|
+
appendAll(target.toolDefs, src.toolDefs);
|
|
1803
|
+
appendAll(target.ormQueries, src.ormQueries);
|
|
1804
|
+
appendAll(target.constructorBindings, src.constructorBindings);
|
|
1805
|
+
appendAll(target.fileScopeBindings, src.fileScopeBindings);
|
|
1537
1806
|
for (const [lang, count] of Object.entries(src.skippedLanguages)) {
|
|
1538
1807
|
target.skippedLanguages[lang] = (target.skippedLanguages[lang] || 0) + count;
|
|
1539
1808
|
}
|
|
@@ -1581,7 +1850,7 @@ parentPort.on('message', (msg) => {
|
|
|
1581
1850
|
toolDefs: [],
|
|
1582
1851
|
ormQueries: [],
|
|
1583
1852
|
constructorBindings: [],
|
|
1584
|
-
|
|
1853
|
+
fileScopeBindings: [],
|
|
1585
1854
|
skippedLanguages: {},
|
|
1586
1855
|
fileCount: 0,
|
|
1587
1856
|
};
|