@colbymchenry/codegraph-win32-x64 1.1.6 → 1.3.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 -1
- package/lib/dist/bin/codegraph.d.ts.map +1 -1
- package/lib/dist/bin/codegraph.js +232 -61
- package/lib/dist/bin/codegraph.js.map +1 -1
- package/lib/dist/bin/command-supervision.d.ts.map +1 -1
- package/lib/dist/bin/command-supervision.js +14 -1
- package/lib/dist/bin/command-supervision.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 +19 -1
- package/lib/dist/db/migrations.js.map +1 -1
- package/lib/dist/db/queries.d.ts +51 -0
- package/lib/dist/db/queries.d.ts.map +1 -1
- package/lib/dist/db/queries.js +141 -0
- package/lib/dist/db/queries.js.map +1 -1
- package/lib/dist/db/schema.sql +19 -0
- package/lib/dist/directory.d.ts +9 -5
- package/lib/dist/directory.d.ts.map +1 -1
- package/lib/dist/directory.js +210 -19
- package/lib/dist/directory.js.map +1 -1
- package/lib/dist/extraction/cfml-extractor.d.ts +107 -0
- package/lib/dist/extraction/cfml-extractor.d.ts.map +1 -0
- package/lib/dist/extraction/cfml-extractor.js +494 -0
- package/lib/dist/extraction/cfml-extractor.js.map +1 -0
- package/lib/dist/extraction/grammars.d.ts +9 -0
- package/lib/dist/extraction/grammars.d.ts.map +1 -1
- package/lib/dist/extraction/grammars.js +115 -3
- package/lib/dist/extraction/grammars.js.map +1 -1
- package/lib/dist/extraction/index.d.ts +46 -1
- package/lib/dist/extraction/index.d.ts.map +1 -1
- package/lib/dist/extraction/index.js +254 -3
- package/lib/dist/extraction/index.js.map +1 -1
- package/lib/dist/extraction/languages/arkts.d.ts +3 -0
- package/lib/dist/extraction/languages/arkts.d.ts.map +1 -0
- package/lib/dist/extraction/languages/arkts.js +127 -0
- package/lib/dist/extraction/languages/arkts.js.map +1 -0
- package/lib/dist/extraction/languages/c-cpp.d.ts +59 -0
- package/lib/dist/extraction/languages/c-cpp.d.ts.map +1 -1
- package/lib/dist/extraction/languages/c-cpp.js +499 -3
- package/lib/dist/extraction/languages/c-cpp.js.map +1 -1
- package/lib/dist/extraction/languages/cfquery.d.ts +12 -0
- package/lib/dist/extraction/languages/cfquery.d.ts.map +1 -0
- package/lib/dist/extraction/languages/cfquery.js +28 -0
- package/lib/dist/extraction/languages/cfquery.js.map +1 -0
- package/lib/dist/extraction/languages/cfscript.d.ts +3 -0
- package/lib/dist/extraction/languages/cfscript.d.ts.map +1 -0
- package/lib/dist/extraction/languages/cfscript.js +73 -0
- package/lib/dist/extraction/languages/cfscript.js.map +1 -0
- package/lib/dist/extraction/languages/cobol.d.ts +33 -0
- package/lib/dist/extraction/languages/cobol.d.ts.map +1 -0
- package/lib/dist/extraction/languages/cobol.js +499 -0
- package/lib/dist/extraction/languages/cobol.js.map +1 -0
- package/lib/dist/extraction/languages/erlang.d.ts +3 -0
- package/lib/dist/extraction/languages/erlang.d.ts.map +1 -0
- package/lib/dist/extraction/languages/erlang.js +350 -0
- package/lib/dist/extraction/languages/erlang.js.map +1 -0
- package/lib/dist/extraction/languages/index.d.ts.map +1 -1
- package/lib/dist/extraction/languages/index.js +18 -0
- package/lib/dist/extraction/languages/index.js.map +1 -1
- package/lib/dist/extraction/languages/nix.d.ts +3 -0
- package/lib/dist/extraction/languages/nix.d.ts.map +1 -0
- package/lib/dist/extraction/languages/nix.js +294 -0
- package/lib/dist/extraction/languages/nix.js.map +1 -0
- package/lib/dist/extraction/languages/solidity.d.ts +3 -0
- package/lib/dist/extraction/languages/solidity.d.ts.map +1 -0
- package/lib/dist/extraction/languages/solidity.js +293 -0
- package/lib/dist/extraction/languages/solidity.js.map +1 -0
- package/lib/dist/extraction/languages/terraform.d.ts +3 -0
- package/lib/dist/extraction/languages/terraform.d.ts.map +1 -0
- package/lib/dist/extraction/languages/terraform.js +641 -0
- package/lib/dist/extraction/languages/terraform.js.map +1 -0
- package/lib/dist/extraction/languages/vbnet.d.ts +11 -0
- package/lib/dist/extraction/languages/vbnet.d.ts.map +1 -0
- package/lib/dist/extraction/languages/vbnet.js +141 -0
- package/lib/dist/extraction/languages/vbnet.js.map +1 -0
- package/lib/dist/extraction/mybatis-extractor.d.ts +30 -10
- package/lib/dist/extraction/mybatis-extractor.d.ts.map +1 -1
- package/lib/dist/extraction/mybatis-extractor.js +140 -38
- package/lib/dist/extraction/mybatis-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 +1 -0
- package/lib/dist/extraction/tree-sitter-helpers.js.map +1 -1
- package/lib/dist/extraction/tree-sitter-types.d.ts +20 -1
- package/lib/dist/extraction/tree-sitter-types.d.ts.map +1 -1
- package/lib/dist/extraction/tree-sitter.d.ts +38 -0
- package/lib/dist/extraction/tree-sitter.d.ts.map +1 -1
- package/lib/dist/extraction/tree-sitter.js +845 -16
- package/lib/dist/extraction/tree-sitter.js.map +1 -1
- package/lib/dist/extraction/wasm/tree-sitter-arkts.wasm +0 -0
- package/lib/dist/extraction/wasm/tree-sitter-cfml.wasm +0 -0
- package/lib/dist/extraction/wasm/tree-sitter-cfquery.wasm +0 -0
- package/lib/dist/extraction/wasm/tree-sitter-cfscript.wasm +0 -0
- package/lib/dist/extraction/wasm/tree-sitter-cobol.wasm +0 -0
- package/lib/dist/extraction/wasm/tree-sitter-erlang.wasm +0 -0
- package/lib/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
- package/lib/dist/extraction/wasm/tree-sitter-terraform.wasm +0 -0
- package/lib/dist/extraction/wasm/tree-sitter-vbnet.wasm +0 -0
- package/lib/dist/graph/traversal.d.ts.map +1 -1
- package/lib/dist/graph/traversal.js +76 -17
- package/lib/dist/graph/traversal.js.map +1 -1
- package/lib/dist/index.d.ts +63 -1
- package/lib/dist/index.d.ts.map +1 -1
- package/lib/dist/index.js +310 -6
- package/lib/dist/index.js.map +1 -1
- package/lib/dist/installer/index.d.ts.map +1 -1
- package/lib/dist/installer/index.js +3 -1
- package/lib/dist/installer/index.js.map +1 -1
- package/lib/dist/mcp/daemon.d.ts +25 -3
- package/lib/dist/mcp/daemon.d.ts.map +1 -1
- package/lib/dist/mcp/daemon.js +39 -7
- package/lib/dist/mcp/daemon.js.map +1 -1
- package/lib/dist/mcp/dynamic-boundaries.d.ts.map +1 -1
- package/lib/dist/mcp/dynamic-boundaries.js +2 -1
- package/lib/dist/mcp/dynamic-boundaries.js.map +1 -1
- package/lib/dist/mcp/early-ppid.d.ts +26 -0
- package/lib/dist/mcp/early-ppid.d.ts.map +1 -0
- package/lib/dist/mcp/early-ppid.js +29 -0
- package/lib/dist/mcp/early-ppid.js.map +1 -0
- package/lib/dist/mcp/index.d.ts.map +1 -1
- package/lib/dist/mcp/index.js +21 -4
- package/lib/dist/mcp/index.js.map +1 -1
- package/lib/dist/mcp/proxy.d.ts.map +1 -1
- package/lib/dist/mcp/proxy.js +21 -3
- package/lib/dist/mcp/proxy.js.map +1 -1
- package/lib/dist/mcp/startup-handshake.d.ts +44 -0
- package/lib/dist/mcp/startup-handshake.d.ts.map +1 -0
- package/lib/dist/mcp/startup-handshake.js +73 -0
- package/lib/dist/mcp/startup-handshake.js.map +1 -0
- package/lib/dist/mcp/tools.d.ts +22 -0
- package/lib/dist/mcp/tools.d.ts.map +1 -1
- package/lib/dist/mcp/tools.js +74 -9
- package/lib/dist/mcp/tools.js.map +1 -1
- package/lib/dist/project-config.d.ts +38 -0
- package/lib/dist/project-config.d.ts.map +1 -1
- package/lib/dist/project-config.js +101 -2
- package/lib/dist/project-config.js.map +1 -1
- package/lib/dist/resolution/callback-synthesizer.d.ts +1 -1
- package/lib/dist/resolution/callback-synthesizer.d.ts.map +1 -1
- package/lib/dist/resolution/callback-synthesizer.js +743 -11
- package/lib/dist/resolution/callback-synthesizer.js.map +1 -1
- package/lib/dist/resolution/cooperative-yield.d.ts +32 -0
- package/lib/dist/resolution/cooperative-yield.d.ts.map +1 -0
- package/lib/dist/resolution/cooperative-yield.js +42 -0
- package/lib/dist/resolution/cooperative-yield.js.map +1 -0
- package/lib/dist/resolution/frameworks/cics.d.ts +20 -0
- package/lib/dist/resolution/frameworks/cics.d.ts.map +1 -0
- package/lib/dist/resolution/frameworks/cics.js +90 -0
- package/lib/dist/resolution/frameworks/cics.js.map +1 -0
- package/lib/dist/resolution/frameworks/index.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/index.js +6 -0
- package/lib/dist/resolution/frameworks/index.js.map +1 -1
- package/lib/dist/resolution/frameworks/java.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/java.js +14 -6
- package/lib/dist/resolution/frameworks/java.js.map +1 -1
- package/lib/dist/resolution/frameworks/terraform.d.ts +38 -0
- package/lib/dist/resolution/frameworks/terraform.d.ts.map +1 -0
- package/lib/dist/resolution/frameworks/terraform.js +277 -0
- package/lib/dist/resolution/frameworks/terraform.js.map +1 -0
- package/lib/dist/resolution/import-resolver.d.ts +7 -0
- package/lib/dist/resolution/import-resolver.d.ts.map +1 -1
- package/lib/dist/resolution/import-resolver.js +129 -4
- package/lib/dist/resolution/import-resolver.js.map +1 -1
- package/lib/dist/resolution/index.d.ts +44 -2
- package/lib/dist/resolution/index.d.ts.map +1 -1
- package/lib/dist/resolution/index.js +335 -30
- package/lib/dist/resolution/index.js.map +1 -1
- package/lib/dist/resolution/name-matcher.d.ts +22 -3
- package/lib/dist/resolution/name-matcher.d.ts.map +1 -1
- package/lib/dist/resolution/name-matcher.js +484 -39
- package/lib/dist/resolution/name-matcher.js.map +1 -1
- package/lib/dist/resolution/strip-comments.d.ts +1 -1
- package/lib/dist/resolution/strip-comments.d.ts.map +1 -1
- package/lib/dist/resolution/strip-comments.js +49 -0
- package/lib/dist/resolution/strip-comments.js.map +1 -1
- package/lib/dist/resolution/types.d.ts +20 -0
- package/lib/dist/resolution/types.d.ts.map +1 -1
- package/lib/dist/resolution/workspace-packages.d.ts +10 -0
- package/lib/dist/resolution/workspace-packages.d.ts.map +1 -1
- package/lib/dist/resolution/workspace-packages.js +142 -4
- package/lib/dist/resolution/workspace-packages.js.map +1 -1
- package/lib/dist/search/identifier-segments.d.ts +60 -0
- package/lib/dist/search/identifier-segments.d.ts.map +1 -0
- package/lib/dist/search/identifier-segments.js +176 -0
- package/lib/dist/search/identifier-segments.js.map +1 -0
- package/lib/dist/sync/git-hooks.d.ts.map +1 -1
- package/lib/dist/sync/git-hooks.js +2 -0
- package/lib/dist/sync/git-hooks.js.map +1 -1
- package/lib/dist/sync/watcher.d.ts +10 -5
- package/lib/dist/sync/watcher.d.ts.map +1 -1
- package/lib/dist/sync/watcher.js +51 -14
- package/lib/dist/sync/watcher.js.map +1 -1
- package/lib/dist/sync/worktree.d.ts.map +1 -1
- package/lib/dist/sync/worktree.js +5 -0
- package/lib/dist/sync/worktree.js.map +1 -1
- package/lib/dist/types.d.ts +19 -1
- package/lib/dist/types.d.ts.map +1 -1
- package/lib/dist/types.js +10 -0
- package/lib/dist/types.js.map +1 -1
- package/lib/dist/upgrade/index.js +1 -1
- package/lib/dist/upgrade/index.js.map +1 -1
- package/lib/node_modules/.package-lock.json +1 -1
- package/lib/package.json +1 -1
- package/package.json +1 -1
- package/lib/dist/reasoning/config.d.ts +0 -45
- package/lib/dist/reasoning/config.d.ts.map +0 -1
- package/lib/dist/reasoning/config.js +0 -171
- package/lib/dist/reasoning/config.js.map +0 -1
- package/lib/dist/reasoning/credentials.d.ts +0 -5
- package/lib/dist/reasoning/credentials.d.ts.map +0 -1
- package/lib/dist/reasoning/credentials.js +0 -83
- package/lib/dist/reasoning/credentials.js.map +0 -1
- package/lib/dist/reasoning/login.d.ts +0 -21
- package/lib/dist/reasoning/login.d.ts.map +0 -1
- package/lib/dist/reasoning/login.js +0 -85
- package/lib/dist/reasoning/login.js.map +0 -1
- package/lib/dist/reasoning/reasoner.d.ts +0 -43
- package/lib/dist/reasoning/reasoner.d.ts.map +0 -1
- package/lib/dist/reasoning/reasoner.js +0 -308
- package/lib/dist/reasoning/reasoner.js.map +0 -1
|
@@ -49,6 +49,7 @@ const name_matcher_1 = require("./name-matcher");
|
|
|
49
49
|
const import_resolver_1 = require("./import-resolver");
|
|
50
50
|
const frameworks_1 = require("./frameworks");
|
|
51
51
|
const callback_synthesizer_1 = require("./callback-synthesizer");
|
|
52
|
+
const cooperative_yield_1 = require("./cooperative-yield");
|
|
52
53
|
const path_aliases_1 = require("./path-aliases");
|
|
53
54
|
const go_module_1 = require("./go-module");
|
|
54
55
|
const workspace_packages_1 = require("./workspace-packages");
|
|
@@ -239,6 +240,17 @@ class ReferenceResolver {
|
|
|
239
240
|
nameCache; // name → nodes cache
|
|
240
241
|
lowerNameCache; // lower(name) → nodes cache
|
|
241
242
|
qualifiedNameCache; // qualified_name → nodes cache
|
|
243
|
+
fileLinesCache; // file → split lines cache
|
|
244
|
+
methodMatchCache; // lang\0Type::method → matching method nodes
|
|
245
|
+
// Node kinds are a small fixed set (~24), so this is a plain Map, not an LRU.
|
|
246
|
+
// getNodesByKind returns the FULL node list for a kind; it was previously
|
|
247
|
+
// uncached — a per-ref `SELECT * FROM nodes WHERE kind=?` + row-mapping. Called
|
|
248
|
+
// for every dotted call ref by the Spring resolver (constants) and every
|
|
249
|
+
// `hook_` ref by the Drupal resolver (functions), that scan dominated
|
|
250
|
+
// resolution on large repos (#1180). The node set is stable within a
|
|
251
|
+
// resolution pass (same lifetime assumption as nameCache); clearCaches() resets
|
|
252
|
+
// it between passes. Callers must treat the returned array as read-only.
|
|
253
|
+
nodesByKindCache = new Map();
|
|
242
254
|
knownNames = null; // all known symbol names for fast pre-filtering
|
|
243
255
|
knownFiles = null;
|
|
244
256
|
cachesWarmed = false;
|
|
@@ -264,6 +276,10 @@ class ReferenceResolver {
|
|
|
264
276
|
this.nameCache = new lru_cache_1.LRUCache(limit);
|
|
265
277
|
this.lowerNameCache = new lru_cache_1.LRUCache(limit);
|
|
266
278
|
this.qualifiedNameCache = new lru_cache_1.LRUCache(limit);
|
|
279
|
+
// Split-lines arrays are heavier than content strings; refs arrive
|
|
280
|
+
// file-ordered, so a small cache still hits nearly always.
|
|
281
|
+
this.fileLinesCache = new lru_cache_1.LRUCache(contentLimit);
|
|
282
|
+
this.methodMatchCache = new lru_cache_1.LRUCache(limit);
|
|
267
283
|
this.context = this.createContext();
|
|
268
284
|
}
|
|
269
285
|
/**
|
|
@@ -330,10 +346,30 @@ class ReferenceResolver {
|
|
|
330
346
|
this.nameCache.clear();
|
|
331
347
|
this.lowerNameCache.clear();
|
|
332
348
|
this.qualifiedNameCache.clear();
|
|
349
|
+
this.fileLinesCache.clear();
|
|
350
|
+
this.methodMatchCache.clear();
|
|
351
|
+
this.nodesByKindCache.clear();
|
|
333
352
|
this.knownNames = null;
|
|
334
353
|
this.knownFiles = null;
|
|
335
354
|
this.cachesWarmed = false;
|
|
336
355
|
}
|
|
356
|
+
/** `readFile` through the LRU content cache (null = read failed, also cached). */
|
|
357
|
+
readFileCached(filePath) {
|
|
358
|
+
if (this.fileCache.has(filePath)) {
|
|
359
|
+
return this.fileCache.get(filePath);
|
|
360
|
+
}
|
|
361
|
+
const fullPath = path.join(this.projectRoot, filePath);
|
|
362
|
+
try {
|
|
363
|
+
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
364
|
+
this.fileCache.set(filePath, content);
|
|
365
|
+
return content;
|
|
366
|
+
}
|
|
367
|
+
catch (error) {
|
|
368
|
+
(0, errors_1.logDebug)('Failed to read file for resolution', { filePath, error: String(error) });
|
|
369
|
+
this.fileCache.set(filePath, null);
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
337
373
|
/**
|
|
338
374
|
* Create the resolution context
|
|
339
375
|
*/
|
|
@@ -353,6 +389,30 @@ class ReferenceResolver {
|
|
|
353
389
|
this.nameCache.set(name, result);
|
|
354
390
|
return result;
|
|
355
391
|
},
|
|
392
|
+
getMethodMatches: (typeName, methodName, language) => {
|
|
393
|
+
const key = `${language} ${typeName}::${methodName}`;
|
|
394
|
+
const cached = this.methodMatchCache.get(key);
|
|
395
|
+
if (cached !== undefined)
|
|
396
|
+
return cached;
|
|
397
|
+
let candidates = this.nameCache.get(methodName);
|
|
398
|
+
if (candidates === undefined) {
|
|
399
|
+
candidates = this.queries.getNodesByName(methodName);
|
|
400
|
+
this.nameCache.set(methodName, candidates);
|
|
401
|
+
}
|
|
402
|
+
const want = `${typeName}::${methodName}`;
|
|
403
|
+
const matches = [];
|
|
404
|
+
for (const m of candidates) {
|
|
405
|
+
if (m.kind !== 'method')
|
|
406
|
+
continue;
|
|
407
|
+
if (m.language !== language)
|
|
408
|
+
continue;
|
|
409
|
+
const qn = m.qualifiedName;
|
|
410
|
+
if (qn === want || qn.endsWith(`::${want}`))
|
|
411
|
+
matches.push(m);
|
|
412
|
+
}
|
|
413
|
+
this.methodMatchCache.set(key, matches);
|
|
414
|
+
return matches;
|
|
415
|
+
},
|
|
356
416
|
getNodesByQualifiedName: (qualifiedName) => {
|
|
357
417
|
const cached = this.qualifiedNameCache.get(qualifiedName);
|
|
358
418
|
if (cached !== undefined)
|
|
@@ -362,7 +422,12 @@ class ReferenceResolver {
|
|
|
362
422
|
return result;
|
|
363
423
|
},
|
|
364
424
|
getNodesByKind: (kind) => {
|
|
365
|
-
|
|
425
|
+
const cached = this.nodesByKindCache.get(kind);
|
|
426
|
+
if (cached !== undefined)
|
|
427
|
+
return cached;
|
|
428
|
+
const result = this.queries.getNodesByKind(kind);
|
|
429
|
+
this.nodesByKindCache.set(kind, result);
|
|
430
|
+
return result;
|
|
366
431
|
},
|
|
367
432
|
fileExists: (filePath) => {
|
|
368
433
|
// Check pre-built known files set first (O(1))
|
|
@@ -382,21 +447,15 @@ class ReferenceResolver {
|
|
|
382
447
|
return false;
|
|
383
448
|
}
|
|
384
449
|
},
|
|
385
|
-
readFile: (filePath) =>
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
}
|
|
395
|
-
catch (error) {
|
|
396
|
-
(0, errors_1.logDebug)('Failed to read file for resolution', { filePath, error: String(error) });
|
|
397
|
-
this.fileCache.set(filePath, null);
|
|
398
|
-
return null;
|
|
399
|
-
}
|
|
450
|
+
readFile: (filePath) => this.readFileCached(filePath),
|
|
451
|
+
getFileLines: (filePath) => {
|
|
452
|
+
const cached = this.fileLinesCache.get(filePath);
|
|
453
|
+
if (cached !== undefined)
|
|
454
|
+
return cached;
|
|
455
|
+
const source = this.readFileCached(filePath);
|
|
456
|
+
const lines = source === null ? null : source.split(/\r?\n/);
|
|
457
|
+
this.fileLinesCache.set(filePath, lines);
|
|
458
|
+
return lines;
|
|
400
459
|
},
|
|
401
460
|
getProjectRoot: () => this.projectRoot,
|
|
402
461
|
getAllFiles: () => {
|
|
@@ -499,7 +558,7 @@ class ReferenceResolver {
|
|
|
499
558
|
// `.ts` index barrel and silently break the chain (#629). Re-key
|
|
500
559
|
// the parse on the barrel's extension so the chase works no matter
|
|
501
560
|
// what kind of file imports through it.
|
|
502
|
-
const isJsFamily = /\.(?:d\.ts|[cm]?tsx?|[cm]?jsx
|
|
561
|
+
const isJsFamily = /\.(?:d\.ts|[cm]?tsx?|[cm]?jsx?|ets)$/i.test(filePath);
|
|
503
562
|
const reExports = (0, import_resolver_1.extractReExports)(content, isJsFamily ? 'typescript' : language);
|
|
504
563
|
this.reExportCache.set(filePath, reExports);
|
|
505
564
|
return reExports;
|
|
@@ -614,6 +673,24 @@ class ReferenceResolver {
|
|
|
614
673
|
return true;
|
|
615
674
|
}
|
|
616
675
|
}
|
|
676
|
+
// Lua/Luau method calls use a single `:` (`lg:log`); R uses `$` (`lg$log`).
|
|
677
|
+
// Check the member (and receiver) around these separators too, so the ref
|
|
678
|
+
// isn't dropped here before the method-call resolver ever sees it. The `:`
|
|
679
|
+
// case is skipped when the name actually contains `::` (handled above).
|
|
680
|
+
for (const sep of [':', '$']) {
|
|
681
|
+
if (sep === ':' && name.includes('::'))
|
|
682
|
+
continue;
|
|
683
|
+
const sepIdx = name.indexOf(sep);
|
|
684
|
+
if (sepIdx > 0) {
|
|
685
|
+
const receiver = name.substring(0, sepIdx);
|
|
686
|
+
const member = name.substring(sepIdx + 1);
|
|
687
|
+
if (this.knownNames.has(member) || this.knownNames.has(receiver))
|
|
688
|
+
return true;
|
|
689
|
+
const capitalized = receiver.charAt(0).toUpperCase() + receiver.slice(1);
|
|
690
|
+
if (this.knownNames.has(capitalized))
|
|
691
|
+
return true;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
617
694
|
// For path-like references (e.g., "snippets/drawer-menu.liquid"), check the filename
|
|
618
695
|
const slashIdx = name.lastIndexOf('/');
|
|
619
696
|
if (slashIdx > 0) {
|
|
@@ -648,13 +725,36 @@ class ReferenceResolver {
|
|
|
648
725
|
if (this.isBuiltInOrExternal(ref)) {
|
|
649
726
|
return null;
|
|
650
727
|
}
|
|
728
|
+
// CFML component paths in inheritance (#1152): `extends="coldbox.system.web.
|
|
729
|
+
// Controller"` names the supertype by its dot-separated path (or `extends=
|
|
730
|
+
// "../base"` by relative file path) — the graph indexes the class under its
|
|
731
|
+
// final segment only, so these die at the fast pre-filter below and never
|
|
732
|
+
// resolved. Handled by a dedicated path-corroborated matcher, gated to
|
|
733
|
+
// inheritance refs only (a dotted `calls` ref is a member-access chain, not
|
|
734
|
+
// a component path). No fallthrough on miss: the full path string can only
|
|
735
|
+
// ever mis-match downstream, and an unresolvable supertype usually lives in
|
|
736
|
+
// an out-of-repo library (mxunit, testbox) — silent beats wrong.
|
|
737
|
+
if ((ref.language === 'cfml' || ref.language === 'cfscript') &&
|
|
738
|
+
(ref.referenceKind === 'extends' || ref.referenceKind === 'implements') &&
|
|
739
|
+
(ref.referenceName.includes('.') || ref.referenceName.includes('/'))) {
|
|
740
|
+
return this.resolveCfmlComponentPath(ref);
|
|
741
|
+
}
|
|
651
742
|
// Fast pre-filter: skip if no symbol with this name exists anywhere
|
|
652
743
|
// AND the name doesn't match a local import. The import escape is
|
|
653
744
|
// necessary because re-export rename chains (`import { login }
|
|
654
745
|
// from './barrel'` where the barrel has `export { signIn as login }
|
|
655
746
|
// from './auth'`) intentionally call a name that has no
|
|
656
747
|
// declaration anywhere — only the renamed upstream symbol does.
|
|
657
|
-
|
|
748
|
+
// ArkTS chained-attribute refs carry a leading dot (`.titleStyle`) that
|
|
749
|
+
// routes them to the decorator-gated matcher; the symbol itself is
|
|
750
|
+
// indexed under the bare name, so the existence check strips the dot.
|
|
751
|
+
// Nix static path imports (`import ./x.nix`) name a FILE, not a symbol —
|
|
752
|
+
// they bypass the symbol-existence check and resolve via resolveViaImport.
|
|
753
|
+
const existenceName = ref.language === 'arkts' && ref.referenceName.startsWith('.')
|
|
754
|
+
? ref.referenceName.slice(1)
|
|
755
|
+
: ref.referenceName;
|
|
756
|
+
if (!(0, import_resolver_1.isNixPathImportRef)(ref) &&
|
|
757
|
+
!this.hasAnyPossibleMatch(existenceName) &&
|
|
658
758
|
!this.matchesAnyImport(ref) &&
|
|
659
759
|
!this.frameworks.some((f) => f.claimsReference?.(ref.referenceName))) {
|
|
660
760
|
return null;
|
|
@@ -720,13 +820,40 @@ class ReferenceResolver {
|
|
|
720
820
|
// If that didn't find the file, do NOT fall back to the symbol
|
|
721
821
|
// name-matcher — it would mis-connect e.g. "inc/db.php" to an unrelated
|
|
722
822
|
// db.php elsewhere in the tree (a wrong edge is worse than none, #660).
|
|
723
|
-
|
|
823
|
+
// Terraform refs are directory-scoped by language semantics — the
|
|
824
|
+
// framework resolver IS the whole rulebook (`var.X` can never legally
|
|
825
|
+
// bind outside its module directory), so the name-matcher's
|
|
826
|
+
// qualified-name fallback would only ever add wrong cross-module edges.
|
|
827
|
+
// Nix static path imports are file references for the same reason —
|
|
828
|
+
// falling through would let "./x.nix" name-match an unrelated node.
|
|
829
|
+
if ((0, import_resolver_1.isPhpIncludePathRef)(ref) || (0, import_resolver_1.isCobolCopybookRef)(ref) || (0, import_resolver_1.isNixPathImportRef)(ref) || ref.language === 'terraform') {
|
|
724
830
|
return candidates.length > 0
|
|
725
831
|
? candidates.reduce((best, curr) => curr.confidence > best.confidence ? curr : best)
|
|
726
832
|
: null;
|
|
727
833
|
}
|
|
728
834
|
// Strategy 3: Try name matching
|
|
729
|
-
|
|
835
|
+
let nameResult = this.gateLanguage((0, name_matcher_1.matchReference)(ref, this.context), ref);
|
|
836
|
+
// Nix has no ambient cross-file namespace — a callee binds lexically
|
|
837
|
+
// (same file) or through explicit import/callPackage wiring (the import
|
|
838
|
+
// path above). A cross-file name match is wrong by construction: every
|
|
839
|
+
// module `inherit (lib) mkOption`s the same nixpkgs helpers, so the
|
|
840
|
+
// matcher would link each `mkOption` call to whichever file's inherit
|
|
841
|
+
// binding it happened to pick. Same-file matches only.
|
|
842
|
+
if (nameResult) {
|
|
843
|
+
const target = this.queries.getNodeById(nameResult.targetNodeId);
|
|
844
|
+
if (ref.language === 'nix') {
|
|
845
|
+
if (!target || target.filePath !== ref.filePath) {
|
|
846
|
+
nameResult = null;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
else if (target && target.language === 'nix') {
|
|
850
|
+
// The reverse direction is just as impossible: no other language can
|
|
851
|
+
// symbolically call into a .nix binding (interop is eval/CLI, never a
|
|
852
|
+
// linkable symbol) — without this, a Python script's `split()` lands
|
|
853
|
+
// on some module's `split = ...` binding as a low-confidence match.
|
|
854
|
+
nameResult = null;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
730
857
|
if (nameResult) {
|
|
731
858
|
candidates.push(nameResult);
|
|
732
859
|
}
|
|
@@ -813,6 +940,20 @@ class ReferenceResolver {
|
|
|
813
940
|
referenceKind: r.original.referenceKind,
|
|
814
941
|
})));
|
|
815
942
|
}
|
|
943
|
+
// Delete unresolvable refs too — parity with resolveAndPersistBatched.
|
|
944
|
+
// Keeping them bought nothing: a ref is only ever retried when its file
|
|
945
|
+
// is re-extracted, which cascade-deletes and re-inserts its rows anyway.
|
|
946
|
+
// And it broke the #1187 orphan sweep's invariant — after a COMPLETED
|
|
947
|
+
// pass the table must hold nothing that pass processed, so that any row
|
|
948
|
+
// still present belongs to an interrupted run and the sweep can key off
|
|
949
|
+
// a bare row count.
|
|
950
|
+
if (result.unresolved.length > 0) {
|
|
951
|
+
this.queries.deleteSpecificResolvedReferences(result.unresolved.map((r) => ({
|
|
952
|
+
fromNodeId: r.fromNodeId,
|
|
953
|
+
referenceName: r.referenceName,
|
|
954
|
+
referenceKind: r.referenceKind,
|
|
955
|
+
})));
|
|
956
|
+
}
|
|
816
957
|
return result;
|
|
817
958
|
}
|
|
818
959
|
/**
|
|
@@ -828,7 +969,7 @@ class ReferenceResolver {
|
|
|
828
969
|
* (re-resolving an already-resolved ref is a no-op since it's been deleted).
|
|
829
970
|
* Returns the number of newly-created edges.
|
|
830
971
|
*/
|
|
831
|
-
resolveChainedCallsViaConformance() {
|
|
972
|
+
async resolveChainedCallsViaConformance() {
|
|
832
973
|
const deferred = this.deferredChainRefs;
|
|
833
974
|
this.deferredChainRefs = [];
|
|
834
975
|
if (deferred.length === 0)
|
|
@@ -837,6 +978,10 @@ class ReferenceResolver {
|
|
|
837
978
|
// these refs were deferred). matchDottedCallChain now resolves a method on a
|
|
838
979
|
// supertype via context.getSupertypes -> resolveMethodOnType's conformance walk.
|
|
839
980
|
this.clearCaches();
|
|
981
|
+
// This post-pass runs synchronously on the indexer's main thread; yield
|
|
982
|
+
// periodically so the #850 liveness watchdog heartbeat can fire on a repo
|
|
983
|
+
// with many deferred chained calls (#1091).
|
|
984
|
+
const maybeYield = (0, cooperative_yield_1.createYielder)();
|
|
840
985
|
const resolved = [];
|
|
841
986
|
for (const ref of deferred) {
|
|
842
987
|
// `::`-receiver languages (Rust) split on `::` (matchScopedCallChain);
|
|
@@ -847,6 +992,7 @@ class ReferenceResolver {
|
|
|
847
992
|
const match = this.gateLanguage(chainMatch, ref);
|
|
848
993
|
if (match)
|
|
849
994
|
resolved.push(match);
|
|
995
|
+
await maybeYield();
|
|
850
996
|
}
|
|
851
997
|
if (resolved.length === 0)
|
|
852
998
|
return 0;
|
|
@@ -857,6 +1003,55 @@ class ReferenceResolver {
|
|
|
857
1003
|
}
|
|
858
1004
|
return edges.length;
|
|
859
1005
|
}
|
|
1006
|
+
/**
|
|
1007
|
+
* Resolve one batch with a yield checkpoint between EVERY ref so the #850
|
|
1008
|
+
* liveness heartbeat can fire on a slow/dense batch (#1091). The checkpoint
|
|
1009
|
+
* granularity is per-ref — not per-N-refs — because per-ref cost is unbounded
|
|
1010
|
+
* in the worst case (a collision-heavy method name whose candidate set misses
|
|
1011
|
+
* the LRU re-fetches tens of thousands of rows): any fixed N multiplies that
|
|
1012
|
+
* worst case into the watchdog window, which is how v1.2.0 still got killed
|
|
1013
|
+
* at "Resolving refs" on large Java monorepos (#1122). `maybeYield()` is a
|
|
1014
|
+
* ~ns time check when under budget, so per-ref checkpoints cost nothing.
|
|
1015
|
+
* Behaviourally identical to `resolveAll(batch)`: `warmCaches()` is
|
|
1016
|
+
* idempotent (guarded) and `resolveOne` is independent per ref, so yielding
|
|
1017
|
+
* between refs changes only timing, never which edges get created.
|
|
1018
|
+
*/
|
|
1019
|
+
async resolveBatchYielding(batch, maybeYield) {
|
|
1020
|
+
this.warmCaches();
|
|
1021
|
+
const resolved = [];
|
|
1022
|
+
const unresolved = [];
|
|
1023
|
+
const byMethod = {};
|
|
1024
|
+
for (const raw of batch) {
|
|
1025
|
+
const ref = {
|
|
1026
|
+
fromNodeId: raw.fromNodeId,
|
|
1027
|
+
referenceName: raw.referenceName,
|
|
1028
|
+
referenceKind: raw.referenceKind,
|
|
1029
|
+
line: raw.line,
|
|
1030
|
+
column: raw.column,
|
|
1031
|
+
filePath: raw.filePath || this.getFilePathFromNodeId(raw.fromNodeId),
|
|
1032
|
+
language: raw.language || this.getLanguageFromNodeId(raw.fromNodeId),
|
|
1033
|
+
};
|
|
1034
|
+
const result = this.resolveOne(ref);
|
|
1035
|
+
if (result) {
|
|
1036
|
+
resolved.push(result);
|
|
1037
|
+
byMethod[result.resolvedBy] = (byMethod[result.resolvedBy] || 0) + 1;
|
|
1038
|
+
}
|
|
1039
|
+
else {
|
|
1040
|
+
unresolved.push(ref);
|
|
1041
|
+
}
|
|
1042
|
+
await maybeYield();
|
|
1043
|
+
}
|
|
1044
|
+
return {
|
|
1045
|
+
resolved,
|
|
1046
|
+
unresolved,
|
|
1047
|
+
stats: {
|
|
1048
|
+
total: batch.length,
|
|
1049
|
+
resolved: resolved.length,
|
|
1050
|
+
unresolved: unresolved.length,
|
|
1051
|
+
byMethod,
|
|
1052
|
+
},
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
860
1055
|
/**
|
|
861
1056
|
* Resolve and persist in batches to keep memory bounded.
|
|
862
1057
|
* Processes unresolved references in chunks, persisting edges and cleaning
|
|
@@ -864,6 +1059,13 @@ class ReferenceResolver {
|
|
|
864
1059
|
*/
|
|
865
1060
|
async resolveAndPersistBatched(onProgress, batchSize = 5000) {
|
|
866
1061
|
this.warmCaches();
|
|
1062
|
+
// Resolution runs on the indexer's MAIN thread, and the #850 liveness
|
|
1063
|
+
// watchdog SIGKILLs a process whose event loop stalls past its window (60s
|
|
1064
|
+
// by default). A single dense batch's resolveAll — or the synthesis pass
|
|
1065
|
+
// below — can exceed that on a large repo, killing a VALID in-progress index
|
|
1066
|
+
// (#1091). A shared yielder lets both give the watchdog heartbeat a regular
|
|
1067
|
+
// window to fire; see ./cooperative-yield.
|
|
1068
|
+
const maybeYield = (0, cooperative_yield_1.createYielder)();
|
|
867
1069
|
const total = this.queries.getUnresolvedReferencesCount();
|
|
868
1070
|
let processed = 0;
|
|
869
1071
|
const aggregateStats = {
|
|
@@ -879,7 +1081,7 @@ class ReferenceResolver {
|
|
|
879
1081
|
const batch = this.queries.getUnresolvedReferencesBatch(0, batchSize);
|
|
880
1082
|
if (batch.length === 0)
|
|
881
1083
|
break;
|
|
882
|
-
const result = this.
|
|
1084
|
+
const result = await this.resolveBatchYielding(batch, maybeYield);
|
|
883
1085
|
// Persist edges immediately
|
|
884
1086
|
const edges = this.createEdges(result.resolved);
|
|
885
1087
|
if (edges.length > 0) {
|
|
@@ -912,11 +1114,13 @@ class ReferenceResolver {
|
|
|
912
1114
|
onProgress?.(processed, total);
|
|
913
1115
|
// Yield so progress UI can render between batches
|
|
914
1116
|
await new Promise(resolve => setImmediate(resolve));
|
|
915
|
-
//
|
|
916
|
-
//
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
1117
|
+
// NOTE: there used to be an extra early break here when a batch resolved
|
|
1118
|
+
// nothing (`result.unresolved.length === batch.length`). That was wrong:
|
|
1119
|
+
// an all-unresolvable batch still DELETES its rows (progress), yet the
|
|
1120
|
+
// break abandoned every batch after it in the same run — on a repo whose
|
|
1121
|
+
// first 5000 refs are all external/stdlib calls, resolution stopped at
|
|
1122
|
+
// batch one and left the rest of the table as permanent orphans (#1187).
|
|
1123
|
+
// The count-based guard below catches the true no-progress case.
|
|
920
1124
|
// Non-progress guard (defense-in-depth). Because we re-read from offset 0
|
|
921
1125
|
// each pass, the unresolved_refs table MUST shrink every iteration — both
|
|
922
1126
|
// resolved and unresolved refs are deleted above. If it didn't shrink, a
|
|
@@ -935,7 +1139,7 @@ class ReferenceResolver {
|
|
|
935
1139
|
// callbacks) that static parsing leaves out. Best-effort — never fail the
|
|
936
1140
|
// index on it. See docs/design/callback-edge-synthesis.md.
|
|
937
1141
|
try {
|
|
938
|
-
aggregateStats.byMethod['callback-synthesis'] = (0, callback_synthesizer_1.synthesizeCallbackEdges)(this.queries, this.context);
|
|
1142
|
+
aggregateStats.byMethod['callback-synthesis'] = await (0, callback_synthesizer_1.synthesizeCallbackEdges)(this.queries, this.context);
|
|
939
1143
|
}
|
|
940
1144
|
catch {
|
|
941
1145
|
// synthesis is additive and optional; ignore failures
|
|
@@ -958,11 +1162,18 @@ class ReferenceResolver {
|
|
|
958
1162
|
isBuiltInOrExternal(ref) {
|
|
959
1163
|
const name = ref.referenceName;
|
|
960
1164
|
const isJsTs = ref.language === 'typescript' || ref.language === 'javascript'
|
|
961
|
-
|| ref.language === 'tsx' || ref.language === 'jsx';
|
|
1165
|
+
|| ref.language === 'tsx' || ref.language === 'jsx' || ref.language === 'arkts';
|
|
962
1166
|
// JavaScript/TypeScript built-ins
|
|
963
1167
|
if (isJsTs && JS_BUILT_INS.has(name)) {
|
|
964
1168
|
return true;
|
|
965
1169
|
}
|
|
1170
|
+
// ArkTS resource-reference intrinsics — `$r('app.string.x')` /
|
|
1171
|
+
// `$rawfile('x.png')` are framework-provided and appear dozens of times
|
|
1172
|
+
// per UI file; without this they can resolve to a stray same-named
|
|
1173
|
+
// symbol (e.g. a checked-in hvigor wrapper's `$r`).
|
|
1174
|
+
if (ref.language === 'arkts' && (name === '$r' || name === '$rawfile')) {
|
|
1175
|
+
return true;
|
|
1176
|
+
}
|
|
966
1177
|
// Common JS/TS library calls (console.log, Math.floor, JSON.parse)
|
|
967
1178
|
if (isJsTs && (name.startsWith('console.') || name.startsWith('Math.') || name.startsWith('JSON.'))) {
|
|
968
1179
|
return true;
|
|
@@ -1127,6 +1338,96 @@ class ReferenceResolver {
|
|
|
1127
1338
|
const target = found.values().next().value;
|
|
1128
1339
|
return { original: ref, targetNodeId: target.id, confidence: 0.9, resolvedBy: 'import' };
|
|
1129
1340
|
}
|
|
1341
|
+
/**
|
|
1342
|
+
* Resolve a CFML inheritance reference written as a component path (#1152).
|
|
1343
|
+
* Two forms exist in real code:
|
|
1344
|
+
*
|
|
1345
|
+
* - Dotted: `extends="coldbox.system.web.Controller"` — dots are directory
|
|
1346
|
+
* separators from the webroot or a CFML mapping. Mappings live in server
|
|
1347
|
+
* config / Application.cfc, so the leading segments may not exist in the
|
|
1348
|
+
* repo at all (in the coldbox repo itself the path is `system/web/
|
|
1349
|
+
* Controller.cfc` — the `coldbox.` root IS the repo). Matched by final
|
|
1350
|
+
* segment (the class), corroborated right-to-left against the candidate's
|
|
1351
|
+
* parent directories.
|
|
1352
|
+
* - Relative: `extends="../base"` / `extends="./base"` (the FW/1 style) —
|
|
1353
|
+
* resolved against the referencing file's own directory.
|
|
1354
|
+
*
|
|
1355
|
+
* Conservative by design: a candidate needs at least one corroborating
|
|
1356
|
+
* directory segment (a dotted path whose only same-named class sits in an
|
|
1357
|
+
* unrelated directory is almost always an out-of-repo library supertype —
|
|
1358
|
+
* mxunit/testbox/coldbox-as-dependency), and a corroboration tie yields no
|
|
1359
|
+
* edge. Directory comparison is case-insensitive (CFML path resolution is);
|
|
1360
|
+
* the class segment itself is matched exactly, which real code satisfies —
|
|
1361
|
+
* dotted paths are written to match the on-disk file name.
|
|
1362
|
+
*/
|
|
1363
|
+
resolveCfmlComponentPath(ref) {
|
|
1364
|
+
const cfmlCandidates = (name) => this.context
|
|
1365
|
+
.getNodesByName(name)
|
|
1366
|
+
.filter((n) => (n.kind === 'class' || n.kind === 'interface') &&
|
|
1367
|
+
(n.language === 'cfml' || n.language === 'cfscript'));
|
|
1368
|
+
const norm = (p) => p.replace(/\\/g, '/').toLowerCase();
|
|
1369
|
+
// Relative-path form: `../base`, `./base`, `sub/thing` — resolve against
|
|
1370
|
+
// the referencing file's directory and require an exact (case-insensitive)
|
|
1371
|
+
// file match.
|
|
1372
|
+
if (ref.referenceName.includes('/')) {
|
|
1373
|
+
const rel = ref.referenceName.replace(/\.cfc$/i, '');
|
|
1374
|
+
const fromDir = ref.filePath.replace(/\\/g, '/').split('/').slice(0, -1);
|
|
1375
|
+
const parts = [...fromDir];
|
|
1376
|
+
for (const seg of rel.split('/')) {
|
|
1377
|
+
if (seg === '' || seg === '.')
|
|
1378
|
+
continue;
|
|
1379
|
+
if (seg === '..') {
|
|
1380
|
+
if (parts.length === 0)
|
|
1381
|
+
return null; // escapes the project root
|
|
1382
|
+
parts.pop();
|
|
1383
|
+
}
|
|
1384
|
+
else {
|
|
1385
|
+
parts.push(seg);
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
const wantPath = norm(parts.join('/') + '.cfc');
|
|
1389
|
+
const className = parts[parts.length - 1];
|
|
1390
|
+
if (!className)
|
|
1391
|
+
return null;
|
|
1392
|
+
const target = cfmlCandidates(className).find((c) => norm(c.filePath) === wantPath);
|
|
1393
|
+
return target
|
|
1394
|
+
? { original: ref, targetNodeId: target.id, confidence: 0.95, resolvedBy: 'file-path' }
|
|
1395
|
+
: null;
|
|
1396
|
+
}
|
|
1397
|
+
// Dotted form.
|
|
1398
|
+
const segments = ref.referenceName.split('.').map((s) => s.trim()).filter(Boolean);
|
|
1399
|
+
if (segments.length < 2)
|
|
1400
|
+
return null;
|
|
1401
|
+
const className = segments[segments.length - 1];
|
|
1402
|
+
const dirSegments = segments.slice(0, -1);
|
|
1403
|
+
let best = null;
|
|
1404
|
+
let bestScore = 0;
|
|
1405
|
+
let tie = false;
|
|
1406
|
+
for (const cand of cfmlCandidates(className)) {
|
|
1407
|
+
const dirs = cand.filePath.replace(/\\/g, '/').split('/').slice(0, -1);
|
|
1408
|
+
// Count matching directory segments right-to-left: for
|
|
1409
|
+
// `coldbox.system.web.Controller` vs `system/web/Controller.cfc`,
|
|
1410
|
+
// `web` and `system` match, then the repo root ends the run → score 2.
|
|
1411
|
+
let score = 0;
|
|
1412
|
+
while (score < dirSegments.length &&
|
|
1413
|
+
score < dirs.length &&
|
|
1414
|
+
dirSegments[dirSegments.length - 1 - score].toLowerCase() ===
|
|
1415
|
+
dirs[dirs.length - 1 - score].toLowerCase()) {
|
|
1416
|
+
score++;
|
|
1417
|
+
}
|
|
1418
|
+
if (score > bestScore) {
|
|
1419
|
+
best = cand;
|
|
1420
|
+
bestScore = score;
|
|
1421
|
+
tie = false;
|
|
1422
|
+
}
|
|
1423
|
+
else if (score === bestScore && score > 0) {
|
|
1424
|
+
tie = true;
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
if (!best || bestScore === 0 || tie)
|
|
1428
|
+
return null;
|
|
1429
|
+
return { original: ref, targetNodeId: best.id, confidence: 0.9, resolvedBy: 'qualified-name' };
|
|
1430
|
+
}
|
|
1130
1431
|
/**
|
|
1131
1432
|
* Resolve a `this.<member>` function-as-value reference (#756/#808) to the
|
|
1132
1433
|
* ENCLOSING CLASS's own member — never a same-named symbol elsewhere. The
|
|
@@ -1186,14 +1487,18 @@ class ReferenceResolver {
|
|
|
1186
1487
|
* Mirrors resolveChainedCallsViaConformance's lifecycle. Returns the number
|
|
1187
1488
|
* of newly-created edges.
|
|
1188
1489
|
*/
|
|
1189
|
-
resolveDeferredThisMemberRefs() {
|
|
1490
|
+
async resolveDeferredThisMemberRefs() {
|
|
1190
1491
|
const deferred = this.deferredThisMemberRefs;
|
|
1191
1492
|
this.deferredThisMemberRefs = [];
|
|
1192
1493
|
if (deferred.length === 0)
|
|
1193
1494
|
return 0;
|
|
1194
1495
|
this.clearCaches();
|
|
1496
|
+
// Synchronous main-thread post-pass with a per-ref supertype BFS — yield
|
|
1497
|
+
// periodically so the #850 liveness watchdog heartbeat can fire (#1091).
|
|
1498
|
+
const maybeYield = (0, cooperative_yield_1.createYielder)();
|
|
1195
1499
|
const resolved = [];
|
|
1196
1500
|
for (const ref of deferred) {
|
|
1501
|
+
await maybeYield();
|
|
1197
1502
|
const member = ref.referenceName.slice('this.'.length);
|
|
1198
1503
|
const fromNode = this.queries.getNodeById(ref.fromNodeId);
|
|
1199
1504
|
if (!fromNode || !member)
|