@spikedpunch/mast 0.1.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/LICENSE +21 -0
- package/MAST_SPEC.md +2926 -0
- package/README.md +842 -0
- package/assets/skill.md +45 -0
- package/dist/ast/extract.d.ts +65 -0
- package/dist/ast/extract.d.ts.map +1 -0
- package/dist/ast/extract.js +147 -0
- package/dist/ast/extract.js.map +1 -0
- package/dist/ast/extractor.d.ts +85 -0
- package/dist/ast/extractor.d.ts.map +1 -0
- package/dist/ast/extractor.js +2 -0
- package/dist/ast/extractor.js.map +1 -0
- package/dist/ast/extractors/markdown.d.ts +40 -0
- package/dist/ast/extractors/markdown.d.ts.map +1 -0
- package/dist/ast/extractors/markdown.js +175 -0
- package/dist/ast/extractors/markdown.js.map +1 -0
- package/dist/ast/extractors/typescript.d.ts +179 -0
- package/dist/ast/extractors/typescript.d.ts.map +1 -0
- package/dist/ast/extractors/typescript.js +1439 -0
- package/dist/ast/extractors/typescript.js.map +1 -0
- package/dist/ast/parser.d.ts +5 -0
- package/dist/ast/parser.d.ts.map +1 -0
- package/dist/ast/parser.js +21 -0
- package/dist/ast/parser.js.map +1 -0
- package/dist/ast/types.d.ts +586 -0
- package/dist/ast/types.d.ts.map +1 -0
- package/dist/ast/types.js +3 -0
- package/dist/ast/types.js.map +1 -0
- package/dist/cli/docs-cmd.d.ts +22 -0
- package/dist/cli/docs-cmd.d.ts.map +1 -0
- package/dist/cli/docs-cmd.js +100 -0
- package/dist/cli/docs-cmd.js.map +1 -0
- package/dist/cli/index-cmd.d.ts +72 -0
- package/dist/cli/index-cmd.d.ts.map +1 -0
- package/dist/cli/index-cmd.js +263 -0
- package/dist/cli/index-cmd.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +4 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +14 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +64 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/install-hooks.d.ts +3 -0
- package/dist/cli/install-hooks.d.ts.map +1 -0
- package/dist/cli/install-hooks.js +34 -0
- package/dist/cli/install-hooks.js.map +1 -0
- package/dist/cli/metrics-cmd.d.ts +3 -0
- package/dist/cli/metrics-cmd.d.ts.map +1 -0
- package/dist/cli/metrics-cmd.js +164 -0
- package/dist/cli/metrics-cmd.js.map +1 -0
- package/dist/cli/program.d.ts +14 -0
- package/dist/cli/program.d.ts.map +1 -0
- package/dist/cli/program.js +44 -0
- package/dist/cli/program.js.map +1 -0
- package/dist/cli/query.d.ts +46 -0
- package/dist/cli/query.d.ts.map +1 -0
- package/dist/cli/query.js +153 -0
- package/dist/cli/query.js.map +1 -0
- package/dist/cli/search-cmd.d.ts +33 -0
- package/dist/cli/search-cmd.d.ts.map +1 -0
- package/dist/cli/search-cmd.js +114 -0
- package/dist/cli/search-cmd.js.map +1 -0
- package/dist/cli/serve.d.ts +3 -0
- package/dist/cli/serve.d.ts.map +1 -0
- package/dist/cli/serve.js +19 -0
- package/dist/cli/serve.js.map +1 -0
- package/dist/cli/skill-install.d.ts +39 -0
- package/dist/cli/skill-install.d.ts.map +1 -0
- package/dist/cli/skill-install.js +57 -0
- package/dist/cli/skill-install.js.map +1 -0
- package/dist/cli/status.d.ts +35 -0
- package/dist/cli/status.d.ts.map +1 -0
- package/dist/cli/status.js +117 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/cli/upgrade-cmd.d.ts +48 -0
- package/dist/cli/upgrade-cmd.d.ts.map +1 -0
- package/dist/cli/upgrade-cmd.js +129 -0
- package/dist/cli/upgrade-cmd.js.map +1 -0
- package/dist/cli/version.d.ts +3 -0
- package/dist/cli/version.d.ts.map +1 -0
- package/dist/cli/version.js +19 -0
- package/dist/cli/version.js.map +1 -0
- package/dist/env.d.ts +17 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +17 -0
- package/dist/env.js.map +1 -0
- package/dist/graph/checker-resolver.d.ts +156 -0
- package/dist/graph/checker-resolver.d.ts.map +1 -0
- package/dist/graph/checker-resolver.js +458 -0
- package/dist/graph/checker-resolver.js.map +1 -0
- package/dist/graph/db.d.ts +318 -0
- package/dist/graph/db.d.ts.map +1 -0
- package/dist/graph/db.js +266 -0
- package/dist/graph/db.js.map +1 -0
- package/dist/graph/index.d.ts +4 -0
- package/dist/graph/index.d.ts.map +1 -0
- package/dist/graph/index.js +5 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph/local-type-env.d.ts +45 -0
- package/dist/graph/local-type-env.d.ts.map +1 -0
- package/dist/graph/local-type-env.js +59 -0
- package/dist/graph/local-type-env.js.map +1 -0
- package/dist/graph/path-range.d.ts +40 -0
- package/dist/graph/path-range.d.ts.map +1 -0
- package/dist/graph/path-range.js +42 -0
- package/dist/graph/path-range.js.map +1 -0
- package/dist/graph/populate.d.ts +263 -0
- package/dist/graph/populate.d.ts.map +1 -0
- package/dist/graph/populate.js +984 -0
- package/dist/graph/populate.js.map +1 -0
- package/dist/graph/queries.d.ts +114 -0
- package/dist/graph/queries.d.ts.map +1 -0
- package/dist/graph/queries.js +415 -0
- package/dist/graph/queries.js.map +1 -0
- package/dist/graph/sqliteBatch.d.ts +48 -0
- package/dist/graph/sqliteBatch.d.ts.map +1 -0
- package/dist/graph/sqliteBatch.js +93 -0
- package/dist/graph/sqliteBatch.js.map +1 -0
- package/dist/indexer/freshness.d.ts +48 -0
- package/dist/indexer/freshness.d.ts.map +1 -0
- package/dist/indexer/freshness.js +72 -0
- package/dist/indexer/freshness.js.map +1 -0
- package/dist/indexer/import-resolver.d.ts +50 -0
- package/dist/indexer/import-resolver.d.ts.map +1 -0
- package/dist/indexer/import-resolver.js +318 -0
- package/dist/indexer/import-resolver.js.map +1 -0
- package/dist/indexer/index.d.ts +249 -0
- package/dist/indexer/index.d.ts.map +1 -0
- package/dist/indexer/index.js +560 -0
- package/dist/indexer/index.js.map +1 -0
- package/dist/indexer/walker.d.ts +60 -0
- package/dist/indexer/walker.d.ts.map +1 -0
- package/dist/indexer/walker.js +128 -0
- package/dist/indexer/walker.js.map +1 -0
- package/dist/indexer/watcher.d.ts +80 -0
- package/dist/indexer/watcher.d.ts.map +1 -0
- package/dist/indexer/watcher.js +151 -0
- package/dist/indexer/watcher.js.map +1 -0
- package/dist/mcp/context.d.ts +23 -0
- package/dist/mcp/context.d.ts.map +1 -0
- package/dist/mcp/context.js +2 -0
- package/dist/mcp/context.js.map +1 -0
- package/dist/mcp/register-tools.d.ts +21 -0
- package/dist/mcp/register-tools.d.ts.map +1 -0
- package/dist/mcp/register-tools.js +42 -0
- package/dist/mcp/register-tools.js.map +1 -0
- package/dist/mcp/server.d.ts +58 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +177 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/staleness.d.ts +72 -0
- package/dist/mcp/staleness.d.ts.map +1 -0
- package/dist/mcp/staleness.js +213 -0
- package/dist/mcp/staleness.js.map +1 -0
- package/dist/mcp/startup.d.ts +40 -0
- package/dist/mcp/startup.d.ts.map +1 -0
- package/dist/mcp/startup.js +114 -0
- package/dist/mcp/startup.js.map +1 -0
- package/dist/mcp/tools/_helpers.d.ts +26 -0
- package/dist/mcp/tools/_helpers.d.ts.map +1 -0
- package/dist/mcp/tools/_helpers.js +54 -0
- package/dist/mcp/tools/_helpers.js.map +1 -0
- package/dist/mcp/tools/callers.d.ts +4 -0
- package/dist/mcp/tools/callers.d.ts.map +1 -0
- package/dist/mcp/tools/callers.js +112 -0
- package/dist/mcp/tools/callers.js.map +1 -0
- package/dist/mcp/tools/dependencies.d.ts +4 -0
- package/dist/mcp/tools/dependencies.d.ts.map +1 -0
- package/dist/mcp/tools/dependencies.js +36 -0
- package/dist/mcp/tools/dependencies.js.map +1 -0
- package/dist/mcp/tools/efficiency.d.ts +4 -0
- package/dist/mcp/tools/efficiency.d.ts.map +1 -0
- package/dist/mcp/tools/efficiency.js +39 -0
- package/dist/mcp/tools/efficiency.js.map +1 -0
- package/dist/mcp/tools/exports.d.ts +4 -0
- package/dist/mcp/tools/exports.d.ts.map +1 -0
- package/dist/mcp/tools/exports.js +56 -0
- package/dist/mcp/tools/exports.js.map +1 -0
- package/dist/mcp/tools/implementors.d.ts +4 -0
- package/dist/mcp/tools/implementors.d.ts.map +1 -0
- package/dist/mcp/tools/implementors.js +47 -0
- package/dist/mcp/tools/implementors.js.map +1 -0
- package/dist/mcp/tools/project-skeleton.d.ts +4 -0
- package/dist/mcp/tools/project-skeleton.d.ts.map +1 -0
- package/dist/mcp/tools/project-skeleton.js +61 -0
- package/dist/mcp/tools/project-skeleton.js.map +1 -0
- package/dist/mcp/tools/reindex.d.ts +14 -0
- package/dist/mcp/tools/reindex.d.ts.map +1 -0
- package/dist/mcp/tools/reindex.js +32 -0
- package/dist/mcp/tools/reindex.js.map +1 -0
- package/dist/mcp/tools/rename-impact.d.ts +4 -0
- package/dist/mcp/tools/rename-impact.d.ts.map +1 -0
- package/dist/mcp/tools/rename-impact.js +124 -0
- package/dist/mcp/tools/rename-impact.js.map +1 -0
- package/dist/mcp/tools/search.d.ts +4 -0
- package/dist/mcp/tools/search.d.ts.map +1 -0
- package/dist/mcp/tools/search.js +69 -0
- package/dist/mcp/tools/search.js.map +1 -0
- package/dist/mcp/tools/signature.d.ts +4 -0
- package/dist/mcp/tools/signature.d.ts.map +1 -0
- package/dist/mcp/tools/signature.js +127 -0
- package/dist/mcp/tools/signature.js.map +1 -0
- package/dist/mcp/tools/status.d.ts +4 -0
- package/dist/mcp/tools/status.d.ts.map +1 -0
- package/dist/mcp/tools/status.js +30 -0
- package/dist/mcp/tools/status.js.map +1 -0
- package/dist/search/declex.d.ts +109 -0
- package/dist/search/declex.d.ts.map +1 -0
- package/dist/search/declex.js +242 -0
- package/dist/search/declex.js.map +1 -0
- package/dist/search/fts.d.ts +77 -0
- package/dist/search/fts.d.ts.map +1 -0
- package/dist/search/fts.js +223 -0
- package/dist/search/fts.js.map +1 -0
- package/dist/search/fused.d.ts +110 -0
- package/dist/search/fused.d.ts.map +1 -0
- package/dist/search/fused.js +323 -0
- package/dist/search/fused.js.map +1 -0
- package/dist/search/potential-matches.d.ts +88 -0
- package/dist/search/potential-matches.d.ts.map +1 -0
- package/dist/search/potential-matches.js +83 -0
- package/dist/search/potential-matches.js.map +1 -0
- package/dist/search/scope.d.ts +66 -0
- package/dist/search/scope.d.ts.map +1 -0
- package/dist/search/scope.js +71 -0
- package/dist/search/scope.js.map +1 -0
- package/dist/store/config.d.ts +57 -0
- package/dist/store/config.d.ts.map +1 -0
- package/dist/store/config.js +208 -0
- package/dist/store/config.js.map +1 -0
- package/dist/store/lock.d.ts +101 -0
- package/dist/store/lock.d.ts.map +1 -0
- package/dist/store/lock.js +182 -0
- package/dist/store/lock.js.map +1 -0
- package/dist/store/lockMetrics.d.ts +52 -0
- package/dist/store/lockMetrics.d.ts.map +1 -0
- package/dist/store/lockMetrics.js +29 -0
- package/dist/store/lockMetrics.js.map +1 -0
- package/dist/store/sqliteChunkStore.d.ts +44 -0
- package/dist/store/sqliteChunkStore.d.ts.map +1 -0
- package/dist/store/sqliteChunkStore.js +135 -0
- package/dist/store/sqliteChunkStore.js.map +1 -0
- package/dist/telemetry/lockMetricsSummary.d.ts +42 -0
- package/dist/telemetry/lockMetricsSummary.d.ts.map +1 -0
- package/dist/telemetry/lockMetricsSummary.js +139 -0
- package/dist/telemetry/lockMetricsSummary.js.map +1 -0
- package/dist/telemetry/metrics.d.ts +140 -0
- package/dist/telemetry/metrics.d.ts.map +1 -0
- package/dist/telemetry/metrics.js +312 -0
- package/dist/telemetry/metrics.js.map +1 -0
- package/dist/telemetry/tokenizer.d.ts +125 -0
- package/dist/telemetry/tokenizer.d.ts.map +1 -0
- package/dist/telemetry/tokenizer.js +174 -0
- package/dist/telemetry/tokenizer.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import type { Db } from './db.js';
|
|
3
|
+
import type { ChunkStore } from '../store/sqliteChunkStore.js';
|
|
4
|
+
import type { ResolvedConfig } from '../store/config.js';
|
|
5
|
+
/** One tsconfig project the checker pass can build a `ts.Program` for. */
|
|
6
|
+
export interface TsProjectDescriptor {
|
|
7
|
+
/** Directory containing tsconfig.json, relative to the project root (POSIX separators). */
|
|
8
|
+
readonly configDir: string;
|
|
9
|
+
/** Absolute paths TypeScript itself resolved via this tsconfig's "include"/"files". */
|
|
10
|
+
readonly fileNames: readonly string[];
|
|
11
|
+
readonly compilerOptions: ts.CompilerOptions;
|
|
12
|
+
}
|
|
13
|
+
/** A tsconfig.json that was found but is not a standalone checkable project. */
|
|
14
|
+
export interface TsProjectSkip {
|
|
15
|
+
readonly configDir: string;
|
|
16
|
+
readonly reason: string;
|
|
17
|
+
}
|
|
18
|
+
export interface TsProjectDiscoveryResult {
|
|
19
|
+
readonly projects: readonly TsProjectDescriptor[];
|
|
20
|
+
readonly skipped: readonly TsProjectSkip[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Enumerate every tsconfig project under `projectRoot`.
|
|
24
|
+
*
|
|
25
|
+
* A tsconfig.json is a real, checkable project when `ts.parseJsonConfigFileContent`
|
|
26
|
+
* resolves at least one source file for it. A base config meant to be
|
|
27
|
+
* `extends`-ed (e.g. `tsconfig.base.json`) declares no "include"/"files" of
|
|
28
|
+
* its own and resolves zero files — skipped with reason `no_include_base_config`.
|
|
29
|
+
* A config that fails to parse is skipped with the parser's own error text.
|
|
30
|
+
* This is a generic, project-shape-agnostic rule (unlike the Stage 1.1 spike's
|
|
31
|
+
* hardcoded 25-project list for the kluster monorepo specifically) so it works
|
|
32
|
+
* for any project `mast index --checker` runs against, monorepo or single-app.
|
|
33
|
+
*/
|
|
34
|
+
export declare function discoverTsConfigProjects(projectRoot: string): TsProjectDiscoveryResult;
|
|
35
|
+
/** One call-site candidate to classify against a loaded project's program. */
|
|
36
|
+
export interface ClassifyInput {
|
|
37
|
+
/** File containing the candidate call site, relative to the project root. */
|
|
38
|
+
readonly relFilePath: string;
|
|
39
|
+
/** Bare (post-`.`) name being searched for — `ClassName.method` → `method`. */
|
|
40
|
+
readonly bareName: string;
|
|
41
|
+
/** Padded search window: the potential match's chunk start/end lines. */
|
|
42
|
+
readonly startLine: number;
|
|
43
|
+
readonly endLine: number;
|
|
44
|
+
/** The queried symbol's own declaration site, for the resolved-declaration comparison. */
|
|
45
|
+
readonly queriedFilePath: string;
|
|
46
|
+
readonly queriedLine: number;
|
|
47
|
+
}
|
|
48
|
+
export type CallSiteClassification = {
|
|
49
|
+
readonly kind: 'resolves_to_queried';
|
|
50
|
+
readonly callLine: number;
|
|
51
|
+
readonly context: string;
|
|
52
|
+
} | {
|
|
53
|
+
readonly kind: 'resolves_to_different';
|
|
54
|
+
} | {
|
|
55
|
+
readonly kind: 'non_call_site';
|
|
56
|
+
} | {
|
|
57
|
+
readonly kind: 'unresolved';
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* A loaded TypeScript project — one `ts.Program` + `ts.TypeChecker`.
|
|
61
|
+
*
|
|
62
|
+
* Callers MUST call `dispose()` before loading the next project; the checker
|
|
63
|
+
* pass holds exactly one handle at a time (see module doc — the RSS gate).
|
|
64
|
+
*/
|
|
65
|
+
export interface TsProjectHandle {
|
|
66
|
+
classify(input: ClassifyInput): CallSiteClassification;
|
|
67
|
+
/** Release the underlying program/checker. Idempotent; `classify()` after `dispose()` throws. */
|
|
68
|
+
dispose(): void;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Abstraction over "hold a TypeScript program for one project and classify
|
|
72
|
+
* call sites against it." The real implementation wraps `ts.createProgram` +
|
|
73
|
+
* `ts.TypeChecker` (the feature IS the compiler integration — a fake exists
|
|
74
|
+
* only so `runCheckerPass`'s orchestration logic, persistence, and filtering
|
|
75
|
+
* can be unit-tested without paying real compiler cost; the classification
|
|
76
|
+
* logic itself is exercised only by the real implementation, in
|
|
77
|
+
* `checker-resolver.test.ts`'s real-compiler fixtures).
|
|
78
|
+
*/
|
|
79
|
+
export interface TsProjectResolver {
|
|
80
|
+
discoverProjects(): TsProjectDiscoveryResult;
|
|
81
|
+
loadProgram(descriptor: TsProjectDescriptor): TsProjectHandle;
|
|
82
|
+
}
|
|
83
|
+
export declare class RealTsProjectResolver implements TsProjectResolver {
|
|
84
|
+
private readonly projectRoot;
|
|
85
|
+
constructor(projectRoot: string);
|
|
86
|
+
discoverProjects(): TsProjectDiscoveryResult;
|
|
87
|
+
loadProgram(descriptor: TsProjectDescriptor): TsProjectHandle;
|
|
88
|
+
}
|
|
89
|
+
export interface CheckerPassOptions {
|
|
90
|
+
/** DI seam for tests — defaults to `RealTsProjectResolver`. */
|
|
91
|
+
readonly resolver?: TsProjectResolver;
|
|
92
|
+
readonly onProject?: (configDir: string, index: number, total: number) => void;
|
|
93
|
+
}
|
|
94
|
+
export interface CheckerProjectTiming {
|
|
95
|
+
readonly configDir: string;
|
|
96
|
+
readonly fileCount: number;
|
|
97
|
+
readonly candidateCount: number;
|
|
98
|
+
readonly durationMs: number;
|
|
99
|
+
}
|
|
100
|
+
export interface CheckerPassResult {
|
|
101
|
+
readonly projectsChecked: number;
|
|
102
|
+
readonly projectsSkipped: readonly TsProjectSkip[];
|
|
103
|
+
readonly symbolsChecked: number;
|
|
104
|
+
/** Potential-match candidates whose file has no owning tsconfig project — left untouched, not silently dropped. */
|
|
105
|
+
readonly potentialSitesOutsideScope: number;
|
|
106
|
+
/** Distinct NEW edge rows actually inserted — not classification attempts
|
|
107
|
+
* (duplicates and already-heuristic-verified pairs collapse via the
|
|
108
|
+
* (from_id, to_id, edge_type) PK, so a rerun reports 0). */
|
|
109
|
+
readonly edgesUpgraded: number;
|
|
110
|
+
readonly classifiedDifferentDeclaration: number;
|
|
111
|
+
readonly classifiedNonCallSite: number;
|
|
112
|
+
readonly unresolved: number;
|
|
113
|
+
readonly perProjectTiming: readonly CheckerProjectTiming[];
|
|
114
|
+
/**
|
|
115
|
+
* Self-sampled peak RSS across the whole pass (`process.memoryUsage().rss`,
|
|
116
|
+
* polled every 250ms). This is an approximation, not the Stage 1.1 spike's
|
|
117
|
+
* external `ps`-on-a-child-process measurement — production runs in-process
|
|
118
|
+
* (the same one-shot-process reasoning `index-cmd.ts` uses throughout),
|
|
119
|
+
* and an in-process sampler can miss a spike inside a long synchronous
|
|
120
|
+
* stretch that never yields the event loop. Reported honestly as an
|
|
121
|
+
* approximation, not hidden.
|
|
122
|
+
*/
|
|
123
|
+
readonly peakRssBytes: number;
|
|
124
|
+
readonly durationMs: number;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Run the checker pass over every tsconfig project in `config.resolved_project_root`.
|
|
128
|
+
*
|
|
129
|
+
* Two phases per project, kept strictly separate so the DB write lock is held
|
|
130
|
+
* in short batches (§7.6) rather than across the compiler-heavy classify loop:
|
|
131
|
+
* 1. Classify every candidate for the project against its `ts.Program` (no lock).
|
|
132
|
+
* 2. Flush the resulting edge/verdict writes under `structure.lock` (short batch).
|
|
133
|
+
*/
|
|
134
|
+
/** One `files` row's identity and freshness stamp, keyed by path. */
|
|
135
|
+
export interface FileMeta {
|
|
136
|
+
readonly id: number;
|
|
137
|
+
readonly mtime: number;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Look up `files` rows for `paths` in one pass, batched under SQLite's bound
|
|
141
|
+
* parameter ceiling.
|
|
142
|
+
*
|
|
143
|
+
* Extracted from the checker pass so the batching is testable without standing
|
|
144
|
+
* up a TypeScript program: the path list is every distinct candidate file in
|
|
145
|
+
* one tsconfig project, accumulated across every symbol the pass examines, so
|
|
146
|
+
* nothing in its construction bounds it below SQLite's bound-parameter ceiling
|
|
147
|
+
* (`SQLITE_MAX_VARIABLES`, `./sqliteBatch.ts`). A single `IN` list past that
|
|
148
|
+
* ceiling throws `too many SQL variables` and fails
|
|
149
|
+
* the whole project's checker pass.
|
|
150
|
+
*
|
|
151
|
+
* Paths with no row are simply absent from the returned map — the caller
|
|
152
|
+
* already treats that as "file row vanished mid-run" and skips the candidate.
|
|
153
|
+
*/
|
|
154
|
+
export declare function loadFileMetaByPath(db: Db, paths: readonly string[]): Promise<Map<string, FileMeta>>;
|
|
155
|
+
export declare function runCheckerPass(db: Db, chunkStore: Pick<ChunkStore, 'getAllChunks'>, config: ResolvedConfig, options?: CheckerPassOptions): Promise<CheckerPassResult>;
|
|
156
|
+
//# sourceMappingURL=checker-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checker-resolver.d.ts","sourceRoot":"","sources":["../../src/graph/checker-resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
import { resolve, sep, dirname } from 'node:path';
|
|
2
|
+
import ts from 'typescript';
|
|
3
|
+
import fg from 'fast-glob';
|
|
4
|
+
import { withLock } from '../store/lock.js';
|
|
5
|
+
import { queryVerifiedCallers, querySymbolByName } from './queries.js';
|
|
6
|
+
import { collectPotentialMatchCandidates } from '../search/potential-matches.js';
|
|
7
|
+
import { chunkValuesForSqlite } from './sqliteBatch.js';
|
|
8
|
+
/**
|
|
9
|
+
* tsconfig.json locations that are structurally never real, standalone
|
|
10
|
+
* projects — excluded before even attempting to parse them so a large
|
|
11
|
+
* `node_modules` tree costs nothing.
|
|
12
|
+
*/
|
|
13
|
+
const DISCOVERY_IGNORE = ['**/node_modules/**', '**/dist/**', '**/.build/**', '**/coverage/**'];
|
|
14
|
+
// Arrow-wrapped (not `ts.sys.fileExists` directly) so each call stays bound to
|
|
15
|
+
// `ts.sys` — @typescript-eslint/unbound-method flags a bare method reference
|
|
16
|
+
// as an unintentional-`this`-scoping risk.
|
|
17
|
+
const PARSE_CONFIG_HOST = {
|
|
18
|
+
fileExists: (path) => ts.sys.fileExists(path),
|
|
19
|
+
readFile: (path) => ts.sys.readFile(path),
|
|
20
|
+
readDirectory: (path, extensions, exclude, include, depth) => ts.sys.readDirectory(path, extensions, exclude, include, depth),
|
|
21
|
+
useCaseSensitiveFileNames: true,
|
|
22
|
+
};
|
|
23
|
+
/** Bound wrapper for `ts.sys.readFile`, passed where a bare function reference is needed. */
|
|
24
|
+
function readFile(path) {
|
|
25
|
+
return ts.sys.readFile(path);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Convert an absolute path to a POSIX-separated path relative to `root`.
|
|
29
|
+
* Returns `.` when `absPath` IS `root` (the fold-app-scale shape: a single
|
|
30
|
+
* package's own directory as project_root, tsconfig.json living directly in
|
|
31
|
+
* it — found running the real pass against align-kimik27-02/packages/core,
|
|
32
|
+
* IMPLEMENTATION_PLAN_VEXP.md Stage 1.2 addendum. Without this case the
|
|
33
|
+
* prefix-strip below never matches — `root` has no trailing slash to align
|
|
34
|
+
* against — and `configDir` came back as the full absolute path instead).
|
|
35
|
+
*/
|
|
36
|
+
function relPath(absPath, root) {
|
|
37
|
+
const norm = absPath.split(sep).join('/');
|
|
38
|
+
const rootNorm = root.split(sep).join('/').replace(/\/$/, '');
|
|
39
|
+
if (norm === rootNorm)
|
|
40
|
+
return '.';
|
|
41
|
+
const withSlash = rootNorm + '/';
|
|
42
|
+
return norm.startsWith(withSlash) ? norm.slice(withSlash.length) : norm;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Enumerate every tsconfig project under `projectRoot`.
|
|
46
|
+
*
|
|
47
|
+
* A tsconfig.json is a real, checkable project when `ts.parseJsonConfigFileContent`
|
|
48
|
+
* resolves at least one source file for it. A base config meant to be
|
|
49
|
+
* `extends`-ed (e.g. `tsconfig.base.json`) declares no "include"/"files" of
|
|
50
|
+
* its own and resolves zero files — skipped with reason `no_include_base_config`.
|
|
51
|
+
* A config that fails to parse is skipped with the parser's own error text.
|
|
52
|
+
* This is a generic, project-shape-agnostic rule (unlike the Stage 1.1 spike's
|
|
53
|
+
* hardcoded 25-project list for the kluster monorepo specifically) so it works
|
|
54
|
+
* for any project `mast index --checker` runs against, monorepo or single-app.
|
|
55
|
+
*/
|
|
56
|
+
export function discoverTsConfigProjects(projectRoot) {
|
|
57
|
+
const configPaths = fg
|
|
58
|
+
.sync('**/tsconfig.json', {
|
|
59
|
+
cwd: projectRoot,
|
|
60
|
+
ignore: DISCOVERY_IGNORE,
|
|
61
|
+
absolute: true,
|
|
62
|
+
onlyFiles: true,
|
|
63
|
+
followSymbolicLinks: false,
|
|
64
|
+
})
|
|
65
|
+
.sort();
|
|
66
|
+
const projects = [];
|
|
67
|
+
const skipped = [];
|
|
68
|
+
for (const configPath of configPaths) {
|
|
69
|
+
const configDir = relPath(dirname(configPath), projectRoot);
|
|
70
|
+
const configFile = ts.readConfigFile(configPath, readFile);
|
|
71
|
+
if (configFile.error !== undefined) {
|
|
72
|
+
skipped.push({
|
|
73
|
+
configDir,
|
|
74
|
+
reason: `tsconfig_parse_error: ${ts.flattenDiagnosticMessageText(configFile.error.messageText, '\n')}`,
|
|
75
|
+
});
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const parsed = ts.parseJsonConfigFileContent(configFile.config, PARSE_CONFIG_HOST, dirname(configPath));
|
|
79
|
+
if (parsed.fileNames.length === 0) {
|
|
80
|
+
skipped.push({ configDir, reason: 'no_include_base_config' });
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
projects.push({ configDir, fileNames: parsed.fileNames, compilerOptions: parsed.options });
|
|
84
|
+
}
|
|
85
|
+
return { projects, skipped };
|
|
86
|
+
}
|
|
87
|
+
/** Chunk `content` extends `context_lines` (default 3, MAST_SPEC §6.1) beyond
|
|
88
|
+
* strict AST boundaries — padding the identifier search window past that
|
|
89
|
+
* default with margin catches a call site sitting just outside
|
|
90
|
+
* [start_line, end_line] (Stage 1.1 spike finding: 10/50 samples
|
|
91
|
+
* false-classified as non-call-site before this pad was added). */
|
|
92
|
+
const CONTEXT_PAD = 5;
|
|
93
|
+
/** Bounded hop count for `ts.Symbol.getAliasedSymbol` chains. MANDATORY per
|
|
94
|
+
* the Stage 1.1 spike: without alias-following, `getSymbolAtLocation` on an
|
|
95
|
+
* imported identifier returns the local import binding (not its real
|
|
96
|
+
* target), and the definite-edge resolution rate collapses 38% -> 2%. */
|
|
97
|
+
const ALIAS_HOP_LIMIT = 8;
|
|
98
|
+
/** True when `node` is the callee of a CallExpression/NewExpression, direct or via `.property(...)`. */
|
|
99
|
+
function isCallShaped(node) {
|
|
100
|
+
const parent = node.parent;
|
|
101
|
+
if (parent === undefined)
|
|
102
|
+
return false;
|
|
103
|
+
if (ts.isCallExpression(parent) && parent.expression === node)
|
|
104
|
+
return true;
|
|
105
|
+
if (ts.isNewExpression(parent) && parent.expression === node)
|
|
106
|
+
return true;
|
|
107
|
+
if (ts.isPropertyAccessExpression(parent) && parent.name === node) {
|
|
108
|
+
const grandparent = parent.parent;
|
|
109
|
+
if (grandparent !== undefined && ts.isCallExpression(grandparent) && grandparent.expression === parent)
|
|
110
|
+
return true;
|
|
111
|
+
if (grandparent !== undefined && ts.isNewExpression(grandparent) && grandparent.expression === parent)
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* All `Identifier` nodes named `name` whose 1-indexed line falls in the
|
|
118
|
+
* padded `[startLine - pad, endLine + pad]` window, nearest-to-the-original-
|
|
119
|
+
* range first (ties broken by line, then source position — deterministic).
|
|
120
|
+
*/
|
|
121
|
+
function findIdentifierOccurrences(sourceFile, name, startLine, endLine, pad) {
|
|
122
|
+
const occurrences = [];
|
|
123
|
+
const visit = (node) => {
|
|
124
|
+
if (ts.isIdentifier(node) && node.text === name) {
|
|
125
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
126
|
+
const line1 = line + 1;
|
|
127
|
+
if (line1 >= startLine - pad && line1 <= endLine + pad) {
|
|
128
|
+
const distance = line1 < startLine ? startLine - line1 : line1 > endLine ? line1 - endLine : 0;
|
|
129
|
+
occurrences.push({ node, line: line1, distance, callShaped: isCallShaped(node) });
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
ts.forEachChild(node, visit);
|
|
133
|
+
};
|
|
134
|
+
visit(sourceFile);
|
|
135
|
+
occurrences.sort((a, b) => a.distance - b.distance || a.line - b.line || a.node.getStart(sourceFile) - b.node.getStart(sourceFile));
|
|
136
|
+
return occurrences;
|
|
137
|
+
}
|
|
138
|
+
class RealTsProjectHandle {
|
|
139
|
+
projectRoot;
|
|
140
|
+
program;
|
|
141
|
+
checker;
|
|
142
|
+
constructor(descriptor, projectRoot) {
|
|
143
|
+
this.projectRoot = projectRoot;
|
|
144
|
+
this.program = ts.createProgram({ rootNames: descriptor.fileNames, options: descriptor.compilerOptions });
|
|
145
|
+
this.checker = this.program.getTypeChecker();
|
|
146
|
+
}
|
|
147
|
+
classify(input) {
|
|
148
|
+
if (this.program === null || this.checker === null) {
|
|
149
|
+
throw new Error('RealTsProjectHandle.classify() called after dispose()');
|
|
150
|
+
}
|
|
151
|
+
const absPath = resolve(this.projectRoot, input.relFilePath).split(sep).join('/');
|
|
152
|
+
const sourceFile = this.program.getSourceFile(absPath);
|
|
153
|
+
// Defensive only: the orchestrator only routes candidates whose file was
|
|
154
|
+
// discovered as a member of THIS project's fileNames.
|
|
155
|
+
if (sourceFile === undefined)
|
|
156
|
+
return { kind: 'unresolved' };
|
|
157
|
+
const occurrences = findIdentifierOccurrences(sourceFile, input.bareName, input.startLine, input.endLine, CONTEXT_PAD);
|
|
158
|
+
const callSite = occurrences.find((o) => o.callShaped);
|
|
159
|
+
if (callSite === undefined)
|
|
160
|
+
return { kind: 'non_call_site' };
|
|
161
|
+
let symbol = this.checker.getSymbolAtLocation(callSite.node);
|
|
162
|
+
for (let hops = 0; symbol !== undefined && (symbol.flags & ts.SymbolFlags.Alias) !== 0 && hops < ALIAS_HOP_LIMIT; hops++) {
|
|
163
|
+
let aliased;
|
|
164
|
+
try {
|
|
165
|
+
aliased = this.checker.getAliasedSymbol(symbol);
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
if (aliased === symbol)
|
|
171
|
+
break;
|
|
172
|
+
symbol = aliased;
|
|
173
|
+
}
|
|
174
|
+
const declarations = symbol?.getDeclarations() ?? [];
|
|
175
|
+
const firstDecl = declarations[0];
|
|
176
|
+
if (symbol === undefined || firstDecl === undefined)
|
|
177
|
+
return { kind: 'unresolved' };
|
|
178
|
+
const declSourceFile = firstDecl.getSourceFile();
|
|
179
|
+
const declLine = declSourceFile.getLineAndCharacterOfPosition(firstDecl.getStart(declSourceFile)).line + 1;
|
|
180
|
+
const declFilePath = relPath(resolve(declSourceFile.fileName), this.projectRoot);
|
|
181
|
+
const sameFile = declFilePath === input.queriedFilePath;
|
|
182
|
+
const lineClose = Math.abs(declLine - input.queriedLine) <= 3;
|
|
183
|
+
if (!(sameFile && lineClose))
|
|
184
|
+
return { kind: 'resolves_to_different' };
|
|
185
|
+
const lineText = sourceFile.getFullText().split('\n')[callSite.line - 1] ?? '';
|
|
186
|
+
return { kind: 'resolves_to_queried', callLine: callSite.line, context: lineText.trim() };
|
|
187
|
+
}
|
|
188
|
+
dispose() {
|
|
189
|
+
// Drop references so nothing keeps this project's Program (and the
|
|
190
|
+
// source ASTs/type graph it retains) alive once the orchestrator moves to
|
|
191
|
+
// the next project — the Stage 1.1 Q2 anomaly (hold-all-programs made
|
|
192
|
+
// "warm" 2x slower than cold via GC pressure) is what this guards against.
|
|
193
|
+
this.program = null;
|
|
194
|
+
this.checker = null;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
export class RealTsProjectResolver {
|
|
198
|
+
projectRoot;
|
|
199
|
+
constructor(projectRoot) {
|
|
200
|
+
this.projectRoot = projectRoot;
|
|
201
|
+
}
|
|
202
|
+
discoverProjects() {
|
|
203
|
+
return discoverTsConfigProjects(this.projectRoot);
|
|
204
|
+
}
|
|
205
|
+
loadProgram(descriptor) {
|
|
206
|
+
return new RealTsProjectHandle(descriptor, this.projectRoot);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/** `queried.name` may be qualified (`ClassName.methodName`, §9 mast_signature convention) — only the bare name is a real identifier token. */
|
|
210
|
+
function bareName(name) {
|
|
211
|
+
const parts = name.split('.');
|
|
212
|
+
return parts[parts.length - 1] ?? name;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Look up `files` rows for `paths` in one pass, batched under SQLite's bound
|
|
216
|
+
* parameter ceiling.
|
|
217
|
+
*
|
|
218
|
+
* Extracted from the checker pass so the batching is testable without standing
|
|
219
|
+
* up a TypeScript program: the path list is every distinct candidate file in
|
|
220
|
+
* one tsconfig project, accumulated across every symbol the pass examines, so
|
|
221
|
+
* nothing in its construction bounds it below SQLite's bound-parameter ceiling
|
|
222
|
+
* (`SQLITE_MAX_VARIABLES`, `./sqliteBatch.ts`). A single `IN` list past that
|
|
223
|
+
* ceiling throws `too many SQL variables` and fails
|
|
224
|
+
* the whole project's checker pass.
|
|
225
|
+
*
|
|
226
|
+
* Paths with no row are simply absent from the returned map — the caller
|
|
227
|
+
* already treats that as "file row vanished mid-run" and skips the candidate.
|
|
228
|
+
*/
|
|
229
|
+
export async function loadFileMetaByPath(db, paths) {
|
|
230
|
+
const meta = new Map();
|
|
231
|
+
for (const batch of chunkValuesForSqlite(paths)) {
|
|
232
|
+
const rows = await db
|
|
233
|
+
.selectFrom('files')
|
|
234
|
+
.select(['id', 'path', 'mtime'])
|
|
235
|
+
.where('path', 'in', [...batch])
|
|
236
|
+
.execute();
|
|
237
|
+
for (const r of rows)
|
|
238
|
+
meta.set(r.path, { id: r.id, mtime: r.mtime });
|
|
239
|
+
}
|
|
240
|
+
return meta;
|
|
241
|
+
}
|
|
242
|
+
export async function runCheckerPass(db, chunkStore, config, options = {}) {
|
|
243
|
+
const startMs = Date.now();
|
|
244
|
+
const resolver = options.resolver ?? new RealTsProjectResolver(config.resolved_project_root);
|
|
245
|
+
let peakRssBytes = process.memoryUsage().rss;
|
|
246
|
+
const rssTimer = setInterval(() => {
|
|
247
|
+
const rss = process.memoryUsage().rss;
|
|
248
|
+
if (rss > peakRssBytes)
|
|
249
|
+
peakRssBytes = rss;
|
|
250
|
+
}, 250);
|
|
251
|
+
try {
|
|
252
|
+
const { projects, skipped } = resolver.discoverProjects();
|
|
253
|
+
// --- Phase A: gather candidates (pure DB/FTS reads, no compiler) ---
|
|
254
|
+
const allSymbols = await db
|
|
255
|
+
.selectFrom('symbols as s')
|
|
256
|
+
.innerJoin('files as f', 'f.id', 's.file_id')
|
|
257
|
+
.select(['s.id', 's.name', 'f.path as file_path', 's.line'])
|
|
258
|
+
.where('s.kind', '!=', 'export')
|
|
259
|
+
.execute();
|
|
260
|
+
const fileToProject = new Map();
|
|
261
|
+
for (const project of projects) {
|
|
262
|
+
for (const absFile of project.fileNames) {
|
|
263
|
+
const rel = relPath(absFile, config.resolved_project_root);
|
|
264
|
+
if (!fileToProject.has(rel))
|
|
265
|
+
fileToProject.set(rel, project);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
const byProject = new Map();
|
|
269
|
+
let potentialSitesOutsideScope = 0;
|
|
270
|
+
// One full chunk scan up front, then Map lookups. Candidate collection
|
|
271
|
+
// runs once per indexed symbol below; fetching chunks one-by-one instead
|
|
272
|
+
// was measured at 50+ CPU-minutes on this monorepo (10,733 symbols)
|
|
273
|
+
// without completing Phase A. Semantics are identical —
|
|
274
|
+
// `collectPotentialMatchCandidates` only needs "chunks by id".
|
|
275
|
+
const allChunks = await chunkStore.getAllChunks();
|
|
276
|
+
const chunkById = new Map(allChunks.map((c) => [c.chunk_id, c]));
|
|
277
|
+
const chunkSource = {
|
|
278
|
+
getChunksByIds: (ids) => Promise.resolve(ids.flatMap((id) => {
|
|
279
|
+
const chunk = chunkById.get(id);
|
|
280
|
+
return chunk === undefined ? [] : [chunk];
|
|
281
|
+
})),
|
|
282
|
+
};
|
|
283
|
+
for (const sym of allSymbols) {
|
|
284
|
+
const verifiedRows = await queryVerifiedCallers(db, sym.id, false);
|
|
285
|
+
const verified = verifiedRows.map((r) => ({
|
|
286
|
+
file_path: r.file_path,
|
|
287
|
+
line: r.line,
|
|
288
|
+
caller_symbol: r.caller_symbol,
|
|
289
|
+
context: r.context,
|
|
290
|
+
resolution: r.resolution,
|
|
291
|
+
}));
|
|
292
|
+
// F10 (Stage 3): collectPotentialMatchCandidates now also returns an
|
|
293
|
+
// optional truncatedMatchCount — Phase A has no use for it (it isn't a
|
|
294
|
+
// tool-response summary), so it's destructured away and ignored here.
|
|
295
|
+
const { candidates } = await collectPotentialMatchCandidates(db, chunkSource, sym.name, verified);
|
|
296
|
+
for (const c of candidates) {
|
|
297
|
+
const project = fileToProject.get(c.file_path);
|
|
298
|
+
if (project === undefined) {
|
|
299
|
+
potentialSitesOutsideScope++;
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
const bucket = byProject.get(project.configDir) ?? [];
|
|
303
|
+
bucket.push({
|
|
304
|
+
symbolId: sym.id,
|
|
305
|
+
symbolName: sym.name,
|
|
306
|
+
queriedFilePath: sym.file_path,
|
|
307
|
+
queriedLine: sym.line,
|
|
308
|
+
candidateFilePath: c.file_path,
|
|
309
|
+
startLine: c.start_line,
|
|
310
|
+
endLine: c.end_line,
|
|
311
|
+
chunkSymbolName: c.chunk_symbol_name,
|
|
312
|
+
});
|
|
313
|
+
byProject.set(project.configDir, bucket);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
// --- Phase B: classify project by project, ONE ts.Program at a time ---
|
|
317
|
+
let edgesUpgraded = 0;
|
|
318
|
+
let classifiedDifferentDeclaration = 0;
|
|
319
|
+
let classifiedNonCallSite = 0;
|
|
320
|
+
let unresolved = 0;
|
|
321
|
+
const perProjectTiming = [];
|
|
322
|
+
for (let i = 0; i < projects.length; i++) {
|
|
323
|
+
const project = projects[i];
|
|
324
|
+
options.onProject?.(project.configDir, i + 1, projects.length);
|
|
325
|
+
const bucket = byProject.get(project.configDir);
|
|
326
|
+
if (bucket === undefined || bucket.length === 0)
|
|
327
|
+
continue; // nothing to check — don't pay program cost
|
|
328
|
+
const t0 = Date.now();
|
|
329
|
+
const handle = resolver.loadProgram(project);
|
|
330
|
+
const pending = [];
|
|
331
|
+
try {
|
|
332
|
+
// File id/mtime cache — one query for the whole project's bucket
|
|
333
|
+
// instead of one per candidate.
|
|
334
|
+
const filePaths = [...new Set(bucket.map((c) => c.candidateFilePath))];
|
|
335
|
+
const fileMeta = await loadFileMetaByPath(db, filePaths);
|
|
336
|
+
for (const c of bucket) {
|
|
337
|
+
const meta = fileMeta.get(c.candidateFilePath);
|
|
338
|
+
if (meta === undefined)
|
|
339
|
+
continue; // file row vanished mid-run — defensive
|
|
340
|
+
const result = handle.classify({
|
|
341
|
+
relFilePath: c.candidateFilePath,
|
|
342
|
+
bareName: bareName(c.symbolName),
|
|
343
|
+
startLine: c.startLine,
|
|
344
|
+
endLine: c.endLine,
|
|
345
|
+
queriedFilePath: c.queriedFilePath,
|
|
346
|
+
queriedLine: c.queriedLine,
|
|
347
|
+
});
|
|
348
|
+
if (result.kind === 'unresolved') {
|
|
349
|
+
unresolved++;
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
// Every non-'unresolved' outcome gets a verdict row keyed by the
|
|
353
|
+
// candidate's OWN chunk identity (not the checker's more-precise
|
|
354
|
+
// call line) — this must match collectPotentialMatchCandidates'
|
|
355
|
+
// dedup key exactly, see _helpers.ts.
|
|
356
|
+
pending.push({
|
|
357
|
+
kind: 'verdict',
|
|
358
|
+
queriedSymbolId: c.symbolId,
|
|
359
|
+
fileId: meta.id,
|
|
360
|
+
line: c.startLine,
|
|
361
|
+
verdict: result.kind,
|
|
362
|
+
mtime: meta.mtime,
|
|
363
|
+
});
|
|
364
|
+
if (result.kind === 'non_call_site') {
|
|
365
|
+
classifiedNonCallSite++;
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
if (result.kind === 'resolves_to_different') {
|
|
369
|
+
classifiedDifferentDeclaration++;
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
// result.kind === 'resolves_to_queried' — write the caller edge too,
|
|
373
|
+
// but only when the call site sits inside a chunk with a real
|
|
374
|
+
// enclosing symbol. Top-level block code has none (chunk_symbol_name
|
|
375
|
+
// is null) — a narrow, documented gap: still classified (so it never
|
|
376
|
+
// re-surfaces as a review site), just not upgraded to a graph edge,
|
|
377
|
+
// because there is no valid `from_id` to write one against.
|
|
378
|
+
if (c.chunkSymbolName === null)
|
|
379
|
+
continue;
|
|
380
|
+
const [fromSymbol] = await querySymbolByName(db, c.chunkSymbolName, c.candidateFilePath);
|
|
381
|
+
if (fromSymbol === undefined)
|
|
382
|
+
continue;
|
|
383
|
+
pending.push({ kind: 'edge', fromId: fromSymbol.id, toId: c.symbolId, callLine: result.callLine, context: result.context });
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
finally {
|
|
387
|
+
handle.dispose();
|
|
388
|
+
}
|
|
389
|
+
// --- Flush this project's writes in one short lock-held batch (§7.6) ---
|
|
390
|
+
if (pending.length > 0) {
|
|
391
|
+
await withLock(config.resolved_state_dir, 'structure', { maxRetries: 5, retryIntervalMs: 1_000, caller: 'checker-resolver' }, async () => {
|
|
392
|
+
for (const w of pending) {
|
|
393
|
+
if (w.kind === 'verdict') {
|
|
394
|
+
await db
|
|
395
|
+
.insertInto('checker_verdicts')
|
|
396
|
+
.values({
|
|
397
|
+
queried_symbol_id: w.queriedSymbolId,
|
|
398
|
+
call_site_file_id: w.fileId,
|
|
399
|
+
call_site_line: w.line,
|
|
400
|
+
verdict: w.verdict,
|
|
401
|
+
call_site_mtime: w.mtime,
|
|
402
|
+
})
|
|
403
|
+
.onConflict((oc) => oc.columns(['queried_symbol_id', 'call_site_file_id', 'call_site_line']).doUpdateSet((eb) => ({
|
|
404
|
+
verdict: eb.ref('excluded.verdict'),
|
|
405
|
+
call_site_mtime: eb.ref('excluded.call_site_mtime'),
|
|
406
|
+
})))
|
|
407
|
+
.execute();
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
const [insert] = await db
|
|
411
|
+
.insertInto('edges')
|
|
412
|
+
.values({
|
|
413
|
+
from_id: w.fromId,
|
|
414
|
+
to_id: w.toId,
|
|
415
|
+
edge_type: 'POTENTIAL_CALL',
|
|
416
|
+
resolution: 'checker',
|
|
417
|
+
call_line: w.callLine,
|
|
418
|
+
context: w.context,
|
|
419
|
+
})
|
|
420
|
+
.onConflict((oc) => oc.doNothing())
|
|
421
|
+
.execute();
|
|
422
|
+
// `edgesUpgraded` reports rows that actually landed, not
|
|
423
|
+
// classification attempts: ON CONFLICT collapses duplicate
|
|
424
|
+
// (from,to) pairs (several call sites in one caller) and edges a
|
|
425
|
+
// heuristic rule already verified — on the monorepo validation
|
|
426
|
+
// run, 3,935 attempts collapsed to 1,885 distinct rows. A rerun
|
|
427
|
+
// therefore honestly reports 0.
|
|
428
|
+
edgesUpgraded += Number(insert?.numInsertedOrUpdatedRows ?? 0n);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
perProjectTiming.push({
|
|
434
|
+
configDir: project.configDir,
|
|
435
|
+
fileCount: project.fileNames.length,
|
|
436
|
+
candidateCount: bucket.length,
|
|
437
|
+
durationMs: Date.now() - t0,
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
return {
|
|
441
|
+
projectsChecked: perProjectTiming.length,
|
|
442
|
+
projectsSkipped: skipped,
|
|
443
|
+
symbolsChecked: allSymbols.length,
|
|
444
|
+
potentialSitesOutsideScope,
|
|
445
|
+
edgesUpgraded,
|
|
446
|
+
classifiedDifferentDeclaration,
|
|
447
|
+
classifiedNonCallSite,
|
|
448
|
+
unresolved,
|
|
449
|
+
perProjectTiming,
|
|
450
|
+
peakRssBytes,
|
|
451
|
+
durationMs: Date.now() - startMs,
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
finally {
|
|
455
|
+
clearInterval(rssTimer);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
//# sourceMappingURL=checker-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checker-resolver.js","sourceRoot":"","sources":["../../src/graph/checker-resolver.ts"],"names":[],"mappings":"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"}
|