homegraph 1.4.1 → 1.5.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/README.md +48 -11
- package/dist/bin/homegraph.js +295 -72
- package/dist/bin/homegraph.js.map +1 -1
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js +32 -11
- package/dist/context/index.js.map +1 -1
- package/dist/db/index.d.ts +143 -1
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +293 -16
- package/dist/db/index.js.map +1 -1
- package/dist/db/queries.d.ts +43 -4
- package/dist/db/queries.d.ts.map +1 -1
- package/dist/db/queries.js +138 -14
- package/dist/db/queries.js.map +1 -1
- package/dist/db/sqlite-adapter.d.ts +24 -17
- package/dist/db/sqlite-adapter.d.ts.map +1 -1
- package/dist/db/sqlite-adapter.js +292 -36
- package/dist/db/sqlite-adapter.js.map +1 -1
- package/dist/db/wal-valve.d.ts +15 -2
- package/dist/db/wal-valve.d.ts.map +1 -1
- package/dist/db/wal-valve.js +88 -6
- package/dist/db/wal-valve.js.map +1 -1
- package/dist/extraction/arkts-batch-worker.js +3 -2
- package/dist/extraction/arkts-batch-worker.js.map +1 -1
- package/dist/extraction/default-ignore.d.ts +39 -0
- package/dist/extraction/default-ignore.d.ts.map +1 -0
- package/dist/extraction/default-ignore.js +221 -0
- package/dist/extraction/default-ignore.js.map +1 -0
- package/dist/extraction/index.d.ts +9 -10
- package/dist/extraction/index.d.ts.map +1 -1
- package/dist/extraction/index.js +227 -323
- package/dist/extraction/index.js.map +1 -1
- package/dist/extraction/languages/arkts.d.ts +90 -6
- package/dist/extraction/languages/arkts.d.ts.map +1 -1
- package/dist/extraction/languages/arkts.js +1579 -128
- package/dist/extraction/languages/arkts.js.map +1 -1
- package/dist/extraction/store-worker.d.ts +20 -0
- package/dist/extraction/store-worker.d.ts.map +1 -0
- package/dist/extraction/store-worker.js +102 -0
- package/dist/extraction/store-worker.js.map +1 -0
- package/dist/extraction/store-writer.d.ts +48 -0
- package/dist/extraction/store-writer.d.ts.map +1 -0
- package/dist/extraction/store-writer.js +167 -0
- package/dist/extraction/store-writer.js.map +1 -0
- package/dist/extraction/tree-sitter.d.ts.map +1 -1
- package/dist/extraction/tree-sitter.js +47 -0
- package/dist/extraction/tree-sitter.js.map +1 -1
- package/dist/extraction/wasm-runtime-flags.d.ts +14 -4
- package/dist/extraction/wasm-runtime-flags.d.ts.map +1 -1
- package/dist/extraction/wasm-runtime-flags.js +55 -7
- package/dist/extraction/wasm-runtime-flags.js.map +1 -1
- package/dist/index.d.ts +16 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +135 -97
- package/dist/index.js.map +1 -1
- package/dist/mcp/query-worker.d.ts +2 -2
- package/dist/mcp/query-worker.js +2 -2
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +42 -26
- package/dist/mcp/tools.js.map +1 -1
- package/dist/resolution/callback-synthesizer.d.ts +52 -16
- package/dist/resolution/callback-synthesizer.d.ts.map +1 -1
- package/dist/resolution/callback-synthesizer.js +234 -180
- package/dist/resolution/callback-synthesizer.js.map +1 -1
- package/dist/resolution/cooperative-yield.d.ts +10 -2
- package/dist/resolution/cooperative-yield.d.ts.map +1 -1
- package/dist/resolution/cooperative-yield.js +6 -4
- package/dist/resolution/cooperative-yield.js.map +1 -1
- package/dist/resolution/frameworks/go.d.ts.map +1 -1
- package/dist/resolution/frameworks/go.js +29 -6
- package/dist/resolution/frameworks/go.js.map +1 -1
- package/dist/resolution/import-resolver.d.ts +2 -3
- package/dist/resolution/import-resolver.d.ts.map +1 -1
- package/dist/resolution/import-resolver.js +166 -7
- package/dist/resolution/import-resolver.js.map +1 -1
- package/dist/resolution/index.d.ts +87 -2
- package/dist/resolution/index.d.ts.map +1 -1
- package/dist/resolution/index.js +739 -131
- package/dist/resolution/index.js.map +1 -1
- package/dist/resolution/memory-budget.d.ts +48 -0
- package/dist/resolution/memory-budget.d.ts.map +1 -0
- package/dist/resolution/memory-budget.js +162 -0
- package/dist/resolution/memory-budget.js.map +1 -0
- package/dist/resolution/name-matcher.d.ts +12 -1
- package/dist/resolution/name-matcher.d.ts.map +1 -1
- package/dist/resolution/name-matcher.js +439 -97
- package/dist/resolution/name-matcher.js.map +1 -1
- package/dist/resolution/resolver-pool.d.ts +106 -0
- package/dist/resolution/resolver-pool.d.ts.map +1 -0
- package/dist/resolution/resolver-pool.js +344 -0
- package/dist/resolution/resolver-pool.js.map +1 -0
- package/dist/resolution/resolver-worker.d.ts +17 -0
- package/dist/resolution/resolver-worker.d.ts.map +1 -0
- package/dist/resolution/resolver-worker.js +141 -0
- package/dist/resolution/resolver-worker.js.map +1 -0
- package/dist/resolution/types.d.ts +3 -0
- package/dist/resolution/types.d.ts.map +1 -1
- package/dist/spec/build/diff-parser.d.ts +55 -0
- package/dist/spec/build/diff-parser.d.ts.map +1 -0
- package/dist/spec/build/diff-parser.js +205 -0
- package/dist/spec/build/diff-parser.js.map +1 -0
- package/dist/spec/build/git-scanner.d.ts +93 -0
- package/dist/spec/build/git-scanner.d.ts.map +1 -0
- package/dist/spec/build/git-scanner.js +254 -0
- package/dist/spec/build/git-scanner.js.map +1 -0
- package/dist/spec/build/pipeline.d.ts +54 -0
- package/dist/spec/build/pipeline.d.ts.map +1 -0
- package/dist/spec/build/pipeline.js +170 -0
- package/dist/spec/build/pipeline.js.map +1 -0
- package/dist/spec/build/scan.d.ts +48 -0
- package/dist/spec/build/scan.d.ts.map +1 -0
- package/dist/spec/build/scan.js +89 -0
- package/dist/spec/build/scan.js.map +1 -0
- package/dist/spec/build/scope-resolver.d.ts +50 -0
- package/dist/spec/build/scope-resolver.d.ts.map +1 -0
- package/dist/spec/build/scope-resolver.js +105 -0
- package/dist/spec/build/scope-resolver.js.map +1 -0
- package/dist/spec/build/spec-extractor.d.ts +74 -0
- package/dist/spec/build/spec-extractor.d.ts.map +1 -0
- package/dist/spec/build/spec-extractor.js +344 -0
- package/dist/spec/build/spec-extractor.js.map +1 -0
- package/dist/spec/config.d.ts +35 -1
- package/dist/spec/config.d.ts.map +1 -1
- package/dist/spec/config.js +30 -5
- package/dist/spec/config.js.map +1 -1
- package/dist/spec/db/fts.d.ts.map +1 -1
- package/dist/spec/db/fts.js +19 -50
- package/dist/spec/db/fts.js.map +1 -1
- package/dist/spec/db/index.d.ts +5 -3
- package/dist/spec/db/index.d.ts.map +1 -1
- package/dist/spec/db/index.js +16 -1
- package/dist/spec/db/index.js.map +1 -1
- package/dist/spec/db/persist.d.ts +45 -0
- package/dist/spec/db/persist.d.ts.map +1 -0
- package/dist/spec/db/persist.js +66 -0
- package/dist/spec/db/persist.js.map +1 -0
- package/dist/spec/db/relations.d.ts +80 -1
- package/dist/spec/db/relations.d.ts.map +1 -1
- package/dist/spec/db/relations.js +175 -4
- package/dist/spec/db/relations.js.map +1 -1
- package/dist/spec/db/schema.d.ts +4 -0
- package/dist/spec/db/schema.d.ts.map +1 -1
- package/dist/spec/db/schema.js +4 -0
- package/dist/spec/db/schema.js.map +1 -1
- package/dist/spec/db/schema.sql +5 -1
- package/dist/spec/db/spec-node.d.ts +5 -0
- package/dist/spec/db/spec-node.d.ts.map +1 -1
- package/dist/spec/db/spec-node.js +11 -5
- package/dist/spec/db/spec-node.js.map +1 -1
- package/dist/spec/db/sql-utils.d.ts +11 -0
- package/dist/spec/db/sql-utils.d.ts.map +1 -0
- package/dist/spec/db/sql-utils.js +19 -0
- package/dist/spec/db/sql-utils.js.map +1 -0
- package/dist/spec/evolve/cluster-context.d.ts +30 -0
- package/dist/spec/evolve/cluster-context.d.ts.map +1 -0
- package/dist/spec/evolve/cluster-context.js +78 -0
- package/dist/spec/evolve/cluster-context.js.map +1 -0
- package/dist/spec/evolve/commit-spec-analyzer.d.ts +51 -0
- package/dist/spec/evolve/commit-spec-analyzer.d.ts.map +1 -0
- package/dist/spec/evolve/commit-spec-analyzer.js +88 -0
- package/dist/spec/evolve/commit-spec-analyzer.js.map +1 -0
- package/dist/spec/evolve/commit-spec-persister.d.ts +53 -0
- package/dist/spec/evolve/commit-spec-persister.d.ts.map +1 -0
- package/dist/spec/evolve/commit-spec-persister.js +93 -0
- package/dist/spec/evolve/commit-spec-persister.js.map +1 -0
- package/dist/spec/evolve/impact-locator.d.ts +23 -7
- package/dist/spec/evolve/impact-locator.d.ts.map +1 -1
- package/dist/spec/evolve/impact-locator.js +58 -14
- package/dist/spec/evolve/impact-locator.js.map +1 -1
- package/dist/spec/evolve/pipeline.d.ts +62 -25
- package/dist/spec/evolve/pipeline.d.ts.map +1 -1
- package/dist/spec/evolve/pipeline.js +436 -457
- package/dist/spec/evolve/pipeline.js.map +1 -1
- package/dist/spec/evolve/spec-rewriter.d.ts +13 -13
- package/dist/spec/evolve/spec-rewriter.d.ts.map +1 -1
- package/dist/spec/evolve/spec-rewriter.js +45 -45
- package/dist/spec/evolve/spec-rewriter.js.map +1 -1
- package/dist/spec/git/commits.d.ts +85 -0
- package/dist/spec/git/commits.d.ts.map +1 -0
- package/dist/spec/git/commits.js +218 -0
- package/dist/spec/git/commits.js.map +1 -0
- package/dist/spec/git/exec.d.ts +13 -0
- package/dist/spec/git/exec.d.ts.map +1 -0
- package/dist/spec/git/exec.js +19 -0
- package/dist/spec/git/exec.js.map +1 -0
- package/dist/spec/git/index.d.ts +9 -0
- package/dist/spec/git/index.d.ts.map +1 -0
- package/dist/spec/git/index.js +22 -0
- package/dist/spec/git/index.js.map +1 -0
- package/dist/spec/git-utils.d.ts +8 -0
- package/dist/spec/git-utils.d.ts.map +1 -0
- package/dist/spec/git-utils.js +14 -0
- package/dist/spec/git-utils.js.map +1 -0
- package/dist/spec/graph/index.d.ts +8 -0
- package/dist/spec/graph/index.d.ts.map +1 -0
- package/dist/spec/graph/index.js +17 -0
- package/dist/spec/graph/index.js.map +1 -0
- package/dist/spec/graph/queries.d.ts +6 -35
- package/dist/spec/graph/queries.d.ts.map +1 -1
- package/dist/spec/graph/queries.js +71 -248
- package/dist/spec/graph/queries.js.map +1 -1
- package/dist/spec/llm/agent-client.d.ts +59 -0
- package/dist/spec/llm/agent-client.d.ts.map +1 -0
- package/dist/spec/llm/agent-client.js +213 -0
- package/dist/spec/llm/agent-client.js.map +1 -0
- package/dist/spec/llm/agents/claude-code.d.ts +32 -0
- package/dist/spec/llm/agents/claude-code.d.ts.map +1 -0
- package/dist/spec/llm/agents/claude-code.js +125 -0
- package/dist/spec/llm/agents/claude-code.js.map +1 -0
- package/dist/spec/llm/agents/codex.d.ts +32 -0
- package/dist/spec/llm/agents/codex.d.ts.map +1 -0
- package/dist/spec/llm/agents/codex.js +145 -0
- package/dist/spec/llm/agents/codex.js.map +1 -0
- package/dist/spec/llm/agents/detect-utils.d.ts +28 -0
- package/dist/spec/llm/agents/detect-utils.d.ts.map +1 -0
- package/dist/spec/llm/agents/detect-utils.js +91 -0
- package/dist/spec/llm/agents/detect-utils.js.map +1 -0
- package/dist/spec/llm/agents/deveco-code.d.ts +33 -0
- package/dist/spec/llm/agents/deveco-code.d.ts.map +1 -0
- package/dist/spec/llm/agents/deveco-code.js +165 -0
- package/dist/spec/llm/agents/deveco-code.js.map +1 -0
- package/dist/spec/llm/agents/index.d.ts +31 -0
- package/dist/spec/llm/agents/index.d.ts.map +1 -0
- package/dist/spec/llm/agents/index.js +65 -0
- package/dist/spec/llm/agents/index.js.map +1 -0
- package/dist/spec/llm/agents/types.d.ts +76 -0
- package/dist/spec/llm/agents/types.d.ts.map +1 -0
- package/dist/spec/llm/agents/types.js +15 -0
- package/dist/spec/llm/agents/types.js.map +1 -0
- package/dist/spec/llm/client.d.ts +31 -11
- package/dist/spec/llm/client.d.ts.map +1 -1
- package/dist/spec/llm/client.js +143 -81
- package/dist/spec/llm/client.js.map +1 -1
- package/dist/spec/llm/factory.d.ts +41 -0
- package/dist/spec/llm/factory.d.ts.map +1 -0
- package/dist/spec/llm/factory.js +80 -0
- package/dist/spec/llm/factory.js.map +1 -0
- package/dist/spec/llm/prompts.d.ts +24 -8
- package/dist/spec/llm/prompts.d.ts.map +1 -1
- package/dist/spec/llm/prompts.js +100 -50
- package/dist/spec/llm/prompts.js.map +1 -1
- package/dist/spec/llm/retry.d.ts +53 -0
- package/dist/spec/llm/retry.d.ts.map +1 -0
- package/dist/spec/llm/retry.js +153 -0
- package/dist/spec/llm/retry.js.map +1 -0
- package/dist/spec/mine/clusterer.d.ts +63 -0
- package/dist/spec/mine/clusterer.d.ts.map +1 -0
- package/dist/spec/mine/clusterer.js +904 -0
- package/dist/spec/mine/clusterer.js.map +1 -0
- package/dist/spec/mine/clustering/features.d.ts +38 -0
- package/dist/spec/mine/clustering/features.d.ts.map +1 -0
- package/dist/spec/mine/clustering/features.js +108 -0
- package/dist/spec/mine/clustering/features.js.map +1 -0
- package/dist/spec/mine/clustering/index.d.ts +62 -0
- package/dist/spec/mine/clustering/index.d.ts.map +1 -0
- package/dist/spec/mine/clustering/index.js +259 -0
- package/dist/spec/mine/clustering/index.js.map +1 -0
- package/dist/spec/mine/clustering/leiden.d.ts +61 -0
- package/dist/spec/mine/clustering/leiden.d.ts.map +1 -0
- package/dist/spec/mine/clustering/leiden.js +489 -0
- package/dist/spec/mine/clustering/leiden.js.map +1 -0
- package/dist/spec/mine/clustering/text-similarity.d.ts +22 -0
- package/dist/spec/mine/clustering/text-similarity.d.ts.map +1 -0
- package/dist/spec/mine/clustering/text-similarity.js +98 -0
- package/dist/spec/mine/clustering/text-similarity.js.map +1 -0
- package/dist/spec/mine/generator.d.ts +54 -0
- package/dist/spec/mine/generator.d.ts.map +1 -0
- package/dist/spec/mine/generator.js +267 -0
- package/dist/spec/mine/generator.js.map +1 -0
- package/dist/spec/mine/persist.d.ts +37 -0
- package/dist/spec/mine/persist.d.ts.map +1 -0
- package/dist/spec/mine/persist.js +170 -0
- package/dist/spec/mine/persist.js.map +1 -0
- package/dist/spec/mine/pipeline.d.ts +41 -0
- package/dist/spec/mine/pipeline.d.ts.map +1 -0
- package/dist/spec/mine/pipeline.js +236 -0
- package/dist/spec/mine/pipeline.js.map +1 -0
- package/dist/spec/mine/progress-handler.d.ts +22 -0
- package/dist/spec/mine/progress-handler.d.ts.map +1 -0
- package/dist/spec/mine/progress-handler.js +108 -0
- package/dist/spec/mine/progress-handler.js.map +1 -0
- package/dist/spec/mine/progress.d.ts +23 -0
- package/dist/spec/mine/progress.d.ts.map +1 -0
- package/dist/spec/mine/progress.js +12 -0
- package/dist/spec/mine/progress.js.map +1 -0
- package/dist/spec/mine/scanner.d.ts +59 -0
- package/dist/spec/mine/scanner.d.ts.map +1 -0
- package/dist/spec/mine/scanner.js +383 -0
- package/dist/spec/mine/scanner.js.map +1 -0
- package/dist/spec/types.d.ts +32 -0
- package/dist/spec/types.d.ts.map +1 -1
- package/dist/spec/ui/index.d.ts +9 -0
- package/dist/spec/ui/index.d.ts.map +1 -0
- package/dist/spec/ui/index.js +16 -0
- package/dist/spec/ui/index.js.map +1 -0
- package/dist/spec/ui/progress-handler.d.ts +33 -0
- package/dist/spec/ui/progress-handler.d.ts.map +1 -0
- package/dist/spec/ui/progress-handler.js +132 -0
- package/dist/spec/ui/progress-handler.js.map +1 -0
- package/dist/spec/ui/progress.d.ts +24 -0
- package/dist/spec/ui/progress.d.ts.map +1 -0
- package/dist/spec/ui/progress.js +13 -0
- package/dist/spec/ui/progress.js.map +1 -0
- package/dist/spec/utils/fs.d.ts +45 -0
- package/dist/spec/utils/fs.d.ts.map +1 -0
- package/dist/spec/utils/fs.js +163 -0
- package/dist/spec/utils/fs.js.map +1 -0
- package/dist/spec/utils/index.d.ts +12 -0
- package/dist/spec/utils/index.d.ts.map +1 -0
- package/dist/spec/utils/index.js +26 -0
- package/dist/spec/utils/index.js.map +1 -0
- package/dist/spec/utils/meta.d.ts +32 -0
- package/dist/spec/utils/meta.d.ts.map +1 -0
- package/dist/spec/utils/meta.js +122 -0
- package/dist/spec/utils/meta.js.map +1 -0
- package/dist/spec/utils/truncate.d.ts +86 -0
- package/dist/spec/utils/truncate.d.ts.map +1 -0
- package/dist/spec/utils/truncate.js +172 -0
- package/dist/spec/utils/truncate.js.map +1 -0
- package/dist/spec/utils.d.ts +4 -16
- package/dist/spec/utils.d.ts.map +1 -1
- package/dist/spec/utils.js +6 -58
- package/dist/spec/utils.js.map +1 -1
- package/dist/sync/watcher.d.ts +25 -1
- package/dist/sync/watcher.d.ts.map +1 -1
- package/dist/sync/watcher.js +76 -3
- package/dist/sync/watcher.js.map +1 -1
- package/dist/telemetry/index.js +3 -3
- package/dist/telemetry/index.js.map +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +7 -3
|
@@ -1,23 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Callback / observer edge synthesis — Phase 1 + 2.
|
|
3
|
+
*
|
|
4
|
+
* Closes dynamic-dispatch holes where a dispatcher invokes callbacks registered
|
|
5
|
+
* elsewhere. Two channel shapes:
|
|
6
|
+
*
|
|
7
|
+
* (1) Field-backed observer (Phase 1):
|
|
8
|
+
* onUpdate(cb) { this.callbacks.add(cb); } // registrar
|
|
9
|
+
* triggerUpdate() { for (cb of this.callbacks) cb(); } // dispatcher
|
|
10
|
+
* scene.onUpdate(this.triggerRender) // registration
|
|
11
|
+
* → synthesize triggerUpdate → triggerRender
|
|
12
|
+
*
|
|
13
|
+
* (2) String-keyed EventEmitter (Phase 2):
|
|
14
|
+
* this.on('mount', function onmount(){...}) // registration
|
|
15
|
+
* fn.emit('mount', this) // dispatch
|
|
16
|
+
* → synthesize (method containing emit('mount')) → onmount
|
|
17
|
+
*
|
|
18
|
+
* Whole-graph pass after base resolution. High-precision/low-recall by design:
|
|
19
|
+
* named callbacks only; field channels paired by file+field; EventEmitter
|
|
20
|
+
* channels capped by event fan-out (generic names like 'error' skipped — they
|
|
21
|
+
* need receiver-type matching, deferred to Phase 3). All synthesized edges are
|
|
22
|
+
* tagged `provenance:'heuristic'`. See docs/design/callback-edge-synthesis.md.
|
|
23
|
+
*/
|
|
24
|
+
import type { Edge } from '../types';
|
|
1
25
|
import type { QueryBuilder } from '../db/queries';
|
|
2
26
|
import type { ResolutionContext } from './types';
|
|
27
|
+
import { type MaybeYield } from './cooperative-yield';
|
|
28
|
+
/** `has(...)` shape passed to pass gates — true when the project contains any of the languages. */
|
|
29
|
+
type HasLang = (...ls: string[]) => boolean;
|
|
3
30
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* MediatR Send/Publish → IRequestHandler/INotificationHandler +
|
|
11
|
-
* Sidekiq Worker.perform_async → #perform + Laravel event(new X) → listener handle).
|
|
12
|
-
* Returns the count added. Never throws into indexing — callers wrap in try/catch.
|
|
31
|
+
* One independent synthesis pass. Every pass scans the COMMITTED graph (plus
|
|
32
|
+
* source via ctx) and returns an edge list; nothing it produces is persisted
|
|
33
|
+
* until the ordered merge in synthesizeCallbackEdges — which is what makes
|
|
34
|
+
* execution order free and the passes safe to fan out across the resolver
|
|
35
|
+
* pool's read-only workers. `gate` short-circuits a pass whose language never
|
|
36
|
+
* appears in the project (its result is provably empty — see #1212).
|
|
13
37
|
*/
|
|
38
|
+
export interface SynthPassDef {
|
|
39
|
+
name: string;
|
|
40
|
+
gate: (has: HasLang) => boolean;
|
|
41
|
+
run: (queries: QueryBuilder, ctx: ResolutionContext, yieldToLoop: MaybeYield, subProgress?: (fraction: number) => void) => Promise<Edge[]>;
|
|
42
|
+
}
|
|
14
43
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
44
|
+
* The independent passes, in MERGE ORDER — the first-seen dedup in
|
|
45
|
+
* synthesizeCallbackEdges follows this array, so reordering entries changes
|
|
46
|
+
* which duplicate edge wins. The two Go pre-passes (cross-file method
|
|
47
|
+
* `contains`, implicit `implements`) are NOT here: they persist before these
|
|
48
|
+
* run because interfaceOverrideEdges reads their edges from the DB.
|
|
20
49
|
*/
|
|
21
|
-
export declare const
|
|
22
|
-
export declare
|
|
50
|
+
export declare const SYNTH_PASSES: SynthPassDef[];
|
|
51
|
+
export declare const SYNTH_PROGRESS_STEPS: number;
|
|
52
|
+
export declare function synthesizeCallbackEdges(queries: QueryBuilder, ctx: ResolutionContext, onProgress?: (done: number, total: number) => void, pool?: {
|
|
53
|
+
runSynthPass(name: string): Promise<{
|
|
54
|
+
edges: Edge[];
|
|
55
|
+
ms: number;
|
|
56
|
+
}>;
|
|
57
|
+
} | null, backpressure?: () => Promise<void> | null): Promise<number>;
|
|
58
|
+
export {};
|
|
23
59
|
//# sourceMappingURL=callback-synthesizer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"callback-synthesizer.d.ts","sourceRoot":"","sources":["../../src/resolution/callback-synthesizer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"callback-synthesizer.d.ts","sourceRoot":"","sources":["../../src/resolution/callback-synthesizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,EAAE,IAAI,EAAkB,MAAM,UAAU,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AASjD,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AA64GrE,mGAAmG;AACnG,KAAK,OAAO,GAAG,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC;AAE5C;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC;IAChC,GAAG,EAAE,CACH,OAAO,EAAE,YAAY,EACrB,GAAG,EAAE,iBAAiB,EACtB,WAAW,EAAE,UAAU,EACvB,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,KACrC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;CACtB;AA6FD;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,EAAE,YAAY,EA6DtC,CAAC;AAIF,eAAO,MAAM,oBAAoB,QAA0C,CAAC;AAC5E,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,YAAY,EACrB,GAAG,EAAE,iBAAiB,EACtB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,EAIlD,IAAI,CAAC,EAAE;IAAE,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,GAAG,IAAI,EAIpF,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GACxC,OAAO,CAAC,MAAM,CAAC,CAmLjB"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SYNTH_PROGRESS_STEPS = void 0;
|
|
3
|
+
exports.SYNTH_PROGRESS_STEPS = exports.SYNTH_PASSES = void 0;
|
|
4
4
|
exports.synthesizeCallbackEdges = synthesizeCallbackEdges;
|
|
5
5
|
const generated_detection_1 = require("../extraction/generated-detection");
|
|
6
6
|
const strip_comments_1 = require("./strip-comments");
|
|
7
7
|
const c_fnptr_synthesizer_1 = require("./c-fnptr-synthesizer");
|
|
8
8
|
const goframe_synthesizer_1 = require("./goframe-synthesizer");
|
|
9
|
-
const cooperative_yield_1 = require("./cooperative-yield");
|
|
10
9
|
const arkts_entry_1 = require("./frameworks/arkts-entry");
|
|
10
|
+
const cooperative_yield_1 = require("./cooperative-yield");
|
|
11
11
|
const REGISTRAR_NAME = /^(on[A-Z]\w*|subscribe|addListener|addEventListener|register|watch|listen|addCallback)$/;
|
|
12
12
|
const DISPATCHER_NAME = /(emit|trigger|notify|dispatch|fire|publish|flush)/i;
|
|
13
13
|
const MAX_CALLBACKS_PER_CHANNEL = 40;
|
|
@@ -413,9 +413,28 @@ async function reactRenderEdges(queries, ctx, onYield) {
|
|
|
413
413
|
let scanned255 = 0;
|
|
414
414
|
const edges = [];
|
|
415
415
|
const seen = new Set();
|
|
416
|
+
// A class can only emit here if it CONTAINS a method named `render` — so one
|
|
417
|
+
// indexed name lookup bounds the candidate set up front, and the class scan
|
|
418
|
+
// below skips everything else before its per-class edge/node queries. On a
|
|
419
|
+
// repo with few/no render methods (any non-React codebase) this collapses
|
|
420
|
+
// the pass from every-class fan-out to ~zero DB work, with identical output:
|
|
421
|
+
// the skipped classes fail the same `render` check today, just after paying
|
|
422
|
+
// for their children. (Not a language gate: `render` + `this.setState(` in
|
|
423
|
+
// Java — e.g. Litho — legitimately matches today and still does.)
|
|
424
|
+
const renderOwners = new Set();
|
|
425
|
+
for (const n of ctx.getNodesByName('render')) {
|
|
426
|
+
if (n.kind !== 'method')
|
|
427
|
+
continue;
|
|
428
|
+
for (const e of queries.getIncomingEdges(n.id, ['contains']))
|
|
429
|
+
renderOwners.add(e.source);
|
|
430
|
+
}
|
|
431
|
+
if (renderOwners.size === 0)
|
|
432
|
+
return edges;
|
|
416
433
|
for (const cls of queries.iterateNodesByKind('class')) {
|
|
417
434
|
if ((++scanned255 & 63) === 0)
|
|
418
435
|
await onYield();
|
|
436
|
+
if (!renderOwners.has(cls.id))
|
|
437
|
+
continue;
|
|
419
438
|
const children = queries.getOutgoingEdges(cls.id, ['contains'])
|
|
420
439
|
.map((e) => queries.getNodeById(e.target))
|
|
421
440
|
.filter((n) => !!n && n.kind === 'method');
|
|
@@ -1073,10 +1092,21 @@ async function interfaceOverrideEdges(queries, onYield) {
|
|
|
1073
1092
|
let scanned255 = 0;
|
|
1074
1093
|
const edges = [];
|
|
1075
1094
|
const seen = new Set();
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1095
|
+
// Memoized: a popular base interface's method list is otherwise re-fetched
|
|
1096
|
+
// once per implementer (dubbo-style hub interfaces have hundreds), and the
|
|
1097
|
+
// memo only ever serves reads. Same rows, same order — byte-identical.
|
|
1098
|
+
const methodsMemo = new Map();
|
|
1099
|
+
const methodsOf = (classId) => {
|
|
1100
|
+
const hit = methodsMemo.get(classId);
|
|
1101
|
+
if (hit)
|
|
1102
|
+
return hit;
|
|
1103
|
+
const methods = queries
|
|
1104
|
+
.getOutgoingEdges(classId, ['contains'])
|
|
1105
|
+
.map((e) => queries.getNodeById(e.target))
|
|
1106
|
+
.filter((n) => !!n && n.kind === 'method');
|
|
1107
|
+
methodsMemo.set(classId, methods);
|
|
1108
|
+
return methods;
|
|
1109
|
+
};
|
|
1080
1110
|
// Concrete-side kinds vary by language: `class` covers Java / Kotlin /
|
|
1081
1111
|
// C# / TS / Swift-classes / Scala-classes; `struct` covers Swift value
|
|
1082
1112
|
// types that conform to protocols. Iterate both.
|
|
@@ -1085,10 +1115,16 @@ async function interfaceOverrideEdges(queries, onYield) {
|
|
|
1085
1115
|
for (const cls of queries.iterateNodesByKind(kind)) {
|
|
1086
1116
|
if ((++scanned255 & 63) === 0)
|
|
1087
1117
|
await onYield();
|
|
1118
|
+
// A class can only emit here if it HAS a supertype edge — check that
|
|
1119
|
+
// (one edge query) before materializing its methods: most classes in a
|
|
1120
|
+
// typical graph extend/implement nothing and skip in one hop.
|
|
1121
|
+
const sups = queries.getOutgoingEdges(cls.id, ['implements', 'extends']);
|
|
1122
|
+
if (sups.length === 0)
|
|
1123
|
+
continue;
|
|
1088
1124
|
const implMethods = methodsOf(cls.id).filter((n) => IFACE_OVERRIDE_LANGS.has(n.language));
|
|
1089
1125
|
if (implMethods.length === 0)
|
|
1090
1126
|
continue;
|
|
1091
|
-
for (const sup of
|
|
1127
|
+
for (const sup of sups) {
|
|
1092
1128
|
const base = queries.getNodeById(sup.target);
|
|
1093
1129
|
if (!base || !IFACE_OVERRIDE_LANGS.has(base.language) || base.id === cls.id)
|
|
1094
1130
|
continue;
|
|
@@ -1878,6 +1914,20 @@ async function mybatisJavaXmlEdges(queries, onYield) {
|
|
|
1878
1914
|
let scanned255 = 0;
|
|
1879
1915
|
const edges = [];
|
|
1880
1916
|
const seen = new Set();
|
|
1917
|
+
// Collect the XML side FIRST (mapper `<select id=…>` statements extracted as
|
|
1918
|
+
// xml-language method nodes): if the project has none — every Java+XML repo
|
|
1919
|
+
// that doesn't use MyBatis — return before paying the full java-method
|
|
1920
|
+
// stream below. Same rowid stream order as matching inline, so the edge
|
|
1921
|
+
// output is byte-identical when mappers do exist.
|
|
1922
|
+
const xmlMethods = [];
|
|
1923
|
+
for (const m of queries.iterateNodesByKind('method')) {
|
|
1924
|
+
if ((++scanned255 & 63) === 0)
|
|
1925
|
+
await onYield();
|
|
1926
|
+
if (m.language === 'xml')
|
|
1927
|
+
xmlMethods.push(m);
|
|
1928
|
+
}
|
|
1929
|
+
if (xmlMethods.length === 0)
|
|
1930
|
+
return edges;
|
|
1881
1931
|
// Index Java methods by `<ClassName>::<methodName>` for O(1) lookup.
|
|
1882
1932
|
const javaIndex = new Map();
|
|
1883
1933
|
for (const m of queries.iterateNodesByKind('method')) {
|
|
@@ -1897,11 +1947,9 @@ async function mybatisJavaXmlEdges(queries, onYield) {
|
|
|
1897
1947
|
else
|
|
1898
1948
|
javaIndex.set(key, [m]);
|
|
1899
1949
|
}
|
|
1900
|
-
for (const xml of
|
|
1950
|
+
for (const xml of xmlMethods) {
|
|
1901
1951
|
if ((++scanned255 & 63) === 0)
|
|
1902
1952
|
await onYield();
|
|
1903
|
-
if (xml.language !== 'xml')
|
|
1904
|
-
continue;
|
|
1905
1953
|
// Qualified name: `<namespace>::<id>`. Extract the simple class name.
|
|
1906
1954
|
const colonIdx = xml.qualifiedName.lastIndexOf('::');
|
|
1907
1955
|
if (colonIdx < 0)
|
|
@@ -3706,6 +3754,26 @@ async function laravelEventEdges(ctx, onYield) {
|
|
|
3706
3754
|
}
|
|
3707
3755
|
return edges;
|
|
3708
3756
|
}
|
|
3757
|
+
/**
|
|
3758
|
+
* Synthesize dispatcher→callback edges (field observers + EventEmitters +
|
|
3759
|
+
* React re-render + JSX children + Vue templates + SvelteKit load + RN event
|
|
3760
|
+
* channel + Fabric native-impl + MyBatis Java↔XML + Gin middleware chain +
|
|
3761
|
+
* Redux-thunk dispatch chain + object-literal registry dispatch + RTK Query
|
|
3762
|
+
* generated-hook → endpoint + Pinia useStore().action() + Vuex string dispatch +
|
|
3763
|
+
* Celery task .delay()/.apply_async() → task body + Spring publishEvent → @EventListener +
|
|
3764
|
+
* MediatR Send/Publish → IRequestHandler/INotificationHandler +
|
|
3765
|
+
* Sidekiq Worker.perform_async → #perform + Laravel event(new X) → listener handle).
|
|
3766
|
+
* Returns the count added. Never throws into indexing — callers wrap in try/catch.
|
|
3767
|
+
*/
|
|
3768
|
+
/**
|
|
3769
|
+
* Number of progress steps synthesizeCallbackEdges reports: one per `__mark()`
|
|
3770
|
+
* call (every synthesis pass, plus the dedupe-merge and edge-insert steps).
|
|
3771
|
+
* Cosmetic only — drift just makes the progress bar end early or jump — and a
|
|
3772
|
+
* test pins it to the actual step count (registry passes + the fixed
|
|
3773
|
+
* pre/post marks) so adding a pass without bumping this fails loudly instead
|
|
3774
|
+
* of silently skewing the bar.
|
|
3775
|
+
*/
|
|
3776
|
+
const JS_FAMILY = ['typescript', 'javascript', 'tsx', 'jsx'];
|
|
3709
3777
|
/** ArkTS startup + UI lifecycle: loadContent → first screen, Ability chain, aboutToAppear → build. */
|
|
3710
3778
|
function arktsEntryEdges(queries, ctx) {
|
|
3711
3779
|
const edges = [];
|
|
@@ -3791,26 +3859,88 @@ function arktsEntryEdges(queries, ctx) {
|
|
|
3791
3859
|
}
|
|
3792
3860
|
return edges;
|
|
3793
3861
|
}
|
|
3862
|
+
const ALWAYS = () => true;
|
|
3794
3863
|
/**
|
|
3795
|
-
*
|
|
3796
|
-
*
|
|
3797
|
-
*
|
|
3798
|
-
*
|
|
3799
|
-
*
|
|
3800
|
-
* Celery task .delay()/.apply_async() → task body + Spring publishEvent → @EventListener +
|
|
3801
|
-
* MediatR Send/Publish → IRequestHandler/INotificationHandler +
|
|
3802
|
-
* Sidekiq Worker.perform_async → #perform + Laravel event(new X) → listener handle).
|
|
3803
|
-
* Returns the count added. Never throws into indexing — callers wrap in try/catch.
|
|
3804
|
-
*/
|
|
3805
|
-
/**
|
|
3806
|
-
* Number of progress steps synthesizeCallbackEdges reports: one per `__mark()`
|
|
3807
|
-
* call (every synthesis pass, plus the dedupe-merge and edge-insert steps).
|
|
3808
|
-
* Cosmetic only — drift just makes the progress bar end early or jump — and a
|
|
3809
|
-
* test pins it to the actual `__mark(` call count so adding a pass without
|
|
3810
|
-
* bumping this fails loudly instead of silently skewing the bar.
|
|
3864
|
+
* The independent passes, in MERGE ORDER — the first-seen dedup in
|
|
3865
|
+
* synthesizeCallbackEdges follows this array, so reordering entries changes
|
|
3866
|
+
* which duplicate edge wins. The two Go pre-passes (cross-file method
|
|
3867
|
+
* `contains`, implicit `implements`) are NOT here: they persist before these
|
|
3868
|
+
* run because interfaceOverrideEdges reads their edges from the DB.
|
|
3811
3869
|
*/
|
|
3812
|
-
exports.
|
|
3813
|
-
|
|
3870
|
+
exports.SYNTH_PASSES = [
|
|
3871
|
+
{ name: 'fieldEdges', gate: ALWAYS, run: (q, c, y) => fieldChannelEdges(q, c, y) },
|
|
3872
|
+
{ name: 'closureCollEdges', gate: ALWAYS, run: (q, c, y) => closureCollectionEdges(q, c, y) },
|
|
3873
|
+
{ name: 'emitterEdges', gate: ALWAYS, run: (_q, c, y) => eventEmitterEdges(c, y) },
|
|
3874
|
+
{ name: 'renderEdges', gate: ALWAYS, run: (q, c, y) => reactRenderEdges(q, c, y) },
|
|
3875
|
+
{ name: 'jsxEdges', gate: ALWAYS, run: (_q, c, y) => reactJsxChildEdges(c, y) },
|
|
3876
|
+
{ name: 'vueEdges', gate: (has) => has('vue'), run: (_q, c, y) => vueTemplateEdges(c, y) },
|
|
3877
|
+
{ name: 'svelteKitEdges', gate: (has) => has('svelte'), run: (_q, c, y) => svelteKitLoadEdges(c, y) },
|
|
3878
|
+
{ name: 'pascalEdges', gate: ALWAYS, run: (_q, c, y) => pascalFormEdges(c, y) },
|
|
3879
|
+
{ name: 'flutterEdges', gate: (has) => has('dart'), run: (q, c, y) => flutterBuildEdges(q, c, y) },
|
|
3880
|
+
{ name: 'arkuiStateEdges', gate: (has) => has('arkts'), run: (q, c, y) => arkuiStateBuildEdges(q, c, y) },
|
|
3881
|
+
{ name: 'arkuiEmitter', gate: (has) => has('arkts'), run: (_q, c, y) => arkuiEmitterEdges(c, y) },
|
|
3882
|
+
{ name: 'arkuiRoutes', gate: (has) => has('arkts'), run: (_q, c, y) => arkuiRouterEdges(c, y) },
|
|
3883
|
+
{ name: 'arktsStartupEdges', gate: (has) => has('arkts'), run: async (q, c) => arktsEntryEdges(q, c) },
|
|
3884
|
+
{ name: 'cppEdges', gate: (has) => has('cpp'), run: (q, _c, y) => cppOverrideEdges(q, y) },
|
|
3885
|
+
{
|
|
3886
|
+
name: 'ifaceEdges',
|
|
3887
|
+
gate: (has) => has('java', 'kotlin', 'csharp', 'swift', 'scala', 'go', 'rust', 'arkts', ...JS_FAMILY),
|
|
3888
|
+
run: (q, _c, y) => interfaceOverrideEdges(q, y),
|
|
3889
|
+
},
|
|
3890
|
+
{ name: 'kotlinExpectActual', gate: (has) => has('kotlin'), run: (q, _c, y) => kotlinExpectActualEdges(q, y) },
|
|
3891
|
+
{ name: 'goGrpcEdges', gate: (has) => has('go'), run: (q, _c, y) => goGrpcStubImplEdges(q, y) },
|
|
3892
|
+
{ name: 'rnEventEdgesList', gate: (has) => has(...JS_FAMILY), run: (_q, c, y) => rnEventEdges(c, y) },
|
|
3893
|
+
{ name: 'fabricNativeEdges', gate: ALWAYS, run: (_q, c, y) => fabricNativeImplEdges(c, y) },
|
|
3894
|
+
// Expo module nodes (`expo-module:` ids) are emitted only from .swift/.kt
|
|
3895
|
+
// files, and a pair needs BOTH platforms — so without both languages the
|
|
3896
|
+
// pass's only collection loop is provably empty (it was streaming every
|
|
3897
|
+
// method row on pure-Java repos to find nothing).
|
|
3898
|
+
{ name: 'expoXPlatEdges', gate: (has) => has('swift') && has('kotlin'), run: (q, _c, y) => expoCrossPlatformEdges(q, y) },
|
|
3899
|
+
// An RN cross-platform edge requires a JS-language caller on the native
|
|
3900
|
+
// method (`isBridge`) — no JS-family files means no JS-language nodes, so
|
|
3901
|
+
// the result is provably empty.
|
|
3902
|
+
{ name: 'rnXPlatEdges', gate: (has) => has(...JS_FAMILY), run: (q, _c, y) => rnCrossPlatformEdges(q, y) },
|
|
3903
|
+
{
|
|
3904
|
+
name: 'mybatisEdges',
|
|
3905
|
+
gate: (has) => has('java', 'kotlin') && has('xml'),
|
|
3906
|
+
run: (q, _c, y) => mybatisJavaXmlEdges(q, y),
|
|
3907
|
+
},
|
|
3908
|
+
{ name: 'ginEdges', gate: (has) => has('go'), run: (q, c, y) => ginMiddlewareChainEdges(q, c, y) },
|
|
3909
|
+
{ name: 'thunkEdges', gate: (has) => has(...JS_FAMILY), run: (q, c, y) => reduxThunkEdges(q, c, y) },
|
|
3910
|
+
{ name: 'registryEdges', gate: ALWAYS, run: (_q, c, y) => objectRegistryEdges(c, y) },
|
|
3911
|
+
{ name: 'rtkEdges', gate: (has) => has(...JS_FAMILY), run: (q, c, y) => rtkQueryEdges(q, c, y) },
|
|
3912
|
+
{ name: 'piniaEdges', gate: (has) => has('vue', ...JS_FAMILY), run: (_q, c, y) => piniaStoreEdges(c, y) },
|
|
3913
|
+
{ name: 'vuexEdges', gate: (has) => has('vue', ...JS_FAMILY), run: (_q, c, y) => vuexDispatchEdges(c, y) },
|
|
3914
|
+
{ name: 'celeryEdges', gate: (has) => has('python'), run: (_q, c, y) => celeryDispatchEdges(c, y) },
|
|
3915
|
+
{ name: 'springEdges', gate: (has) => has('java'), run: (_q, c, y) => springEventEdges(c, y) },
|
|
3916
|
+
{ name: 'mediatrEdges', gate: (has) => has('csharp'), run: (_q, c, y) => mediatrDispatchEdges(c, y) },
|
|
3917
|
+
{ name: 'sidekiqEdges', gate: (has) => has('ruby'), run: (_q, c, y) => sidekiqDispatchEdges(c, y) },
|
|
3918
|
+
{
|
|
3919
|
+
name: 'erlangBehaviourEdges',
|
|
3920
|
+
gate: (has) => has('erlang'),
|
|
3921
|
+
run: (q, c, y) => erlangBehaviourDispatchEdges(q, c, y),
|
|
3922
|
+
},
|
|
3923
|
+
{ name: 'laravelEdges', gate: (has) => has('php'), run: (_q, c, y) => laravelEventEdges(c, y) },
|
|
3924
|
+
{
|
|
3925
|
+
name: 'cFnPtrEdges',
|
|
3926
|
+
gate: (has) => has('c', 'cpp'),
|
|
3927
|
+
run: (q, c, y, sub) => (0, c_fnptr_synthesizer_1.cFnPointerDispatchEdges)(q, c, y, sub),
|
|
3928
|
+
},
|
|
3929
|
+
{ name: 'goframeEdges', gate: (has) => has('go'), run: (_q, c, y) => (0, goframe_synthesizer_1.goframeRouteEdges)(c, y) },
|
|
3930
|
+
{ name: 'nixOptionEdges', gate: (has) => has('nix'), run: (q, _c, y) => nixOptionPathEdges(q, y) },
|
|
3931
|
+
];
|
|
3932
|
+
/** Fixed non-registry steps: goMethodContains, goImplements, dedupe-merge, insertMergedEdges. */
|
|
3933
|
+
const FIXED_SYNTH_STEPS = 4;
|
|
3934
|
+
exports.SYNTH_PROGRESS_STEPS = exports.SYNTH_PASSES.length + FIXED_SYNTH_STEPS;
|
|
3935
|
+
async function synthesizeCallbackEdges(queries, ctx, onProgress,
|
|
3936
|
+
// A live resolver pool to fan the independent passes across (structural type
|
|
3937
|
+
// so this file never imports the pool — resolver-worker imports THIS file).
|
|
3938
|
+
// Null/omitted → the sequential path, byte-identical to the pool path.
|
|
3939
|
+
pool,
|
|
3940
|
+
// WAL-valve writer backstop (WalCheckpointValve.backpressure), called at
|
|
3941
|
+
// pool-idle points in the edge-insert loops below — the passes themselves
|
|
3942
|
+
// only read; every write in this function happens with the pool idle.
|
|
3943
|
+
backpressure) {
|
|
3814
3944
|
// Each sub-pass below is a whole-graph scan, and there are ~30 of them, all
|
|
3815
3945
|
// running synchronously on the indexer's main thread. Their AGGREGATE can run
|
|
3816
3946
|
// for well over a minute on a large repo — long enough for the #850 liveness
|
|
@@ -3865,17 +3995,24 @@ async function synthesizeCallbackEdges(queries, ctx, onProgress) {
|
|
|
3865
3995
|
// Passes without an explicit language filter always run.
|
|
3866
3996
|
const langs = queries.getDistinctFileLanguages();
|
|
3867
3997
|
const has = (...ls) => ls.some((l) => langs.has(l));
|
|
3868
|
-
const JS_FAMILY = ['typescript', 'javascript', 'tsx', 'jsx'];
|
|
3869
3998
|
const NONE = [];
|
|
3870
3999
|
// Cross-file Go method→type `contains` edges must be synthesized AND persisted
|
|
3871
4000
|
// FIRST: a method declared in a different file from its receiver type is
|
|
3872
4001
|
// otherwise orphaned from the struct, and goImplementsEdges (next) derives a
|
|
3873
4002
|
// struct's method set from its `contains` edges — so without this it would
|
|
3874
4003
|
// under-count the interfaces a cross-file struct satisfies. (#583)
|
|
4004
|
+
// Writer-side WAL backstop for the insert loops here (see the param doc):
|
|
4005
|
+
// one fstat when under the valve's hard cap, a parked full backfill past it.
|
|
4006
|
+
const foldIfOver = async () => {
|
|
4007
|
+
const bp = backpressure?.();
|
|
4008
|
+
if (bp)
|
|
4009
|
+
await bp;
|
|
4010
|
+
};
|
|
3875
4011
|
const goMethodContains = has('go') ? await goCrossFileMethodContainsEdges(queries, yieldToLoop) : NONE;
|
|
3876
4012
|
for (let i = 0; i < goMethodContains.length; i += 2000) {
|
|
3877
4013
|
queries.insertEdges(goMethodContains.slice(i, i + 2000));
|
|
3878
4014
|
await yieldToLoop();
|
|
4015
|
+
await foldIfOver();
|
|
3879
4016
|
}
|
|
3880
4017
|
await yieldToLoop();
|
|
3881
4018
|
__mark('goMethodContains');
|
|
@@ -3887,162 +4024,78 @@ async function synthesizeCallbackEdges(queries, ctx, onProgress) {
|
|
|
3887
4024
|
for (let i = 0; i < goImpl.length; i += 2000) {
|
|
3888
4025
|
queries.insertEdges(goImpl.slice(i, i + 2000));
|
|
3889
4026
|
await yieldToLoop();
|
|
4027
|
+
await foldIfOver();
|
|
3890
4028
|
}
|
|
3891
4029
|
await yieldToLoop();
|
|
3892
4030
|
__mark('goImplements');
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
const
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
const
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
await yieldToLoop();
|
|
3959
|
-
__mark('ginEdges');
|
|
3960
|
-
const thunkEdges = has(...JS_FAMILY) ? await reduxThunkEdges(queries, ctx, yieldToLoop) : NONE;
|
|
3961
|
-
await yieldToLoop();
|
|
3962
|
-
__mark('thunkEdges');
|
|
3963
|
-
const registryEdges = await objectRegistryEdges(ctx, yieldToLoop);
|
|
3964
|
-
await yieldToLoop();
|
|
3965
|
-
__mark('registryEdges');
|
|
3966
|
-
const rtkEdges = has(...JS_FAMILY) ? await rtkQueryEdges(queries, ctx, yieldToLoop) : NONE;
|
|
3967
|
-
await yieldToLoop();
|
|
3968
|
-
__mark('rtkEdges');
|
|
3969
|
-
const piniaEdges = has('vue', ...JS_FAMILY) ? await piniaStoreEdges(ctx, yieldToLoop) : NONE;
|
|
3970
|
-
await yieldToLoop();
|
|
3971
|
-
__mark('piniaEdges');
|
|
3972
|
-
const vuexEdges = has('vue', ...JS_FAMILY) ? await vuexDispatchEdges(ctx, yieldToLoop) : NONE;
|
|
3973
|
-
await yieldToLoop();
|
|
3974
|
-
__mark('vuexEdges');
|
|
3975
|
-
const celeryEdges = has('python') ? await celeryDispatchEdges(ctx, yieldToLoop) : NONE;
|
|
3976
|
-
await yieldToLoop();
|
|
3977
|
-
__mark('celeryEdges');
|
|
3978
|
-
const springEdges = has('java') ? await springEventEdges(ctx, yieldToLoop) : NONE;
|
|
3979
|
-
await yieldToLoop();
|
|
3980
|
-
__mark('springEdges');
|
|
3981
|
-
const mediatrEdges = has('csharp') ? await mediatrDispatchEdges(ctx, yieldToLoop) : NONE;
|
|
3982
|
-
await yieldToLoop();
|
|
3983
|
-
__mark('mediatrEdges');
|
|
3984
|
-
const sidekiqEdges = has('ruby') ? await sidekiqDispatchEdges(ctx, yieldToLoop) : NONE;
|
|
3985
|
-
await yieldToLoop();
|
|
3986
|
-
__mark('sidekiqEdges');
|
|
3987
|
-
const erlangBehaviourEdges = has('erlang') ? await erlangBehaviourDispatchEdges(queries, ctx, yieldToLoop) : NONE;
|
|
3988
|
-
await yieldToLoop();
|
|
3989
|
-
__mark('erlangBehaviourEdges');
|
|
3990
|
-
const laravelEdges = has('php') ? await laravelEventEdges(ctx, yieldToLoop) : NONE;
|
|
3991
|
-
await yieldToLoop();
|
|
3992
|
-
__mark('laravelEdges');
|
|
3993
|
-
const cFnPtrEdges = has('c', 'cpp') ? await (0, c_fnptr_synthesizer_1.cFnPointerDispatchEdges)(queries, ctx, yieldToLoop, subProgress) : NONE;
|
|
3994
|
-
await yieldToLoop();
|
|
3995
|
-
__mark('cFnPtrEdges');
|
|
3996
|
-
const goframeEdges = has('go') ? await (0, goframe_synthesizer_1.goframeRouteEdges)(ctx, yieldToLoop) : NONE;
|
|
3997
|
-
await yieldToLoop();
|
|
3998
|
-
__mark('goframeEdges');
|
|
3999
|
-
const nixOptionEdges = has('nix') ? await nixOptionPathEdges(queries, yieldToLoop) : NONE;
|
|
4000
|
-
await yieldToLoop();
|
|
4001
|
-
__mark('nixOptionEdges');
|
|
4002
|
-
const arktsStartupEdges = has('arkts') ? arktsEntryEdges(queries, ctx) : NONE;
|
|
4003
|
-
await yieldToLoop();
|
|
4004
|
-
__mark('arktsStartupEdges');
|
|
4031
|
+
// Run the independent passes (see SYNTH_PASSES). Their results are merged in
|
|
4032
|
+
// REGISTRY ORDER below regardless of execution order, and none of their edges
|
|
4033
|
+
// persist until that merge — so every pass sees the same committed
|
|
4034
|
+
// post-resolution DB state whether it runs sequentially here or on a resolver
|
|
4035
|
+
// pool worker. With a live pool (already booted on ≥150k-ref repos), passes
|
|
4036
|
+
// fan out across its read-only workers and the per-pass wall-clock comes from
|
|
4037
|
+
// the worker; a pass that fails on a worker falls back to running on the main
|
|
4038
|
+
// thread, so a worker crash isolates to a retry instead of failing synthesis.
|
|
4039
|
+
const passEdges = new Array(exports.SYNTH_PASSES.length).fill(NONE);
|
|
4040
|
+
const markPass = (label, dt) => {
|
|
4041
|
+
if (process.env.HOMEGRAPH_SYNTH_TIMINGS && (dt > 250 || process.env.HOMEGRAPH_SYNTH_TIMINGS === 'all')) {
|
|
4042
|
+
console.error(`[synth-timing] ${label}: ${dt}ms`);
|
|
4043
|
+
}
|
|
4044
|
+
passesDone++;
|
|
4045
|
+
emit(passesDone);
|
|
4046
|
+
};
|
|
4047
|
+
const runPassOnMain = async (i) => {
|
|
4048
|
+
const pass = exports.SYNTH_PASSES[i];
|
|
4049
|
+
const t0 = Date.now();
|
|
4050
|
+
passEdges[i] = await pass.run(queries, ctx, yieldToLoop, subProgress);
|
|
4051
|
+
await yieldToLoop();
|
|
4052
|
+
markPass(pass.name, Date.now() - t0);
|
|
4053
|
+
};
|
|
4054
|
+
const gatedIn = [];
|
|
4055
|
+
for (let i = 0; i < exports.SYNTH_PASSES.length; i++) {
|
|
4056
|
+
if (exports.SYNTH_PASSES[i].gate(has))
|
|
4057
|
+
gatedIn.push(i);
|
|
4058
|
+
else
|
|
4059
|
+
markPass(exports.SYNTH_PASSES[i].name, 0);
|
|
4060
|
+
}
|
|
4061
|
+
// Above this node count, a pass that OOM-killed its worker must NOT be
|
|
4062
|
+
// retried on the main thread — the retry would OOM the whole process and
|
|
4063
|
+
// take the index with it (the #1212 failure class). Below it, a worker
|
|
4064
|
+
// failure is more likely a transient crash than a memory ceiling, and the
|
|
4065
|
+
// main-thread retry keeps coverage. Skipping loses only that pass's
|
|
4066
|
+
// synthesized edges; the index still completes.
|
|
4067
|
+
const MAIN_RETRY_MAX_NODES = 1_500_000;
|
|
4068
|
+
const graphNodes = queries.getNodeAndEdgeCount().nodes;
|
|
4069
|
+
if (pool && gatedIn.length > 1) {
|
|
4070
|
+
await Promise.all(gatedIn.map(async (i) => {
|
|
4071
|
+
const pass = exports.SYNTH_PASSES[i];
|
|
4072
|
+
try {
|
|
4073
|
+
const out = await pool.runSynthPass(pass.name);
|
|
4074
|
+
passEdges[i] = out.edges;
|
|
4075
|
+
markPass(pass.name, out.ms);
|
|
4076
|
+
}
|
|
4077
|
+
catch (err) {
|
|
4078
|
+
if (graphNodes > MAIN_RETRY_MAX_NODES) {
|
|
4079
|
+
// Worker died at a scale where the main-thread retry is a process
|
|
4080
|
+
// OOM risk: skip the pass, keep the index alive, and say so.
|
|
4081
|
+
console.error(`[synthesis] pass '${pass.name}' failed on a worker at ${graphNodes} nodes — skipped (edges from this pass are absent): ${err instanceof Error ? err.message : String(err)}`);
|
|
4082
|
+
markPass(`${pass.name} (skipped at scale)`, 0);
|
|
4083
|
+
return;
|
|
4084
|
+
}
|
|
4085
|
+
// Worker-side failure (crash, OOM, unknown pass after a version
|
|
4086
|
+
// mismatch): retry this one pass on the main thread.
|
|
4087
|
+
await runPassOnMain(i);
|
|
4088
|
+
}
|
|
4089
|
+
}));
|
|
4090
|
+
}
|
|
4091
|
+
else {
|
|
4092
|
+
for (const i of gatedIn) {
|
|
4093
|
+
await runPassOnMain(i);
|
|
4094
|
+
}
|
|
4095
|
+
}
|
|
4005
4096
|
const merged = [];
|
|
4006
4097
|
const seen = new Set();
|
|
4007
|
-
for (const e of
|
|
4008
|
-
...fieldEdges,
|
|
4009
|
-
...closureCollEdges,
|
|
4010
|
-
...emitterEdges,
|
|
4011
|
-
...renderEdges,
|
|
4012
|
-
...jsxEdges,
|
|
4013
|
-
...vueEdges,
|
|
4014
|
-
...svelteKitEdges,
|
|
4015
|
-
...pascalEdges,
|
|
4016
|
-
...flutterEdges,
|
|
4017
|
-
...arkuiStateEdges,
|
|
4018
|
-
...arkuiEmitter,
|
|
4019
|
-
...arkuiRoutes,
|
|
4020
|
-
...cppEdges,
|
|
4021
|
-
...ifaceEdges,
|
|
4022
|
-
...kotlinExpectActual,
|
|
4023
|
-
...goGrpcEdges,
|
|
4024
|
-
...rnEventEdgesList,
|
|
4025
|
-
...fabricNativeEdges,
|
|
4026
|
-
...expoXPlatEdges,
|
|
4027
|
-
...rnXPlatEdges,
|
|
4028
|
-
...mybatisEdges,
|
|
4029
|
-
...ginEdges,
|
|
4030
|
-
...thunkEdges,
|
|
4031
|
-
...registryEdges,
|
|
4032
|
-
...rtkEdges,
|
|
4033
|
-
...piniaEdges,
|
|
4034
|
-
...vuexEdges,
|
|
4035
|
-
...celeryEdges,
|
|
4036
|
-
...springEdges,
|
|
4037
|
-
...mediatrEdges,
|
|
4038
|
-
...sidekiqEdges,
|
|
4039
|
-
...erlangBehaviourEdges,
|
|
4040
|
-
...laravelEdges,
|
|
4041
|
-
...cFnPtrEdges,
|
|
4042
|
-
...goframeEdges,
|
|
4043
|
-
...nixOptionEdges,
|
|
4044
|
-
...arktsStartupEdges,
|
|
4045
|
-
]) {
|
|
4098
|
+
for (const e of passEdges.flat()) {
|
|
4046
4099
|
const key = `${e.source}>${e.target}`;
|
|
4047
4100
|
if (seen.has(key))
|
|
4048
4101
|
continue;
|
|
@@ -4056,6 +4109,7 @@ async function synthesizeCallbackEdges(queries, ctx, onProgress) {
|
|
|
4056
4109
|
for (let i = 0; i < merged.length; i += 2000) {
|
|
4057
4110
|
queries.insertEdges(merged.slice(i, i + 2000));
|
|
4058
4111
|
await yieldToLoop();
|
|
4112
|
+
await foldIfOver();
|
|
4059
4113
|
}
|
|
4060
4114
|
__mark('insertMergedEdges');
|
|
4061
4115
|
return merged.length + goImpl.length + goMethodContains.length;
|