@colbymchenry/codegraph-darwin-x64 0.9.9 → 1.0.0
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/lib/dist/bin/codegraph.d.ts +1 -0
- package/lib/dist/bin/codegraph.d.ts.map +1 -1
- package/lib/dist/bin/codegraph.js +246 -3
- package/lib/dist/bin/codegraph.js.map +1 -1
- package/lib/dist/context/index.d.ts.map +1 -1
- package/lib/dist/context/index.js +7 -0
- package/lib/dist/context/index.js.map +1 -1
- package/lib/dist/db/index.d.ts.map +1 -1
- package/lib/dist/db/index.js +2 -1
- package/lib/dist/db/index.js.map +1 -1
- package/lib/dist/db/migrations.d.ts +1 -1
- package/lib/dist/db/migrations.d.ts.map +1 -1
- package/lib/dist/db/migrations.js +10 -1
- package/lib/dist/db/migrations.js.map +1 -1
- package/lib/dist/db/queries.d.ts +43 -0
- package/lib/dist/db/queries.d.ts.map +1 -1
- package/lib/dist/db/queries.js +103 -7
- package/lib/dist/db/queries.js.map +1 -1
- package/lib/dist/db/schema.sql +1 -0
- package/lib/dist/db/sqlite-adapter.d.ts +7 -0
- package/lib/dist/db/sqlite-adapter.d.ts.map +1 -1
- package/lib/dist/db/sqlite-adapter.js +3 -0
- package/lib/dist/db/sqlite-adapter.js.map +1 -1
- package/lib/dist/directory.d.ts +34 -2
- package/lib/dist/directory.d.ts.map +1 -1
- package/lib/dist/directory.js +129 -35
- package/lib/dist/directory.js.map +1 -1
- package/lib/dist/extraction/astro-extractor.d.ts +79 -0
- package/lib/dist/extraction/astro-extractor.d.ts.map +1 -0
- package/lib/dist/extraction/astro-extractor.js +320 -0
- package/lib/dist/extraction/astro-extractor.js.map +1 -0
- package/lib/dist/extraction/extraction-version.d.ts +25 -0
- package/lib/dist/extraction/extraction-version.d.ts.map +1 -0
- package/lib/dist/extraction/extraction-version.js +28 -0
- package/lib/dist/extraction/extraction-version.js.map +1 -0
- package/lib/dist/extraction/function-ref.d.ts +118 -0
- package/lib/dist/extraction/function-ref.d.ts.map +1 -0
- package/lib/dist/extraction/function-ref.js +727 -0
- package/lib/dist/extraction/function-ref.js.map +1 -0
- package/lib/dist/extraction/generated-detection.d.ts.map +1 -1
- package/lib/dist/extraction/generated-detection.js +3 -0
- package/lib/dist/extraction/generated-detection.js.map +1 -1
- package/lib/dist/extraction/grammars.d.ts +7 -1
- package/lib/dist/extraction/grammars.d.ts.map +1 -1
- package/lib/dist/extraction/grammars.js +52 -4
- package/lib/dist/extraction/grammars.js.map +1 -1
- package/lib/dist/extraction/index.d.ts +34 -0
- package/lib/dist/extraction/index.d.ts.map +1 -1
- package/lib/dist/extraction/index.js +346 -62
- package/lib/dist/extraction/index.js.map +1 -1
- package/lib/dist/extraction/languages/c-cpp.d.ts +8 -0
- package/lib/dist/extraction/languages/c-cpp.d.ts.map +1 -1
- package/lib/dist/extraction/languages/c-cpp.js +87 -28
- package/lib/dist/extraction/languages/c-cpp.js.map +1 -1
- package/lib/dist/extraction/languages/csharp.d.ts +22 -0
- package/lib/dist/extraction/languages/csharp.d.ts.map +1 -1
- package/lib/dist/extraction/languages/csharp.js +84 -2
- package/lib/dist/extraction/languages/csharp.js.map +1 -1
- package/lib/dist/extraction/languages/dart.d.ts.map +1 -1
- package/lib/dist/extraction/languages/dart.js +161 -1
- package/lib/dist/extraction/languages/dart.js.map +1 -1
- package/lib/dist/extraction/languages/go.d.ts.map +1 -1
- package/lib/dist/extraction/languages/go.js +43 -2
- package/lib/dist/extraction/languages/go.js.map +1 -1
- package/lib/dist/extraction/languages/index.d.ts.map +1 -1
- package/lib/dist/extraction/languages/index.js +2 -0
- package/lib/dist/extraction/languages/index.js.map +1 -1
- package/lib/dist/extraction/languages/java.d.ts.map +1 -1
- package/lib/dist/extraction/languages/java.js +42 -1
- package/lib/dist/extraction/languages/java.js.map +1 -1
- package/lib/dist/extraction/languages/javascript.d.ts.map +1 -1
- package/lib/dist/extraction/languages/javascript.js +16 -0
- package/lib/dist/extraction/languages/javascript.js.map +1 -1
- package/lib/dist/extraction/languages/kotlin.d.ts.map +1 -1
- package/lib/dist/extraction/languages/kotlin.js +69 -0
- package/lib/dist/extraction/languages/kotlin.js.map +1 -1
- package/lib/dist/extraction/languages/objc.d.ts.map +1 -1
- package/lib/dist/extraction/languages/objc.js +42 -0
- package/lib/dist/extraction/languages/objc.js.map +1 -1
- package/lib/dist/extraction/languages/pascal.d.ts.map +1 -1
- package/lib/dist/extraction/languages/pascal.js +11 -0
- package/lib/dist/extraction/languages/pascal.js.map +1 -1
- package/lib/dist/extraction/languages/php.d.ts.map +1 -1
- package/lib/dist/extraction/languages/php.js +90 -1
- package/lib/dist/extraction/languages/php.js.map +1 -1
- package/lib/dist/extraction/languages/r.d.ts +3 -0
- package/lib/dist/extraction/languages/r.d.ts.map +1 -0
- package/lib/dist/extraction/languages/r.js +314 -0
- package/lib/dist/extraction/languages/r.js.map +1 -0
- package/lib/dist/extraction/languages/ruby.d.ts.map +1 -1
- package/lib/dist/extraction/languages/ruby.js +35 -0
- package/lib/dist/extraction/languages/ruby.js.map +1 -1
- package/lib/dist/extraction/languages/rust.d.ts.map +1 -1
- package/lib/dist/extraction/languages/rust.js +35 -2
- package/lib/dist/extraction/languages/rust.js.map +1 -1
- package/lib/dist/extraction/languages/scala.d.ts.map +1 -1
- package/lib/dist/extraction/languages/scala.js +61 -1
- package/lib/dist/extraction/languages/scala.js.map +1 -1
- package/lib/dist/extraction/languages/swift.d.ts.map +1 -1
- package/lib/dist/extraction/languages/swift.js +61 -0
- package/lib/dist/extraction/languages/swift.js.map +1 -1
- package/lib/dist/extraction/languages/typescript.d.ts +13 -0
- package/lib/dist/extraction/languages/typescript.d.ts.map +1 -1
- package/lib/dist/extraction/languages/typescript.js +38 -0
- package/lib/dist/extraction/languages/typescript.js.map +1 -1
- package/lib/dist/extraction/liquid-extractor.d.ts +7 -0
- package/lib/dist/extraction/liquid-extractor.d.ts.map +1 -1
- package/lib/dist/extraction/liquid-extractor.js +53 -9
- package/lib/dist/extraction/liquid-extractor.js.map +1 -1
- package/lib/dist/extraction/razor-extractor.d.ts +42 -0
- package/lib/dist/extraction/razor-extractor.d.ts.map +1 -0
- package/lib/dist/extraction/razor-extractor.js +285 -0
- package/lib/dist/extraction/razor-extractor.js.map +1 -0
- package/lib/dist/extraction/svelte-extractor.d.ts.map +1 -1
- package/lib/dist/extraction/svelte-extractor.js +6 -3
- package/lib/dist/extraction/svelte-extractor.js.map +1 -1
- package/lib/dist/extraction/tree-sitter-helpers.d.ts.map +1 -1
- package/lib/dist/extraction/tree-sitter-helpers.js +59 -10
- package/lib/dist/extraction/tree-sitter-helpers.js.map +1 -1
- package/lib/dist/extraction/tree-sitter-types.d.ts +33 -0
- package/lib/dist/extraction/tree-sitter-types.d.ts.map +1 -1
- package/lib/dist/extraction/tree-sitter.d.ts +211 -0
- package/lib/dist/extraction/tree-sitter.d.ts.map +1 -1
- package/lib/dist/extraction/tree-sitter.js +1681 -49
- package/lib/dist/extraction/tree-sitter.js.map +1 -1
- package/lib/dist/extraction/vue-extractor.d.ts +15 -0
- package/lib/dist/extraction/vue-extractor.d.ts.map +1 -1
- package/lib/dist/extraction/vue-extractor.js +94 -3
- package/lib/dist/extraction/vue-extractor.js.map +1 -1
- package/lib/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
- package/lib/dist/extraction/wasm/tree-sitter-r.wasm +0 -0
- package/lib/dist/graph/queries.d.ts.map +1 -1
- package/lib/dist/graph/queries.js +13 -40
- package/lib/dist/graph/queries.js.map +1 -1
- package/lib/dist/graph/traversal.d.ts.map +1 -1
- package/lib/dist/graph/traversal.js +16 -4
- package/lib/dist/graph/traversal.js.map +1 -1
- package/lib/dist/index.d.ts +34 -2
- package/lib/dist/index.d.ts.map +1 -1
- package/lib/dist/index.js +90 -8
- package/lib/dist/index.js.map +1 -1
- package/lib/dist/installer/index.d.ts.map +1 -1
- package/lib/dist/installer/index.js +52 -2
- package/lib/dist/installer/index.js.map +1 -1
- package/lib/dist/installer/instructions-template.d.ts +34 -11
- package/lib/dist/installer/instructions-template.d.ts.map +1 -1
- package/lib/dist/installer/instructions-template.js +44 -12
- package/lib/dist/installer/instructions-template.js.map +1 -1
- package/lib/dist/installer/targets/claude.d.ts.map +1 -1
- package/lib/dist/installer/targets/claude.js +6 -10
- package/lib/dist/installer/targets/claude.js.map +1 -1
- package/lib/dist/installer/targets/codex.js +4 -6
- package/lib/dist/installer/targets/codex.js.map +1 -1
- package/lib/dist/installer/targets/gemini.js +4 -6
- package/lib/dist/installer/targets/gemini.js.map +1 -1
- package/lib/dist/installer/targets/opencode.d.ts +9 -1
- package/lib/dist/installer/targets/opencode.d.ts.map +1 -1
- package/lib/dist/installer/targets/opencode.js +91 -40
- package/lib/dist/installer/targets/opencode.js.map +1 -1
- package/lib/dist/installer/targets/shared.d.ts +14 -0
- package/lib/dist/installer/targets/shared.d.ts.map +1 -1
- package/lib/dist/installer/targets/shared.js +16 -0
- package/lib/dist/installer/targets/shared.js.map +1 -1
- package/lib/dist/mcp/daemon.d.ts +60 -1
- package/lib/dist/mcp/daemon.d.ts.map +1 -1
- package/lib/dist/mcp/daemon.js +221 -8
- package/lib/dist/mcp/daemon.js.map +1 -1
- package/lib/dist/mcp/dynamic-boundaries.d.ts +41 -0
- package/lib/dist/mcp/dynamic-boundaries.d.ts.map +1 -0
- package/lib/dist/mcp/dynamic-boundaries.js +359 -0
- package/lib/dist/mcp/dynamic-boundaries.js.map +1 -0
- package/lib/dist/mcp/index.d.ts.map +1 -1
- package/lib/dist/mcp/index.js +18 -9
- package/lib/dist/mcp/index.js.map +1 -1
- package/lib/dist/mcp/ppid-watchdog.d.ts +44 -0
- package/lib/dist/mcp/ppid-watchdog.d.ts.map +1 -0
- package/lib/dist/mcp/ppid-watchdog.js +27 -0
- package/lib/dist/mcp/ppid-watchdog.js.map +1 -0
- package/lib/dist/mcp/proxy.d.ts +6 -0
- package/lib/dist/mcp/proxy.d.ts.map +1 -1
- package/lib/dist/mcp/proxy.js +153 -24
- package/lib/dist/mcp/proxy.js.map +1 -1
- package/lib/dist/mcp/server-instructions.d.ts +12 -1
- package/lib/dist/mcp/server-instructions.d.ts.map +1 -1
- package/lib/dist/mcp/server-instructions.js +43 -16
- package/lib/dist/mcp/server-instructions.js.map +1 -1
- package/lib/dist/mcp/session.d.ts +2 -0
- package/lib/dist/mcp/session.d.ts.map +1 -1
- package/lib/dist/mcp/session.js +49 -2
- package/lib/dist/mcp/session.js.map +1 -1
- package/lib/dist/mcp/stdin-teardown.d.ts +27 -0
- package/lib/dist/mcp/stdin-teardown.d.ts.map +1 -0
- package/lib/dist/mcp/stdin-teardown.js +49 -0
- package/lib/dist/mcp/stdin-teardown.js.map +1 -0
- package/lib/dist/mcp/tools.d.ts +71 -0
- package/lib/dist/mcp/tools.d.ts.map +1 -1
- package/lib/dist/mcp/tools.js +703 -85
- package/lib/dist/mcp/tools.js.map +1 -1
- package/lib/dist/mcp/transport.d.ts.map +1 -1
- package/lib/dist/mcp/transport.js +18 -2
- package/lib/dist/mcp/transport.js.map +1 -1
- package/lib/dist/resolution/callback-synthesizer.d.ts +3 -3
- package/lib/dist/resolution/callback-synthesizer.d.ts.map +1 -1
- package/lib/dist/resolution/callback-synthesizer.js +549 -21
- package/lib/dist/resolution/callback-synthesizer.js.map +1 -1
- package/lib/dist/resolution/frameworks/astro.d.ts +9 -0
- package/lib/dist/resolution/frameworks/astro.d.ts.map +1 -0
- package/lib/dist/resolution/frameworks/astro.js +169 -0
- package/lib/dist/resolution/frameworks/astro.js.map +1 -0
- package/lib/dist/resolution/frameworks/expo-modules.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/expo-modules.js +6 -1
- package/lib/dist/resolution/frameworks/expo-modules.js.map +1 -1
- package/lib/dist/resolution/frameworks/index.d.ts +1 -0
- package/lib/dist/resolution/frameworks/index.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/index.js +5 -1
- package/lib/dist/resolution/frameworks/index.js.map +1 -1
- package/lib/dist/resolution/frameworks/java.js +6 -1
- package/lib/dist/resolution/frameworks/java.js.map +1 -1
- package/lib/dist/resolution/frameworks/python.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/python.js +7 -3
- package/lib/dist/resolution/frameworks/python.js.map +1 -1
- package/lib/dist/resolution/frameworks/react-native.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/react-native.js +53 -3
- package/lib/dist/resolution/frameworks/react-native.js.map +1 -1
- package/lib/dist/resolution/frameworks/react.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/react.js +15 -3
- package/lib/dist/resolution/frameworks/react.js.map +1 -1
- package/lib/dist/resolution/frameworks/svelte.js +5 -1
- package/lib/dist/resolution/frameworks/svelte.js.map +1 -1
- package/lib/dist/resolution/frameworks/vue.js +24 -27
- package/lib/dist/resolution/frameworks/vue.js.map +1 -1
- package/lib/dist/resolution/import-resolver.d.ts +10 -0
- package/lib/dist/resolution/import-resolver.d.ts.map +1 -1
- package/lib/dist/resolution/import-resolver.js +564 -2
- package/lib/dist/resolution/import-resolver.js.map +1 -1
- package/lib/dist/resolution/index.d.ts +80 -0
- package/lib/dist/resolution/index.d.ts.map +1 -1
- package/lib/dist/resolution/index.js +457 -7
- package/lib/dist/resolution/index.js.map +1 -1
- package/lib/dist/resolution/name-matcher.d.ts +61 -0
- package/lib/dist/resolution/name-matcher.d.ts.map +1 -1
- package/lib/dist/resolution/name-matcher.js +590 -14
- package/lib/dist/resolution/name-matcher.js.map +1 -1
- package/lib/dist/resolution/types.d.ts +27 -3
- package/lib/dist/resolution/types.d.ts.map +1 -1
- package/lib/dist/resolution/workspace-packages.d.ts +48 -0
- package/lib/dist/resolution/workspace-packages.d.ts.map +1 -0
- package/lib/dist/resolution/workspace-packages.js +208 -0
- package/lib/dist/resolution/workspace-packages.js.map +1 -0
- package/lib/dist/search/query-utils.d.ts +17 -1
- package/lib/dist/search/query-utils.d.ts.map +1 -1
- package/lib/dist/search/query-utils.js +79 -10
- package/lib/dist/search/query-utils.js.map +1 -1
- package/lib/dist/sync/watcher.d.ts +124 -32
- package/lib/dist/sync/watcher.d.ts.map +1 -1
- package/lib/dist/sync/watcher.js +326 -111
- package/lib/dist/sync/watcher.js.map +1 -1
- package/lib/dist/telemetry/index.d.ts +146 -0
- package/lib/dist/telemetry/index.d.ts.map +1 -0
- package/lib/dist/telemetry/index.js +544 -0
- package/lib/dist/telemetry/index.js.map +1 -0
- package/lib/dist/types.d.ts +17 -2
- package/lib/dist/types.d.ts.map +1 -1
- package/lib/dist/types.js +3 -0
- package/lib/dist/types.js.map +1 -1
- package/lib/dist/upgrade/index.d.ts +132 -0
- package/lib/dist/upgrade/index.d.ts.map +1 -0
- package/lib/dist/upgrade/index.js +462 -0
- package/lib/dist/upgrade/index.js.map +1 -0
- package/lib/dist/utils.d.ts +30 -24
- package/lib/dist/utils.d.ts.map +1 -1
- package/lib/dist/utils.js +64 -48
- package/lib/dist/utils.js.map +1 -1
- package/lib/node_modules/.package-lock.json +1 -29
- package/lib/package.json +1 -2
- package/package.json +1 -1
- package/lib/node_modules/chokidar/LICENSE +0 -21
- package/lib/node_modules/chokidar/README.md +0 -305
- package/lib/node_modules/chokidar/esm/handler.d.ts +0 -90
- package/lib/node_modules/chokidar/esm/handler.js +0 -629
- package/lib/node_modules/chokidar/esm/index.d.ts +0 -215
- package/lib/node_modules/chokidar/esm/index.js +0 -798
- package/lib/node_modules/chokidar/esm/package.json +0 -1
- package/lib/node_modules/chokidar/handler.d.ts +0 -90
- package/lib/node_modules/chokidar/handler.js +0 -635
- package/lib/node_modules/chokidar/index.d.ts +0 -215
- package/lib/node_modules/chokidar/index.js +0 -804
- package/lib/node_modules/chokidar/package.json +0 -69
- package/lib/node_modules/readdirp/LICENSE +0 -21
- package/lib/node_modules/readdirp/README.md +0 -120
- package/lib/node_modules/readdirp/esm/index.d.ts +0 -108
- package/lib/node_modules/readdirp/esm/index.js +0 -257
- package/lib/node_modules/readdirp/esm/package.json +0 -1
- package/lib/node_modules/readdirp/index.d.ts +0 -108
- package/lib/node_modules/readdirp/index.js +0 -263
- package/lib/node_modules/readdirp/package.json +0 -70
|
@@ -51,8 +51,22 @@ const frameworks_1 = require("./frameworks");
|
|
|
51
51
|
const callback_synthesizer_1 = require("./callback-synthesizer");
|
|
52
52
|
const path_aliases_1 = require("./path-aliases");
|
|
53
53
|
const go_module_1 = require("./go-module");
|
|
54
|
+
const workspace_packages_1 = require("./workspace-packages");
|
|
54
55
|
const errors_1 = require("../errors");
|
|
55
56
|
const lru_cache_1 = require("./lru-cache");
|
|
57
|
+
/** Node kinds that can declare supertypes (extends/implements). */
|
|
58
|
+
const SUPERTYPE_BEARING_KINDS = new Set([
|
|
59
|
+
'class', 'struct', 'interface', 'trait', 'protocol', 'enum',
|
|
60
|
+
]);
|
|
61
|
+
/**
|
|
62
|
+
* Languages whose chained static-factory/fluent calls defer to the conformance
|
|
63
|
+
* second pass. Dotted-receiver languages resolve via matchDottedCallChain; the
|
|
64
|
+
* `::`-receiver ones (Rust) via matchScopedCallChain.
|
|
65
|
+
*/
|
|
66
|
+
const CHAIN_LANGUAGES = new Set(['java', 'kotlin', 'csharp', 'swift', 'rust', 'go', 'scala', 'dart', 'objc', 'pascal']);
|
|
67
|
+
const SCOPED_CHAIN_LANGUAGES = new Set(['rust']);
|
|
68
|
+
/** The extractor's chained-receiver encoding: `<inner>().<method>`. */
|
|
69
|
+
const CHAIN_SHAPE = /^(.+)\(\)\.(\w+)$/;
|
|
56
70
|
/**
|
|
57
71
|
* Cache size limits. Each per-resolver cache is bounded so memory
|
|
58
72
|
* stays flat on large codebases (20k+ files). Sizes were chosen to
|
|
@@ -200,6 +214,21 @@ class ReferenceResolver {
|
|
|
200
214
|
queries;
|
|
201
215
|
context;
|
|
202
216
|
frameworks = [];
|
|
217
|
+
// Chained static-factory/fluent call refs the first pass couldn't resolve,
|
|
218
|
+
// collected in-memory (the batched resolver deletes unresolved refs from the
|
|
219
|
+
// DB, so they can't be re-read). Drained by resolveChainedCallsViaConformance
|
|
220
|
+
// once implements/extends edges exist, to resolve methods on a supertype the
|
|
221
|
+
// receiver conforms to (#750).
|
|
222
|
+
deferredChainRefs = [];
|
|
223
|
+
// `this.<member>` function-as-value refs whose member is NOT on the
|
|
224
|
+
// enclosing class itself — possibly inherited. Collected in-memory for the
|
|
225
|
+
// same reason as deferredChainRefs and drained by
|
|
226
|
+
// resolveDeferredThisMemberRefs once implements/extends edges exist (#808).
|
|
227
|
+
deferredThisMemberRefs = [];
|
|
228
|
+
// Per-`.razor`/`.cshtml`-file `@using` namespace set (own directives + folder
|
|
229
|
+
// `_Imports.razor`, cascading to the project root). Used to disambiguate a
|
|
230
|
+
// markup type ref to the right C# namespace.
|
|
231
|
+
razorUsingsCache = new Map();
|
|
203
232
|
// All per-resolver caches are LRU-bounded. Previously these were
|
|
204
233
|
// unbounded Maps that grew with every distinct lookup and OOM'd on
|
|
205
234
|
// codebases with 20k+ files (see issue: unbounded cache growth).
|
|
@@ -219,6 +248,8 @@ class ReferenceResolver {
|
|
|
219
248
|
projectAliases = undefined;
|
|
220
249
|
// go.mod module path. Same lazy/immutable convention as projectAliases.
|
|
221
250
|
goModule = undefined;
|
|
251
|
+
// Monorepo workspace member packages. Same lazy/immutable convention.
|
|
252
|
+
workspacePackages = undefined;
|
|
222
253
|
constructor(projectRoot, queries) {
|
|
223
254
|
this.projectRoot = projectRoot;
|
|
224
255
|
this.queries = queries;
|
|
@@ -397,6 +428,29 @@ class ReferenceResolver {
|
|
|
397
428
|
this.lowerNameCache.set(lowerName, result);
|
|
398
429
|
return result;
|
|
399
430
|
},
|
|
431
|
+
getNodeById: (id) => {
|
|
432
|
+
return this.queries.getNodeById(id);
|
|
433
|
+
},
|
|
434
|
+
getSupertypes: (typeName, language) => {
|
|
435
|
+
// Union the `implements`/`extends` targets of every same-named type node.
|
|
436
|
+
// Matching by simple name (not id) reconciles a type declared in one node
|
|
437
|
+
// (`KF::Builder`) with conformance declared in a separate extension node
|
|
438
|
+
// (`KF.Builder: KFOptionSetter`) — both have name `Builder`.
|
|
439
|
+
const typeNodes = this.context
|
|
440
|
+
.getNodesByName(typeName)
|
|
441
|
+
.filter((n) => SUPERTYPE_BEARING_KINDS.has(n.kind) && n.language === language);
|
|
442
|
+
if (typeNodes.length === 0)
|
|
443
|
+
return [];
|
|
444
|
+
const supertypes = new Set();
|
|
445
|
+
for (const tn of typeNodes) {
|
|
446
|
+
for (const edge of this.queries.getOutgoingEdges(tn.id, ['implements', 'extends'])) {
|
|
447
|
+
const target = this.queries.getNodeById(edge.target);
|
|
448
|
+
if (target?.name && target.name !== typeName)
|
|
449
|
+
supertypes.add(target.name);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return [...supertypes];
|
|
453
|
+
},
|
|
400
454
|
getImportMappings: (filePath, language) => {
|
|
401
455
|
const cacheKey = filePath;
|
|
402
456
|
const cached = this.importMappingCache.get(cacheKey);
|
|
@@ -423,6 +477,12 @@ class ReferenceResolver {
|
|
|
423
477
|
}
|
|
424
478
|
return this.goModule;
|
|
425
479
|
},
|
|
480
|
+
getWorkspacePackages: () => {
|
|
481
|
+
if (this.workspacePackages === undefined) {
|
|
482
|
+
this.workspacePackages = (0, workspace_packages_1.loadWorkspacePackages)(this.projectRoot);
|
|
483
|
+
}
|
|
484
|
+
return this.workspacePackages;
|
|
485
|
+
},
|
|
426
486
|
getReExports: (filePath, language) => {
|
|
427
487
|
const cached = this.reExportCache.get(filePath);
|
|
428
488
|
if (cached)
|
|
@@ -432,7 +492,15 @@ class ReferenceResolver {
|
|
|
432
492
|
this.reExportCache.set(filePath, []);
|
|
433
493
|
return [];
|
|
434
494
|
}
|
|
435
|
-
|
|
495
|
+
// Re-exports are a JS/TS-only construct, and what matters is the
|
|
496
|
+
// BARREL file's own language — not the consuming reference's. A
|
|
497
|
+
// `.svelte`/`.vue` consumer threads its own language down the
|
|
498
|
+
// re-export chase, which would make extractReExports() bail on a
|
|
499
|
+
// `.ts` index barrel and silently break the chain (#629). Re-key
|
|
500
|
+
// the parse on the barrel's extension so the chase works no matter
|
|
501
|
+
// what kind of file imports through it.
|
|
502
|
+
const isJsFamily = /\.(?:d\.ts|[cm]?tsx?|[cm]?jsx?)$/i.test(filePath);
|
|
503
|
+
const reExports = (0, import_resolver_1.extractReExports)(content, isJsFamily ? 'typescript' : language);
|
|
436
504
|
this.reExportCache.set(filePath, reExports);
|
|
437
505
|
return reExports;
|
|
438
506
|
},
|
|
@@ -534,6 +602,17 @@ class ReferenceResolver {
|
|
|
534
602
|
const member = name.substring(colonIdx + 2);
|
|
535
603
|
if (this.knownNames.has(receiver) || this.knownNames.has(member))
|
|
536
604
|
return true;
|
|
605
|
+
// Multi-segment path `a::b::c` (a Rust/C++ module call like
|
|
606
|
+
// `database::profiles::find`) — the only segment that names a symbol is
|
|
607
|
+
// the last (`c`); `member` above is `b::c`, which never matches a node
|
|
608
|
+
// name, so without this the pre-filter drops the ref before the Rust path
|
|
609
|
+
// resolver ever sees it. Mirror the dotted-name leaf check above.
|
|
610
|
+
const lastColon = name.lastIndexOf('::');
|
|
611
|
+
if (lastColon > colonIdx) {
|
|
612
|
+
const tail = name.substring(lastColon + 2);
|
|
613
|
+
if (tail && this.knownNames.has(tail))
|
|
614
|
+
return true;
|
|
615
|
+
}
|
|
537
616
|
}
|
|
538
617
|
// For path-like references (e.g., "snippets/drawer-menu.liquid"), check the filename
|
|
539
618
|
const slashIdx = name.lastIndexOf('/');
|
|
@@ -580,16 +659,50 @@ class ReferenceResolver {
|
|
|
580
659
|
!this.frameworks.some((f) => f.claimsReference?.(ref.referenceName))) {
|
|
581
660
|
return null;
|
|
582
661
|
}
|
|
662
|
+
// Function-as-value refs (#756) get a dedicated, strictly-gated path:
|
|
663
|
+
// import-based resolution first (an imported callback resolves through its
|
|
664
|
+
// import, the most precise cross-file signal), then matchFunctionRef
|
|
665
|
+
// (same-file first, unique-only cross-file, function/method targets only).
|
|
666
|
+
// They never reach the framework or fuzzy strategies below.
|
|
667
|
+
if (ref.referenceKind === 'function_ref') {
|
|
668
|
+
// `this.<member>` values (TS/JS) resolve ONLY against the enclosing
|
|
669
|
+
// class's own members — never a same-named symbol elsewhere.
|
|
670
|
+
if (ref.referenceName.startsWith('this.')) {
|
|
671
|
+
return this.gateLanguage(this.resolveThisMemberFnRef(ref), ref);
|
|
672
|
+
}
|
|
673
|
+
const viaImport = this.gateLanguage((0, import_resolver_1.resolveViaImport)(ref, this.context), ref);
|
|
674
|
+
if (viaImport) {
|
|
675
|
+
const target = this.queries.getNodeById(viaImport.targetNodeId);
|
|
676
|
+
if (target && (target.kind === 'function' || target.kind === 'method')) {
|
|
677
|
+
return viaImport;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
return this.gateLanguage((0, name_matcher_1.matchFunctionRef)(ref, this.context), ref);
|
|
681
|
+
}
|
|
583
682
|
// JVM FQN imports skip framework/name-matcher: `import com.example.Bar`
|
|
584
683
|
// resolves directly through the qualifiedName index, which is unambiguous
|
|
585
684
|
// even when several `Bar` classes exist in different packages.
|
|
586
685
|
const jvmImport = (0, import_resolver_1.resolveJvmImport)(ref, this.context);
|
|
587
686
|
if (jvmImport)
|
|
588
687
|
return jvmImport;
|
|
688
|
+
// Razor/Blazor: a markup or `@code` type ref resolves through the file's
|
|
689
|
+
// `@using` namespaces (incl. folder `_Imports.razor`). This precisely
|
|
690
|
+
// disambiguates a simple name that exists in several namespaces — e.g.
|
|
691
|
+
// `CatalogBrand` resolving to `BlazorShared.Models::CatalogBrand` (the DTO,
|
|
692
|
+
// which the `.razor` `@using`s) rather than the same-named domain entity.
|
|
693
|
+
if (ref.language === 'razor') {
|
|
694
|
+
const razorResult = this.resolveRazorUsing(ref);
|
|
695
|
+
if (razorResult)
|
|
696
|
+
return razorResult;
|
|
697
|
+
}
|
|
589
698
|
const candidates = [];
|
|
590
|
-
// Strategy 1: Try framework-specific resolution
|
|
699
|
+
// Strategy 1: Try framework-specific resolution. Cross-language bridges
|
|
700
|
+
// are deliberately preserved (Drupal `routing.yml` → PHP controller, RN
|
|
701
|
+
// JS → native `calls`) — `gateFrameworkLanguage` only drops a type/import
|
|
702
|
+
// edge between two KNOWN families (see its doc), never a `calls` bridge or
|
|
703
|
+
// a config↔code edge.
|
|
591
704
|
for (const framework of this.frameworks) {
|
|
592
|
-
const result = framework.resolve(ref, this.context);
|
|
705
|
+
const result = this.gateFrameworkLanguage(framework.resolve(ref, this.context), ref);
|
|
593
706
|
if (result) {
|
|
594
707
|
if (result.confidence >= 0.9)
|
|
595
708
|
return result; // High confidence, return immediately
|
|
@@ -597,19 +710,37 @@ class ReferenceResolver {
|
|
|
597
710
|
}
|
|
598
711
|
}
|
|
599
712
|
// Strategy 2: Try import-based resolution
|
|
600
|
-
const importResult = (0, import_resolver_1.resolveViaImport)(ref, this.context);
|
|
713
|
+
const importResult = this.gateLanguage((0, import_resolver_1.resolveViaImport)(ref, this.context), ref);
|
|
601
714
|
if (importResult) {
|
|
602
715
|
if (importResult.confidence >= 0.9)
|
|
603
716
|
return importResult;
|
|
604
717
|
candidates.push(importResult);
|
|
605
718
|
}
|
|
719
|
+
// PHP include/require paths resolve to files via import resolution only.
|
|
720
|
+
// If that didn't find the file, do NOT fall back to the symbol
|
|
721
|
+
// name-matcher — it would mis-connect e.g. "inc/db.php" to an unrelated
|
|
722
|
+
// db.php elsewhere in the tree (a wrong edge is worse than none, #660).
|
|
723
|
+
if ((0, import_resolver_1.isPhpIncludePathRef)(ref)) {
|
|
724
|
+
return candidates.length > 0
|
|
725
|
+
? candidates.reduce((best, curr) => curr.confidence > best.confidence ? curr : best)
|
|
726
|
+
: null;
|
|
727
|
+
}
|
|
606
728
|
// Strategy 3: Try name matching
|
|
607
|
-
const nameResult = (0, name_matcher_1.matchReference)(ref, this.context);
|
|
729
|
+
const nameResult = this.gateLanguage((0, name_matcher_1.matchReference)(ref, this.context), ref);
|
|
608
730
|
if (nameResult) {
|
|
609
731
|
candidates.push(nameResult);
|
|
610
732
|
}
|
|
611
|
-
if (candidates.length === 0)
|
|
733
|
+
if (candidates.length === 0) {
|
|
734
|
+
// Defer a chained static-factory/fluent call the first pass couldn't
|
|
735
|
+
// resolve — its method may live on a supertype the receiver conforms to,
|
|
736
|
+
// resolvable once implements/extends edges exist (the conformance pass).
|
|
737
|
+
if (ref.referenceKind === 'calls' &&
|
|
738
|
+
CHAIN_LANGUAGES.has(ref.language) &&
|
|
739
|
+
CHAIN_SHAPE.test(ref.referenceName)) {
|
|
740
|
+
this.deferredChainRefs.push(ref);
|
|
741
|
+
}
|
|
612
742
|
return null;
|
|
743
|
+
}
|
|
613
744
|
// Return highest confidence candidate
|
|
614
745
|
return candidates.reduce((best, curr) => curr.confidence > best.confidence ? curr : best);
|
|
615
746
|
}
|
|
@@ -618,7 +749,12 @@ class ReferenceResolver {
|
|
|
618
749
|
*/
|
|
619
750
|
createEdges(resolved) {
|
|
620
751
|
return resolved.map((ref) => {
|
|
621
|
-
|
|
752
|
+
// `function_ref` (#756) is internal-only: it persists as a `references`
|
|
753
|
+
// edge (the registration site depends on the callback), distinguishable
|
|
754
|
+
// by metadata.resolvedBy === 'function-ref'. callers/impact already
|
|
755
|
+
// traverse `references`, so registration sites surface with no
|
|
756
|
+
// graph-layer changes.
|
|
757
|
+
let kind = ref.original.referenceKind === 'function_ref' ? 'references' : ref.original.referenceKind;
|
|
622
758
|
// Promote "extends" to "implements" when a class/struct targets an interface
|
|
623
759
|
if (kind === 'extends') {
|
|
624
760
|
const targetNode = this.queries.getNodeById(ref.targetNodeId);
|
|
@@ -649,6 +785,11 @@ class ReferenceResolver {
|
|
|
649
785
|
metadata: {
|
|
650
786
|
confidence: ref.confidence,
|
|
651
787
|
resolvedBy: ref.resolvedBy,
|
|
788
|
+
// Uniform marker for function-as-value edges (#756), regardless of
|
|
789
|
+
// which strategy resolved them (import vs matchFunctionRef) — lets
|
|
790
|
+
// tooling label "callback registration" and lets validation diff
|
|
791
|
+
// exactly the edges this feature added.
|
|
792
|
+
...(ref.original.referenceKind === 'function_ref' ? { fnRef: true } : {}),
|
|
652
793
|
},
|
|
653
794
|
};
|
|
654
795
|
});
|
|
@@ -674,6 +815,48 @@ class ReferenceResolver {
|
|
|
674
815
|
}
|
|
675
816
|
return result;
|
|
676
817
|
}
|
|
818
|
+
/**
|
|
819
|
+
* Second resolution pass for chained static-factory / fluent calls whose
|
|
820
|
+
* chained method is defined on a SUPERTYPE the receiver's type conforms to —
|
|
821
|
+
* a protocol-extension / inherited / default-interface method (#750). The
|
|
822
|
+
* first pass can't resolve these because `implements`/`extends` edges aren't
|
|
823
|
+
* built yet; this runs AFTER edges are persisted, so `context.getSupertypes`
|
|
824
|
+
* (and the conformance fallback in resolveMethodOnType) can walk them.
|
|
825
|
+
*
|
|
826
|
+
* Operates only on the leftover unresolved refs that have the `inner().method`
|
|
827
|
+
* chain shape, for the dotted-chain languages — a small set — and is idempotent
|
|
828
|
+
* (re-resolving an already-resolved ref is a no-op since it's been deleted).
|
|
829
|
+
* Returns the number of newly-created edges.
|
|
830
|
+
*/
|
|
831
|
+
resolveChainedCallsViaConformance() {
|
|
832
|
+
const deferred = this.deferredChainRefs;
|
|
833
|
+
this.deferredChainRefs = [];
|
|
834
|
+
if (deferred.length === 0)
|
|
835
|
+
return 0;
|
|
836
|
+
// Read fresh edges (the main pass built the implements/extends edges after
|
|
837
|
+
// these refs were deferred). matchDottedCallChain now resolves a method on a
|
|
838
|
+
// supertype via context.getSupertypes -> resolveMethodOnType's conformance walk.
|
|
839
|
+
this.clearCaches();
|
|
840
|
+
const resolved = [];
|
|
841
|
+
for (const ref of deferred) {
|
|
842
|
+
// `::`-receiver languages (Rust) split on `::` (matchScopedCallChain);
|
|
843
|
+
// dotted-receiver languages on `.` (matchDottedCallChain).
|
|
844
|
+
const chainMatch = SCOPED_CHAIN_LANGUAGES.has(ref.language)
|
|
845
|
+
? (0, name_matcher_1.matchScopedCallChain)(ref, this.context)
|
|
846
|
+
: (0, name_matcher_1.matchDottedCallChain)(ref, this.context);
|
|
847
|
+
const match = this.gateLanguage(chainMatch, ref);
|
|
848
|
+
if (match)
|
|
849
|
+
resolved.push(match);
|
|
850
|
+
}
|
|
851
|
+
if (resolved.length === 0)
|
|
852
|
+
return 0;
|
|
853
|
+
const edges = this.createEdges(resolved);
|
|
854
|
+
if (edges.length > 0) {
|
|
855
|
+
this.queries.insertEdges(edges);
|
|
856
|
+
this.clearCaches();
|
|
857
|
+
}
|
|
858
|
+
return edges.length;
|
|
859
|
+
}
|
|
677
860
|
/**
|
|
678
861
|
* Resolve and persist in batches to keep memory bounded.
|
|
679
862
|
* Processes unresolved references in chunks, persisting edges and cleaning
|
|
@@ -691,6 +874,7 @@ class ReferenceResolver {
|
|
|
691
874
|
};
|
|
692
875
|
// Process in batches. We always read from offset 0 because resolved refs
|
|
693
876
|
// are deleted after each batch, shifting the remaining rows forward.
|
|
877
|
+
let prevRemaining = Number.POSITIVE_INFINITY;
|
|
694
878
|
while (true) {
|
|
695
879
|
const batch = this.queries.getUnresolvedReferencesBatch(0, batchSize);
|
|
696
880
|
if (batch.length === 0)
|
|
@@ -733,6 +917,18 @@ class ReferenceResolver {
|
|
|
733
917
|
if (result.resolved.length === 0 && result.unresolved.length === batch.length) {
|
|
734
918
|
break;
|
|
735
919
|
}
|
|
920
|
+
// Non-progress guard (defense-in-depth). Because we re-read from offset 0
|
|
921
|
+
// each pass, the unresolved_refs table MUST shrink every iteration — both
|
|
922
|
+
// resolved and unresolved refs are deleted above. If it didn't shrink, a
|
|
923
|
+
// resolver returned a match whose `original.referenceName` differs from the
|
|
924
|
+
// stored row, so the keyed delete no-ops, and we'd re-read + re-resolve +
|
|
925
|
+
// re-insert the same rows forever (the runaway that grew a 99-file repo to
|
|
926
|
+
// 5M edges / 1.4 GB before the Go-fallback fix). Stop rather than grow the
|
|
927
|
+
// graph without bound.
|
|
928
|
+
const remaining = this.queries.getUnresolvedReferencesCount();
|
|
929
|
+
if (remaining >= prevRemaining)
|
|
930
|
+
break;
|
|
931
|
+
prevRemaining = remaining;
|
|
736
932
|
}
|
|
737
933
|
// Dynamic-edge synthesis: now that all base `calls` edges are persisted,
|
|
738
934
|
// synthesize observer/callback dispatch edges (dispatcher → registered
|
|
@@ -865,6 +1061,260 @@ class ReferenceResolver {
|
|
|
865
1061
|
const node = this.queries.getNodeById(nodeId);
|
|
866
1062
|
return node?.language || 'unknown';
|
|
867
1063
|
}
|
|
1064
|
+
/**
|
|
1065
|
+
* Drop an import/name-strategy resolution that crosses a language family.
|
|
1066
|
+
* Two regimes (mirrors `applyLanguageGate`'s candidate filter):
|
|
1067
|
+
* - `references` (type usage): STRICT — a `Type.member` static read names a
|
|
1068
|
+
* same-family type, never a coincidentally same-named symbol in another
|
|
1069
|
+
* language. Drops any non-same-family target.
|
|
1070
|
+
* - `imports` (import binding / `#include`): both-known — a C++ `#include
|
|
1071
|
+
* "X.h"` must not resolve to a same-named ObjC header on another platform
|
|
1072
|
+
* (basename collision), but a singleton-family / SFC language (`vue` →
|
|
1073
|
+
* `.ts`) importing across is left alone.
|
|
1074
|
+
* Applies to the import (strategy 2) + name-match (strategy 3) results.
|
|
1075
|
+
*/
|
|
1076
|
+
/**
|
|
1077
|
+
* Collect the `@using` namespaces in scope for a `.razor`/`.cshtml` file: its
|
|
1078
|
+
* own `@using` directives plus every `_Imports.razor` from the file's folder up
|
|
1079
|
+
* to the project root (Razor `_Imports` cascade). Cached per file.
|
|
1080
|
+
*/
|
|
1081
|
+
getRazorUsings(filePath) {
|
|
1082
|
+
const cached = this.razorUsingsCache.get(filePath);
|
|
1083
|
+
if (cached)
|
|
1084
|
+
return cached;
|
|
1085
|
+
const usings = new Set();
|
|
1086
|
+
const addFrom = (src) => {
|
|
1087
|
+
if (!src)
|
|
1088
|
+
return;
|
|
1089
|
+
for (const m of src.matchAll(/^\s*@using\s+(?:static\s+)?([A-Za-z_][\w.]*)/gm))
|
|
1090
|
+
usings.add(m[1]);
|
|
1091
|
+
};
|
|
1092
|
+
addFrom(this.context.readFile(filePath));
|
|
1093
|
+
let dir = filePath.includes('/') ? filePath.slice(0, filePath.lastIndexOf('/')) : '';
|
|
1094
|
+
// Walk up to the project root, reading each level's _Imports.razor.
|
|
1095
|
+
for (;;) {
|
|
1096
|
+
addFrom(this.context.readFile(dir ? `${dir}/_Imports.razor` : '_Imports.razor'));
|
|
1097
|
+
if (!dir)
|
|
1098
|
+
break;
|
|
1099
|
+
const slash = dir.lastIndexOf('/');
|
|
1100
|
+
dir = slash >= 0 ? dir.slice(0, slash) : '';
|
|
1101
|
+
}
|
|
1102
|
+
const arr = [...usings];
|
|
1103
|
+
this.razorUsingsCache.set(filePath, arr);
|
|
1104
|
+
return arr;
|
|
1105
|
+
}
|
|
1106
|
+
/**
|
|
1107
|
+
* Resolve a Razor/Blazor simple type ref through the file's `@using`
|
|
1108
|
+
* namespaces: `CatalogBrand` + `@using BlazorShared.Models` → the node whose
|
|
1109
|
+
* qualified name is `BlazorShared.Models::CatalogBrand`. Only resolves when the
|
|
1110
|
+
* `@using` set yields exactly ONE type (otherwise it stays ambiguous and falls
|
|
1111
|
+
* through to name-matching).
|
|
1112
|
+
*/
|
|
1113
|
+
resolveRazorUsing(ref) {
|
|
1114
|
+
if (ref.referenceName.includes('.') || ref.referenceName.includes('::'))
|
|
1115
|
+
return null;
|
|
1116
|
+
const usings = this.getRazorUsings(ref.filePath);
|
|
1117
|
+
if (usings.length === 0)
|
|
1118
|
+
return null;
|
|
1119
|
+
const found = new Map();
|
|
1120
|
+
for (const ns of usings) {
|
|
1121
|
+
for (const cand of this.context.getNodesByQualifiedName(`${ns}::${ref.referenceName}`)) {
|
|
1122
|
+
found.set(cand.id, cand);
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
if (found.size !== 1)
|
|
1126
|
+
return null;
|
|
1127
|
+
const target = found.values().next().value;
|
|
1128
|
+
return { original: ref, targetNodeId: target.id, confidence: 0.9, resolvedBy: 'import' };
|
|
1129
|
+
}
|
|
1130
|
+
/**
|
|
1131
|
+
* Resolve a `this.<member>` function-as-value reference (#756/#808) to the
|
|
1132
|
+
* ENCLOSING CLASS's own member — never a same-named symbol elsewhere. The
|
|
1133
|
+
* registration idiom (`btn.on('click', this.handleClick)`) names a member
|
|
1134
|
+
* of the class being defined, so the only valid target shares the
|
|
1135
|
+
* from-symbol's qualified-name scope. Function/method targets only — a
|
|
1136
|
+
* property (a data field, post-#808 classification) yields no edge — same
|
|
1137
|
+
* file required, no fallback of any kind.
|
|
1138
|
+
*/
|
|
1139
|
+
resolveThisMemberFnRef(ref) {
|
|
1140
|
+
const member = ref.referenceName.slice('this.'.length);
|
|
1141
|
+
if (!member)
|
|
1142
|
+
return null;
|
|
1143
|
+
const fromNode = this.queries.getNodeById(ref.fromNodeId);
|
|
1144
|
+
if (!fromNode)
|
|
1145
|
+
return null;
|
|
1146
|
+
// A hook declared at class-body level (Ruby `before_action :authenticate`)
|
|
1147
|
+
// attributes to the CLASS node itself — its qualified name IS the scope.
|
|
1148
|
+
// For members, strip the member segment.
|
|
1149
|
+
let classPrefix;
|
|
1150
|
+
if (SUPERTYPE_BEARING_KINDS.has(fromNode.kind) || fromNode.kind === 'module') {
|
|
1151
|
+
classPrefix = fromNode.qualifiedName;
|
|
1152
|
+
}
|
|
1153
|
+
else {
|
|
1154
|
+
const sep = fromNode.qualifiedName.lastIndexOf('::');
|
|
1155
|
+
if (sep <= 0)
|
|
1156
|
+
return null; // not inside a class scope
|
|
1157
|
+
classPrefix = fromNode.qualifiedName.slice(0, sep);
|
|
1158
|
+
}
|
|
1159
|
+
const candidates = this.context
|
|
1160
|
+
.getNodesByQualifiedName(`${classPrefix}::${member}`)
|
|
1161
|
+
.filter((n) => (n.kind === 'function' || n.kind === 'method') &&
|
|
1162
|
+
n.filePath === ref.filePath &&
|
|
1163
|
+
n.id !== ref.fromNodeId);
|
|
1164
|
+
if (candidates.length === 0) {
|
|
1165
|
+
// Not on the class itself — possibly INHERITED. implements/extends
|
|
1166
|
+
// edges don't exist yet in this pass, so retry in the supertype pass
|
|
1167
|
+
// (resolveDeferredThisMemberRefs) instead of giving up.
|
|
1168
|
+
this.deferredThisMemberRefs.push(ref);
|
|
1169
|
+
return null;
|
|
1170
|
+
}
|
|
1171
|
+
const target = candidates.reduce((a, b) => (a.startLine <= b.startLine ? a : b));
|
|
1172
|
+
return {
|
|
1173
|
+
original: ref,
|
|
1174
|
+
targetNodeId: target.id,
|
|
1175
|
+
confidence: 0.95,
|
|
1176
|
+
resolvedBy: 'function-ref',
|
|
1177
|
+
};
|
|
1178
|
+
}
|
|
1179
|
+
/**
|
|
1180
|
+
* Second pass for `this.<member>` refs whose member wasn't on the enclosing
|
|
1181
|
+
* class itself (#808): once implements/extends edges exist, walk the
|
|
1182
|
+
* class's supertypes (transitively, depth-capped) and resolve the member on
|
|
1183
|
+
* the nearest one that declares it — `this.handleSubmit` registered in a
|
|
1184
|
+
* subclass resolves to `FormBase::handleSubmit`. Validated targets only
|
|
1185
|
+
* (function/method kind, same language family); no match → no edge.
|
|
1186
|
+
* Mirrors resolveChainedCallsViaConformance's lifecycle. Returns the number
|
|
1187
|
+
* of newly-created edges.
|
|
1188
|
+
*/
|
|
1189
|
+
resolveDeferredThisMemberRefs() {
|
|
1190
|
+
const deferred = this.deferredThisMemberRefs;
|
|
1191
|
+
this.deferredThisMemberRefs = [];
|
|
1192
|
+
if (deferred.length === 0)
|
|
1193
|
+
return 0;
|
|
1194
|
+
this.clearCaches();
|
|
1195
|
+
const resolved = [];
|
|
1196
|
+
for (const ref of deferred) {
|
|
1197
|
+
const member = ref.referenceName.slice('this.'.length);
|
|
1198
|
+
const fromNode = this.queries.getNodeById(ref.fromNodeId);
|
|
1199
|
+
if (!fromNode || !member)
|
|
1200
|
+
continue;
|
|
1201
|
+
// Class-body-level hooks (Ruby) attribute to the CLASS node itself.
|
|
1202
|
+
let className;
|
|
1203
|
+
if (SUPERTYPE_BEARING_KINDS.has(fromNode.kind) || fromNode.kind === 'module') {
|
|
1204
|
+
className = fromNode.name;
|
|
1205
|
+
}
|
|
1206
|
+
else {
|
|
1207
|
+
const sep = fromNode.qualifiedName.lastIndexOf('::');
|
|
1208
|
+
if (sep <= 0)
|
|
1209
|
+
continue;
|
|
1210
|
+
const classPrefix = fromNode.qualifiedName.slice(0, sep);
|
|
1211
|
+
className = classPrefix.includes('::')
|
|
1212
|
+
? classPrefix.slice(classPrefix.lastIndexOf('::') + 2)
|
|
1213
|
+
: classPrefix;
|
|
1214
|
+
}
|
|
1215
|
+
// NODE-anchored BFS up the supertype graph: start from the class node
|
|
1216
|
+
// in the ref's own file (never a same-named class elsewhere — rails has
|
|
1217
|
+
// a dozen `Engine`s), follow implements/extends EDGES to supertype
|
|
1218
|
+
// NODES, and look members up through `contains` edges. No name-based
|
|
1219
|
+
// unions anywhere — a name-keyed getSupertypes('Engine') merged every
|
|
1220
|
+
// Engine's parents and produced a cross-class wrong edge on rails.
|
|
1221
|
+
let frontierNodes = this.context
|
|
1222
|
+
.getNodesByName(className)
|
|
1223
|
+
.filter((n) => SUPERTYPE_BEARING_KINDS.has(n.kind) &&
|
|
1224
|
+
n.filePath === ref.filePath);
|
|
1225
|
+
if (frontierNodes.length === 0) {
|
|
1226
|
+
// The class itself may be declared in another file (partial/reopened
|
|
1227
|
+
// classes); fall back to same-family nodes of that name.
|
|
1228
|
+
frontierNodes = this.context
|
|
1229
|
+
.getNodesByName(className)
|
|
1230
|
+
.filter((n) => SUPERTYPE_BEARING_KINDS.has(n.kind) &&
|
|
1231
|
+
(0, name_matcher_1.sameLanguageFamily)(n.language, ref.language));
|
|
1232
|
+
}
|
|
1233
|
+
const seenNodes = new Set(frontierNodes.map((n) => n.id));
|
|
1234
|
+
let target = null;
|
|
1235
|
+
for (let depth = 0; depth < 5 && frontierNodes.length > 0 && !target; depth++) {
|
|
1236
|
+
const next = [];
|
|
1237
|
+
for (const typeNode of frontierNodes) {
|
|
1238
|
+
for (const edge of this.queries.getOutgoingEdges(typeNode.id, ['implements', 'extends'])) {
|
|
1239
|
+
const superNode = this.queries.getNodeById(edge.target);
|
|
1240
|
+
if (!superNode || seenNodes.has(superNode.id))
|
|
1241
|
+
continue;
|
|
1242
|
+
seenNodes.add(superNode.id);
|
|
1243
|
+
if (!SUPERTYPE_BEARING_KINDS.has(superNode.kind))
|
|
1244
|
+
continue;
|
|
1245
|
+
// Member lookup anchored on the supertype's contains edges.
|
|
1246
|
+
for (const c of this.queries.getOutgoingEdges(superNode.id, ['contains'])) {
|
|
1247
|
+
const m = this.queries.getNodeById(c.target);
|
|
1248
|
+
if (m &&
|
|
1249
|
+
m.name === member &&
|
|
1250
|
+
(m.kind === 'function' || m.kind === 'method') &&
|
|
1251
|
+
(0, name_matcher_1.sameLanguageFamily)(m.language, ref.language)) {
|
|
1252
|
+
target = m;
|
|
1253
|
+
break;
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
if (target)
|
|
1257
|
+
break;
|
|
1258
|
+
next.push(superNode);
|
|
1259
|
+
}
|
|
1260
|
+
if (target)
|
|
1261
|
+
break;
|
|
1262
|
+
}
|
|
1263
|
+
frontierNodes = next;
|
|
1264
|
+
}
|
|
1265
|
+
if (target) {
|
|
1266
|
+
resolved.push({
|
|
1267
|
+
original: ref,
|
|
1268
|
+
targetNodeId: target.id,
|
|
1269
|
+
confidence: 0.85,
|
|
1270
|
+
resolvedBy: 'function-ref',
|
|
1271
|
+
});
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
if (resolved.length === 0)
|
|
1275
|
+
return 0;
|
|
1276
|
+
const edges = this.createEdges(resolved);
|
|
1277
|
+
if (edges.length > 0) {
|
|
1278
|
+
this.queries.insertEdges(edges);
|
|
1279
|
+
this.clearCaches();
|
|
1280
|
+
}
|
|
1281
|
+
return edges.length;
|
|
1282
|
+
}
|
|
1283
|
+
gateLanguage(result, ref) {
|
|
1284
|
+
if (!result)
|
|
1285
|
+
return result;
|
|
1286
|
+
const tgt = this.getLanguageFromNodeId(result.targetNodeId);
|
|
1287
|
+
if (!tgt || !ref.language)
|
|
1288
|
+
return result;
|
|
1289
|
+
if ((ref.referenceKind === 'references' || ref.referenceKind === 'function_ref') && !(0, name_matcher_1.sameLanguageFamily)(tgt, ref.language))
|
|
1290
|
+
return null;
|
|
1291
|
+
if (ref.referenceKind === 'imports' && (0, name_matcher_1.crossesKnownFamily)(tgt, ref.language))
|
|
1292
|
+
return null;
|
|
1293
|
+
return result;
|
|
1294
|
+
}
|
|
1295
|
+
/**
|
|
1296
|
+
* Drop a FRAMEWORK-strategy resolution that crosses two *known* language
|
|
1297
|
+
* families for a type-usage (`references`) or import-binding (`imports`)
|
|
1298
|
+
* edge. The framework strategy is intentionally ungated for cross-language
|
|
1299
|
+
* bridges, but those legitimate bridges are either `calls` edges (RN/Expo
|
|
1300
|
+
* JS → native) or config↔code edges whose config side (`yaml`/`blade`/…) is
|
|
1301
|
+
* not a known programming-language family. A `references`/`imports` edge
|
|
1302
|
+
* between two *known* families is always a coincidental name collision — the
|
|
1303
|
+
* React/Svelte/Vue PascalCase component resolvers name-match `getNodesByName`
|
|
1304
|
+
* without a language check, so a TS `<TestRunner>` ref happily matched a
|
|
1305
|
+
* Kotlin `class TestRunner`. Gating only the both-known-cross-family case
|
|
1306
|
+
* lets config bridges and `calls` bridges through untouched.
|
|
1307
|
+
*/
|
|
1308
|
+
gateFrameworkLanguage(result, ref) {
|
|
1309
|
+
if (!result)
|
|
1310
|
+
return result;
|
|
1311
|
+
if (ref.referenceKind !== 'references' && ref.referenceKind !== 'imports')
|
|
1312
|
+
return result;
|
|
1313
|
+
const tgt = this.getLanguageFromNodeId(result.targetNodeId);
|
|
1314
|
+
if (tgt && ref.language && (0, name_matcher_1.crossesKnownFamily)(tgt, ref.language))
|
|
1315
|
+
return null;
|
|
1316
|
+
return result;
|
|
1317
|
+
}
|
|
868
1318
|
}
|
|
869
1319
|
exports.ReferenceResolver = ReferenceResolver;
|
|
870
1320
|
/**
|