gitnexus 1.6.3-rc.2 → 1.6.3-rc.21
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/dist/_shared/graph/types.d.ts +16 -0
- package/dist/_shared/graph/types.d.ts.map +1 -1
- package/dist/_shared/index.d.ts +41 -1
- package/dist/_shared/index.d.ts.map +1 -1
- package/dist/_shared/index.js +28 -0
- package/dist/_shared/index.js.map +1 -1
- package/dist/_shared/scope-resolution/def-index.d.ts +36 -0
- package/dist/_shared/scope-resolution/def-index.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/def-index.js +51 -0
- package/dist/_shared/scope-resolution/def-index.js.map +1 -0
- package/dist/_shared/scope-resolution/finalize-algorithm.d.ts +139 -0
- package/dist/_shared/scope-resolution/finalize-algorithm.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/finalize-algorithm.js +479 -0
- package/dist/_shared/scope-resolution/finalize-algorithm.js.map +1 -0
- package/dist/_shared/scope-resolution/method-dispatch-index.d.ts +80 -0
- package/dist/_shared/scope-resolution/method-dispatch-index.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/method-dispatch-index.js +79 -0
- package/dist/_shared/scope-resolution/method-dispatch-index.js.map +1 -0
- package/dist/_shared/scope-resolution/module-scope-index.d.ts +46 -0
- package/dist/_shared/scope-resolution/module-scope-index.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/module-scope-index.js +58 -0
- package/dist/_shared/scope-resolution/module-scope-index.js.map +1 -0
- package/dist/_shared/scope-resolution/parsed-file.d.ts +64 -0
- package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/parsed-file.js +42 -0
- package/dist/_shared/scope-resolution/parsed-file.js.map +1 -0
- package/dist/_shared/scope-resolution/position-index.d.ts +62 -0
- package/dist/_shared/scope-resolution/position-index.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/position-index.js +134 -0
- package/dist/_shared/scope-resolution/position-index.js.map +1 -0
- package/dist/_shared/scope-resolution/qualified-name-index.d.ts +44 -0
- package/dist/_shared/scope-resolution/qualified-name-index.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/qualified-name-index.js +75 -0
- package/dist/_shared/scope-resolution/qualified-name-index.js.map +1 -0
- package/dist/_shared/scope-resolution/reference-site.d.ts +67 -0
- package/dist/_shared/scope-resolution/reference-site.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/reference-site.js +24 -0
- package/dist/_shared/scope-resolution/reference-site.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/class-registry.d.ts +27 -0
- package/dist/_shared/scope-resolution/registries/class-registry.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/class-registry.js +30 -0
- package/dist/_shared/scope-resolution/registries/class-registry.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/context.d.ts +69 -0
- package/dist/_shared/scope-resolution/registries/context.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/context.js +44 -0
- package/dist/_shared/scope-resolution/registries/context.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/evidence.d.ts +56 -0
- package/dist/_shared/scope-resolution/registries/evidence.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/evidence.js +150 -0
- package/dist/_shared/scope-resolution/registries/evidence.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/field-registry.d.ts +26 -0
- package/dist/_shared/scope-resolution/registries/field-registry.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/field-registry.js +31 -0
- package/dist/_shared/scope-resolution/registries/field-registry.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/lookup-core.d.ts +81 -0
- package/dist/_shared/scope-resolution/registries/lookup-core.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/lookup-core.js +332 -0
- package/dist/_shared/scope-resolution/registries/lookup-core.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/lookup-qualified.d.ts +33 -0
- package/dist/_shared/scope-resolution/registries/lookup-qualified.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/lookup-qualified.js +56 -0
- package/dist/_shared/scope-resolution/registries/lookup-qualified.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/method-registry.d.ts +36 -0
- package/dist/_shared/scope-resolution/registries/method-registry.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/method-registry.js +32 -0
- package/dist/_shared/scope-resolution/registries/method-registry.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/tie-breaks.d.ts +43 -0
- package/dist/_shared/scope-resolution/registries/tie-breaks.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/tie-breaks.js +60 -0
- package/dist/_shared/scope-resolution/registries/tie-breaks.js.map +1 -0
- package/dist/_shared/scope-resolution/resolve-type-ref.d.ts +53 -0
- package/dist/_shared/scope-resolution/resolve-type-ref.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/resolve-type-ref.js +126 -0
- package/dist/_shared/scope-resolution/resolve-type-ref.js.map +1 -0
- package/dist/_shared/scope-resolution/scope-id.d.ts +43 -0
- package/dist/_shared/scope-resolution/scope-id.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/scope-id.js +46 -0
- package/dist/_shared/scope-resolution/scope-id.js.map +1 -0
- package/dist/_shared/scope-resolution/scope-tree.d.ts +61 -0
- package/dist/_shared/scope-resolution/scope-tree.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/scope-tree.js +186 -0
- package/dist/_shared/scope-resolution/scope-tree.js.map +1 -0
- package/dist/_shared/scope-resolution/shadow/aggregate.d.ts +63 -0
- package/dist/_shared/scope-resolution/shadow/aggregate.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/shadow/aggregate.js +122 -0
- package/dist/_shared/scope-resolution/shadow/aggregate.js.map +1 -0
- package/dist/_shared/scope-resolution/shadow/diff.d.ts +59 -0
- package/dist/_shared/scope-resolution/shadow/diff.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/shadow/diff.js +79 -0
- package/dist/_shared/scope-resolution/shadow/diff.js.map +1 -0
- package/dist/_shared/scope-resolution/types.d.ts +156 -0
- package/dist/_shared/scope-resolution/types.d.ts.map +1 -1
- package/dist/cli/analyze.d.ts +15 -0
- package/dist/cli/analyze.js +22 -1
- package/dist/cli/index.js +4 -0
- package/dist/cli/list.js +11 -1
- package/dist/core/ingestion/emit-references.d.ts +88 -0
- package/dist/core/ingestion/emit-references.js +229 -0
- package/dist/core/ingestion/finalize-orchestrator.d.ts +63 -0
- package/dist/core/ingestion/finalize-orchestrator.js +139 -0
- package/dist/core/ingestion/framework-detection.js +6 -2
- package/dist/core/ingestion/import-target-adapter.d.ts +73 -0
- package/dist/core/ingestion/import-target-adapter.js +95 -0
- package/dist/core/ingestion/language-provider.d.ts +187 -1
- package/dist/core/ingestion/model/scope-resolution-indexes.d.ts +59 -0
- package/dist/core/ingestion/model/scope-resolution-indexes.js +42 -0
- package/dist/core/ingestion/model/semantic-model.d.ts +25 -0
- package/dist/core/ingestion/model/semantic-model.js +16 -0
- package/dist/core/ingestion/parsing-processor.d.ts +9 -0
- package/dist/core/ingestion/parsing-processor.js +10 -0
- package/dist/core/ingestion/registry-primary-flag.d.ts +59 -0
- package/dist/core/ingestion/registry-primary-flag.js +78 -0
- package/dist/core/ingestion/scope-extractor-bridge.d.ts +32 -0
- package/dist/core/ingestion/scope-extractor-bridge.js +44 -0
- package/dist/core/ingestion/scope-extractor.d.ts +87 -0
- package/dist/core/ingestion/scope-extractor.js +603 -0
- package/dist/core/ingestion/shadow-harness.d.ts +113 -0
- package/dist/core/ingestion/shadow-harness.js +148 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +9 -0
- package/dist/core/ingestion/workers/parse-worker.js +20 -1
- package/dist/core/run-analyze.d.ts +21 -0
- package/dist/core/run-analyze.js +15 -4
- package/dist/core/search/phase-timer.d.ts +72 -0
- package/dist/core/search/phase-timer.js +106 -0
- package/dist/mcp/local/local-backend.js +70 -8
- package/dist/storage/git.d.ts +25 -0
- package/dist/storage/git.js +52 -0
- package/dist/storage/repo-manager.d.ts +70 -1
- package/dist/storage/repo-manager.js +107 -5
- package/package.json +1 -1
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge between CLI-package per-language `ImportResolverFn`s and the
|
|
3
|
+
* shared `FinalizeHooks.resolveImportTarget` contract
|
|
4
|
+
* (RFC §5.2; Ring 2 PKG #922).
|
|
5
|
+
*
|
|
6
|
+
* The shared finalize algorithm (#915) asks one question:
|
|
7
|
+
*
|
|
8
|
+
* resolveImportTarget(targetRaw, fromFile, workspaceIndex): string | null
|
|
9
|
+
*
|
|
10
|
+
* The CLI already has 16 language-specific resolvers satisfying a
|
|
11
|
+
* richer signature:
|
|
12
|
+
*
|
|
13
|
+
* ImportResolverFn(rawImportPath, filePath, resolveCtx): ImportResult
|
|
14
|
+
*
|
|
15
|
+
* This module builds a dispatch adapter — one FinalizeHook implementation
|
|
16
|
+
* that looks up the file's language from its path and delegates to the
|
|
17
|
+
* right per-language resolver. Callers package per-language resolvers +
|
|
18
|
+
* a shared `ResolveCtx` into an opaque `ImportTargetWorkspace` and pass
|
|
19
|
+
* it as `workspaceIndex` to `finalizeScopeModel`.
|
|
20
|
+
*
|
|
21
|
+
* ## What's deliberately NOT here
|
|
22
|
+
*
|
|
23
|
+
* - **Re-implementation of any per-language resolver.** We wrap the
|
|
24
|
+
* existing `importResolver` field on each `LanguageProvider` — the
|
|
25
|
+
* same code path the legacy DAG uses today.
|
|
26
|
+
* - **Dynamic-import handling.** The shared finalize algorithm short-
|
|
27
|
+
* circuits `ParsedImport { kind: 'dynamic-unresolved' }` before
|
|
28
|
+
* calling `resolveImportTarget`, so the adapter never sees those.
|
|
29
|
+
* - **`importPathPreprocessor`.** Preprocessing belongs inside the
|
|
30
|
+
* provider's `interpretImport` hook (which writes the final
|
|
31
|
+
* `ParsedImport.targetRaw`). By the time finalize passes a
|
|
32
|
+
* `targetRaw` to this adapter, it is the string the provider wants
|
|
33
|
+
* resolved verbatim.
|
|
34
|
+
*/
|
|
35
|
+
import { getLanguageFromFilename, } from '../../_shared/index.js';
|
|
36
|
+
/**
|
|
37
|
+
* Build the workspace index from a map of language → provider. Providers
|
|
38
|
+
* whose `importResolver` is absent are silently skipped (no language will
|
|
39
|
+
* ever hit that branch at dispatch time).
|
|
40
|
+
*
|
|
41
|
+
* The `resolveCtx` is shared across all languages. Callers assemble it
|
|
42
|
+
* once per run (the existing pipeline already does this for the legacy
|
|
43
|
+
* DAG) and hand it to both the legacy resolution path and this factory.
|
|
44
|
+
*/
|
|
45
|
+
export function buildImportTargetWorkspace(providers, resolveCtx) {
|
|
46
|
+
const perLanguage = new Map();
|
|
47
|
+
for (const [lang, provider] of providers) {
|
|
48
|
+
if (provider.importResolver === undefined)
|
|
49
|
+
continue;
|
|
50
|
+
perLanguage.set(lang, { resolver: provider.importResolver, ctx: resolveCtx });
|
|
51
|
+
}
|
|
52
|
+
return { perLanguage };
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The FinalizeHooks-compatible implementation. Dispatches on `fromFile`'s
|
|
56
|
+
* extension → per-language resolver. Returns the first resolved file,
|
|
57
|
+
* or `null` if the resolver returns `null` or doesn't know about the
|
|
58
|
+
* language.
|
|
59
|
+
*
|
|
60
|
+
* Picks the first entry of `files[]` for both `'files'` and `'package'`
|
|
61
|
+
* result kinds — the legacy pipeline uses the whole array, but the
|
|
62
|
+
* shared `finalize()` hook contract is single-file. If the workspace
|
|
63
|
+
* later needs richer semantics (split-target packages), this is the
|
|
64
|
+
* single site to extend.
|
|
65
|
+
*/
|
|
66
|
+
export function resolveImportTargetAcrossLanguages(targetRaw, fromFile, workspaceIndex) {
|
|
67
|
+
const workspace = workspaceIndex;
|
|
68
|
+
if (workspace === undefined || workspace.perLanguage === undefined)
|
|
69
|
+
return null;
|
|
70
|
+
const lang = getLanguageFromFilename(fromFile);
|
|
71
|
+
if (lang === null)
|
|
72
|
+
return null;
|
|
73
|
+
const entry = workspace.perLanguage.get(lang);
|
|
74
|
+
if (entry === undefined)
|
|
75
|
+
return null;
|
|
76
|
+
let result;
|
|
77
|
+
try {
|
|
78
|
+
result = entry.resolver(targetRaw, fromFile, entry.ctx);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// Existing resolvers can throw on malformed inputs (e.g., Python
|
|
82
|
+
// relative paths above the workspace root). Swallow — the shared
|
|
83
|
+
// algorithm treats a null here as `linkStatus: 'unresolved'`, which
|
|
84
|
+
// is the right fallback.
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
if (result === null)
|
|
88
|
+
return null;
|
|
89
|
+
// Both `files` and `package` variants expose a `files` array; the
|
|
90
|
+
// package variant also carries `dirSuffix` which we ignore at the
|
|
91
|
+
// FinalizeHook boundary (single-file contract). Legacy consumers
|
|
92
|
+
// continue to see the full result via `importResolver` directly.
|
|
93
|
+
const first = result.files[0];
|
|
94
|
+
return first ?? null;
|
|
95
|
+
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* The providers table in `languages/index.ts` uses `satisfies Record<SupportedLanguages, LanguageProvider>`
|
|
9
9
|
* so adding a language to the enum without creating a provider is a compiler error.
|
|
10
10
|
*/
|
|
11
|
-
import type { SupportedLanguages, MroStrategy } from '../../_shared/index.js';
|
|
11
|
+
import type { SupportedLanguages, MroStrategy, CaptureMatch, BindingRef, TypeRef, Scope, ScopeId, ScopeKind, ScopeTree, ParsedImport, ParsedTypeBinding, SymbolDefinition, Callsite, WorkspaceIndex } from '../../_shared/index.js';
|
|
12
12
|
import type { LanguageTypeConfig } from './type-extractors/types.js';
|
|
13
13
|
import type { CallRouter } from './call-routing.js';
|
|
14
14
|
import type { CallExtractor, DispatchDecision, ImplicitReceiverOverride, ReceiverEnriched } from './call-types.js';
|
|
@@ -222,6 +222,192 @@ interface LanguageProviderConfig {
|
|
|
222
222
|
/** Built-in/stdlib names that should be filtered from the call graph for this language.
|
|
223
223
|
* Default: undefined (no language-specific filtering). */
|
|
224
224
|
readonly builtInNames?: ReadonlySet<string>;
|
|
225
|
+
/**
|
|
226
|
+
* Emit scope captures from raw source, **pre-grouped per tree-sitter
|
|
227
|
+
* query match**. Tree-sitter-based providers run a `scopes.scm` query
|
|
228
|
+
* and emit one `CaptureMatch` per query match; standalone providers
|
|
229
|
+
* (COBOL) emit matches from a regex tagger. The return shape is
|
|
230
|
+
* parser-agnostic: the central `ScopeExtractor` consumes
|
|
231
|
+
* `CaptureMatch[]` without knowing which parser produced them.
|
|
232
|
+
*
|
|
233
|
+
* **Pre-grouping is the provider's job.** The extractor expects each
|
|
234
|
+
* `CaptureMatch` to correspond to one logical match — e.g., an import
|
|
235
|
+
* statement match carries `@import.statement` + `@import.source` +
|
|
236
|
+
* `@import.name` keyed under their capture names. Providers MUST
|
|
237
|
+
* preserve the tree-sitter match boundaries so the extractor's topic
|
|
238
|
+
* routing (scope / declaration / import / type-binding / reference)
|
|
239
|
+
* lands on coherent records.
|
|
240
|
+
*
|
|
241
|
+
* Required for any provider participating in scope-based resolution.
|
|
242
|
+
* Providers that have not yet migrated continue to run through the
|
|
243
|
+
* legacy DAG path (feature-flagged per `REGISTRY_PRIMARY_<LANG>`).
|
|
244
|
+
*
|
|
245
|
+
* **Sync return.** Tree-sitter query execution and COBOL's regex
|
|
246
|
+
* tagger are both synchronous; no current or foreseeable provider
|
|
247
|
+
* needs async work inside this hook. The sync signature lets
|
|
248
|
+
* `parse-worker.ts` (#920) invoke it inline in its already-sync
|
|
249
|
+
* per-file loop without cascading `async` through the batch pipeline.
|
|
250
|
+
*
|
|
251
|
+
* Default: undefined (language continues to use legacy DAG).
|
|
252
|
+
*/
|
|
253
|
+
readonly emitScopeCaptures?: (sourceText: string, filePath: string) => readonly CaptureMatch[];
|
|
254
|
+
/**
|
|
255
|
+
* Interpret a raw `@import.statement` capture group into a `ParsedImport`.
|
|
256
|
+
* The central finalize algorithm resolves `ParsedImport.targetRaw` to a
|
|
257
|
+
* concrete file via `resolveImportTarget` and materializes the final
|
|
258
|
+
* `ImportEdge` with `targetModuleScope` / `targetDefId` filled in.
|
|
259
|
+
*
|
|
260
|
+
* Required when `emitScopeCaptures` is implemented.
|
|
261
|
+
*/
|
|
262
|
+
readonly interpretImport?: (captures: CaptureMatch) => ParsedImport | null;
|
|
263
|
+
/**
|
|
264
|
+
* What is the implicit receiver on a Function scope? For instance methods
|
|
265
|
+
* this is `self`/`this`; for standalone functions it is `null`. Consulted
|
|
266
|
+
* by `Registry.lookup` Step 2 via the `resolveTypeRef` helper.
|
|
267
|
+
*
|
|
268
|
+
* Required for any language with method dispatch (OO semantics).
|
|
269
|
+
*
|
|
270
|
+
* Default: undefined (treated as `null` — no implicit receiver).
|
|
271
|
+
*/
|
|
272
|
+
readonly receiverBinding?: (functionScope: Scope) => TypeRef | null;
|
|
273
|
+
/**
|
|
274
|
+
* Interpret a raw type-binding capture (parameter annotation, `self`,
|
|
275
|
+
* assignment with constructor RHS, …) into a `ParsedTypeBinding`. The
|
|
276
|
+
* central extractor attaches the resulting `TypeRef` to the appropriate
|
|
277
|
+
* scope's `typeBindings` map.
|
|
278
|
+
*
|
|
279
|
+
* Default: undefined (falls back to `{ boundName: captures.name, rawTypeName: captures.type, source: 'annotation' }`).
|
|
280
|
+
*/
|
|
281
|
+
readonly interpretTypeBinding?: (captures: CaptureMatch) => ParsedTypeBinding | null;
|
|
282
|
+
/**
|
|
283
|
+
* Override the `ScopeKind` assigned to a scope capture. Use when the
|
|
284
|
+
* capture name alone can't resolve the kind (e.g., tree-sitter captures
|
|
285
|
+
* a `block` that is semantically an `Expression` in this language).
|
|
286
|
+
*
|
|
287
|
+
* Default: undefined (the central extractor uses the capture name's
|
|
288
|
+
* suffix — `@scope.function` → `'Function'`, etc.).
|
|
289
|
+
*/
|
|
290
|
+
readonly resolveScopeKind?: (captures: CaptureMatch) => ScopeKind | null;
|
|
291
|
+
/**
|
|
292
|
+
* Should this scope capture materialize as a real `Scope` node? Return
|
|
293
|
+
* `false` to skip scope creation while still emitting declarations that
|
|
294
|
+
* would have gone inside (they attach to the enclosing real scope).
|
|
295
|
+
*
|
|
296
|
+
* Example: Python `if`/`for`/`while` bodies capture as `@scope.block` but
|
|
297
|
+
* Python has no block scope — hook returns `false` and child declarations
|
|
298
|
+
* lift to the enclosing function/module.
|
|
299
|
+
*
|
|
300
|
+
* Default: undefined (treated as `true` — always create).
|
|
301
|
+
*/
|
|
302
|
+
readonly shouldCreateScope?: (captures: CaptureMatch) => boolean;
|
|
303
|
+
/**
|
|
304
|
+
* Override where a declaration's name becomes visible. By default the name
|
|
305
|
+
* is bound in the innermost enclosing scope; return a different `ScopeId`
|
|
306
|
+
* to hoist it (JS `var` → enclosing function scope; Ruby `def` inside
|
|
307
|
+
* `begin` → enclosing class scope).
|
|
308
|
+
*
|
|
309
|
+
* Return `null` to delegate to the central default (innermost enclosing
|
|
310
|
+
* scope). This matches the `X | null` convention used by the other optional
|
|
311
|
+
* hooks and supports partial overrides — e.g., a JS provider can return a
|
|
312
|
+
* hoisted scope for `var` declarations and `null` for `let`/`const`, without
|
|
313
|
+
* re-implementing the default lookup.
|
|
314
|
+
*
|
|
315
|
+
* **Purity:** must be a pure function of its inputs — same parameters must
|
|
316
|
+
* yield the same `ScopeId` (or `null`) across invocations. No closure over
|
|
317
|
+
* mutable state. Required so scope-tree construction stays deterministic
|
|
318
|
+
* across re-parses.
|
|
319
|
+
*
|
|
320
|
+
* Default: undefined (the central extractor uses `innermostScope.id`).
|
|
321
|
+
*/
|
|
322
|
+
readonly bindingScopeFor?: (declCapture: CaptureMatch, innermostScope: Scope, scopeTree: ScopeTree) => ScopeId | null;
|
|
323
|
+
/**
|
|
324
|
+
* Resolve a `ParsedImport.targetRaw` expression to a concrete file path in
|
|
325
|
+
* the workspace. Language-specific resolution: Python relative imports,
|
|
326
|
+
* JS package.json + node_modules, Go module paths, Java classpath,
|
|
327
|
+
* COBOL COPY paths. Ports today's per-language import resolver.
|
|
328
|
+
*
|
|
329
|
+
* Required when `emitScopeCaptures` is implemented. Ring 2 PKG #922
|
|
330
|
+
* provides the adapter that bridges today's resolver shape to this hook.
|
|
331
|
+
*/
|
|
332
|
+
readonly resolveImportTarget?: (parsedImport: ParsedImport, workspaceIndex: WorkspaceIndex) => string | null;
|
|
333
|
+
/**
|
|
334
|
+
* Enumerate the exported names of a file — used by the finalize algorithm
|
|
335
|
+
* to expand `import * from M` into individual `BindingRef`s with
|
|
336
|
+
* `origin: 'wildcard'`.
|
|
337
|
+
*
|
|
338
|
+
* Default: undefined (central finalize walks the target file's
|
|
339
|
+
* `ExportMap.keys()`).
|
|
340
|
+
*/
|
|
341
|
+
readonly expandsWildcardTo?: (targetFile: string, workspaceIndex: WorkspaceIndex) => readonly string[];
|
|
342
|
+
/**
|
|
343
|
+
* Decide the scope to which a `ParsedImport` attaches. Most languages
|
|
344
|
+
* attach imports to the nearest enclosing `Module`/`Namespace` scope
|
|
345
|
+
* (the default); some languages allow local imports (Python function-local
|
|
346
|
+
* `from x import Y`, Rust fn-local `use`, TS dynamic `import()`) — return
|
|
347
|
+
* a `Function`/`Block` scope id instead.
|
|
348
|
+
*
|
|
349
|
+
* Return `null` to delegate to the central default (nearest enclosing
|
|
350
|
+
* `Module`/`Namespace`). This matches the `X | null` convention used by
|
|
351
|
+
* the other optional hooks and supports partial overrides — a provider
|
|
352
|
+
* that handles only specific import forms non-standardly can `return null`
|
|
353
|
+
* for the common cases and let the central walk handle them.
|
|
354
|
+
*
|
|
355
|
+
* **Purity:** must be a pure function of its inputs — same parameters must
|
|
356
|
+
* yield the same `ScopeId` (or `null`) across invocations. No closure over
|
|
357
|
+
* mutable state. Required so scope-tree construction stays deterministic
|
|
358
|
+
* across re-parses.
|
|
359
|
+
*
|
|
360
|
+
* Default: undefined (central finalize walks to the nearest enclosing
|
|
361
|
+
* `Module` or `Namespace` scope).
|
|
362
|
+
*/
|
|
363
|
+
readonly importOwningScope?: (parsedImport: ParsedImport, innermostScope: Scope, scopeTree: ScopeTree) => ScopeId | null;
|
|
364
|
+
/**
|
|
365
|
+
* Merge local declarations and imported bindings for a single (scope, name)
|
|
366
|
+
* during finalize materialization of a scope's binding table. Language-
|
|
367
|
+
* specific precedence: Python local hides import; TypeScript namespace
|
|
368
|
+
* merging keeps both; Ruby constant resolution has its own rules.
|
|
369
|
+
*
|
|
370
|
+
* Default: undefined (central finalize uses local-first-then-imports,
|
|
371
|
+
* deduping by `DefId`).
|
|
372
|
+
*/
|
|
373
|
+
readonly mergeBindings?: (scope: Scope, bindings: readonly BindingRef[]) => readonly BindingRef[];
|
|
374
|
+
/**
|
|
375
|
+
* Classify a `@reference.call` capture as free / member / constructor /
|
|
376
|
+
* index. Preferred path is declarative via capture sub-tags
|
|
377
|
+
* (`@reference.call.free`, etc.); this hook handles the languages where
|
|
378
|
+
* call form can't be decided statically (Ruby bare `foo(x)` is free-or-
|
|
379
|
+
* member until resolved).
|
|
380
|
+
*
|
|
381
|
+
* Default: undefined (central extractor reads capture sub-tag if present;
|
|
382
|
+
* else treats as `'free'`).
|
|
383
|
+
*/
|
|
384
|
+
readonly classifyCallForm?: (captures: CaptureMatch, enclosingScope: Scope) => 'free' | 'member' | 'constructor' | 'index';
|
|
385
|
+
/**
|
|
386
|
+
* Does a binding at this scope shadow bindings of the same name in outer
|
|
387
|
+
* scopes? Default: any binding shadows (standard lexical scoping). Return
|
|
388
|
+
* `false` for transparent-scope edge cases (Python `from x import *`
|
|
389
|
+
* contexts, JS `var` hoisting quirks, COBOL PARAGRAPH transparency).
|
|
390
|
+
*
|
|
391
|
+
* Consulted by `Registry.lookup` Step 1 and by `resolveTypeRef` for
|
|
392
|
+
* shadowing decisions during the lexical chain walk.
|
|
393
|
+
*
|
|
394
|
+
* Default: undefined (treated as `true` — any binding shadows).
|
|
395
|
+
*/
|
|
396
|
+
readonly shouldShadow?: (scope: Scope, bindings: readonly BindingRef[]) => boolean;
|
|
397
|
+
/**
|
|
398
|
+
* Is this callable definition compatible with the given call-site arity?
|
|
399
|
+
* Language-specific rules: Python `*args`/`**kwargs`/defaults, JS default
|
|
400
|
+
* params + rest, Kotlin vararg + defaults, Ruby optional/splat/block, Go
|
|
401
|
+
* straight counts, Rust no-variadic-no-defaults.
|
|
402
|
+
*
|
|
403
|
+
* `'incompatible'` is a soft penalty (−0.15 per EvidenceWeights) and is
|
|
404
|
+
* filtered only when at least one `'compatible'` candidate exists;
|
|
405
|
+
* otherwise the incompatible candidate is kept with the penalty so the
|
|
406
|
+
* call-site still links to a best-guess target.
|
|
407
|
+
*
|
|
408
|
+
* Default: undefined (treated as `'unknown'` — no signal either way).
|
|
409
|
+
*/
|
|
410
|
+
readonly arityCompatibility?: (def: SymbolDefinition, callsite: Callsite) => 'compatible' | 'unknown' | 'incompatible';
|
|
225
411
|
}
|
|
226
412
|
/** Runtime type — same as LanguageProviderConfig but with defaults guaranteed present. */
|
|
227
413
|
export interface LanguageProvider extends Omit<LanguageProviderConfig, 'importSemantics' | 'heritageDefaultEdge' | 'mroStrategy'> {
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ScopeResolutionIndexes` — the bundle of materialized indexes produced
|
|
3
|
+
* by the finalize-orchestrator (RFC #909 Ring 2 PKG #921) and attached
|
|
4
|
+
* to `MutableSemanticModel`.
|
|
5
|
+
*
|
|
6
|
+
* Produced by `finalizeScopeModel(parsedFiles, hooks)` in
|
|
7
|
+
* `finalize-orchestrator.ts`. Consumed by the resolution phase (future
|
|
8
|
+
* tickets) where `Registry.lookup` / `resolveTypeRef` query this bundle
|
|
9
|
+
* to answer call-resolution questions without re-walking any AST.
|
|
10
|
+
*
|
|
11
|
+
* ## Lifecycle
|
|
12
|
+
*
|
|
13
|
+
* 1. Pipeline collects `ParsedFile[]` from the parsing-processor (#920).
|
|
14
|
+
* 2. Pipeline invokes `finalizeScopeModel(parsedFiles, hooks)` →
|
|
15
|
+
* returns a `ScopeResolutionIndexes` (this interface).
|
|
16
|
+
* 3. Pipeline calls `model.attachScopeIndexes(indexes)` to stamp them
|
|
17
|
+
* onto the `MutableSemanticModel`. This is a **one-shot write**;
|
|
18
|
+
* subsequent calls throw. After attachment, the indexes are frozen
|
|
19
|
+
* at the type level (everything is `readonly`) and at runtime via
|
|
20
|
+
* `Object.freeze` on the bundle.
|
|
21
|
+
* 4. Resolution callers hold a `SemanticModel` reference and read
|
|
22
|
+
* `model.scopes` to query.
|
|
23
|
+
*
|
|
24
|
+
* ## Content
|
|
25
|
+
*
|
|
26
|
+
* - `scopeTree` / `moduleScopes` / `defs` / `qualifiedNames` — the
|
|
27
|
+
* four Ring 2 SHARED indexes built over per-file artifacts.
|
|
28
|
+
* - `methodDispatch` — MRO + implements materialized view (#914).
|
|
29
|
+
* - `imports` — finalized `ImportEdge[]` per module scope (`parsedImports`
|
|
30
|
+
* resolved through cross-file link + wildcard expansion).
|
|
31
|
+
* - `bindings` — merged bindings per module scope (local + import +
|
|
32
|
+
* wildcard + re-export), with the provider's precedence applied.
|
|
33
|
+
* - `referenceSites` — union of every file's pre-resolution usage
|
|
34
|
+
* facts. Consumed by the resolution phase (future) to emit
|
|
35
|
+
* `Reference` records into `ReferenceIndex`.
|
|
36
|
+
* - `stats` — coarse-grained counts from the shared finalize algorithm
|
|
37
|
+
* (total files/edges, linked vs unresolved, SCC topology).
|
|
38
|
+
*
|
|
39
|
+
* `ReferenceIndex` is deliberately NOT here — it is populated in a later
|
|
40
|
+
* phase (RFC §3.2 Phase 4 / Ring 2 PKG #925) and owned separately.
|
|
41
|
+
*/
|
|
42
|
+
import type { BindingRef, DefIndex, FinalizedScc, FinalizeStats, ImportEdge, MethodDispatchIndex, ModuleScopeIndex, QualifiedNameIndex, ReferenceSite, ScopeId, ScopeTree } from '../../../_shared/index.js';
|
|
43
|
+
export interface ScopeResolutionIndexes {
|
|
44
|
+
readonly scopeTree: ScopeTree;
|
|
45
|
+
readonly defs: DefIndex;
|
|
46
|
+
readonly qualifiedNames: QualifiedNameIndex;
|
|
47
|
+
readonly moduleScopes: ModuleScopeIndex;
|
|
48
|
+
readonly methodDispatch: MethodDispatchIndex;
|
|
49
|
+
/** Finalized `ImportEdge[]` per module scope. */
|
|
50
|
+
readonly imports: ReadonlyMap<ScopeId, readonly ImportEdge[]>;
|
|
51
|
+
/** Merged bindings (local + imports + wildcards) per module scope. */
|
|
52
|
+
readonly bindings: ReadonlyMap<ScopeId, ReadonlyMap<string, readonly BindingRef[]>>;
|
|
53
|
+
/** Pre-resolution usage facts; consumed by the resolution phase. */
|
|
54
|
+
readonly referenceSites: readonly ReferenceSite[];
|
|
55
|
+
/** SCC condensation of the file-level import graph — callers that want
|
|
56
|
+
* parallel per-SCC processing in the resolution phase read this. */
|
|
57
|
+
readonly sccs: readonly FinalizedScc[];
|
|
58
|
+
readonly stats: FinalizeStats;
|
|
59
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ScopeResolutionIndexes` — the bundle of materialized indexes produced
|
|
3
|
+
* by the finalize-orchestrator (RFC #909 Ring 2 PKG #921) and attached
|
|
4
|
+
* to `MutableSemanticModel`.
|
|
5
|
+
*
|
|
6
|
+
* Produced by `finalizeScopeModel(parsedFiles, hooks)` in
|
|
7
|
+
* `finalize-orchestrator.ts`. Consumed by the resolution phase (future
|
|
8
|
+
* tickets) where `Registry.lookup` / `resolveTypeRef` query this bundle
|
|
9
|
+
* to answer call-resolution questions without re-walking any AST.
|
|
10
|
+
*
|
|
11
|
+
* ## Lifecycle
|
|
12
|
+
*
|
|
13
|
+
* 1. Pipeline collects `ParsedFile[]` from the parsing-processor (#920).
|
|
14
|
+
* 2. Pipeline invokes `finalizeScopeModel(parsedFiles, hooks)` →
|
|
15
|
+
* returns a `ScopeResolutionIndexes` (this interface).
|
|
16
|
+
* 3. Pipeline calls `model.attachScopeIndexes(indexes)` to stamp them
|
|
17
|
+
* onto the `MutableSemanticModel`. This is a **one-shot write**;
|
|
18
|
+
* subsequent calls throw. After attachment, the indexes are frozen
|
|
19
|
+
* at the type level (everything is `readonly`) and at runtime via
|
|
20
|
+
* `Object.freeze` on the bundle.
|
|
21
|
+
* 4. Resolution callers hold a `SemanticModel` reference and read
|
|
22
|
+
* `model.scopes` to query.
|
|
23
|
+
*
|
|
24
|
+
* ## Content
|
|
25
|
+
*
|
|
26
|
+
* - `scopeTree` / `moduleScopes` / `defs` / `qualifiedNames` — the
|
|
27
|
+
* four Ring 2 SHARED indexes built over per-file artifacts.
|
|
28
|
+
* - `methodDispatch` — MRO + implements materialized view (#914).
|
|
29
|
+
* - `imports` — finalized `ImportEdge[]` per module scope (`parsedImports`
|
|
30
|
+
* resolved through cross-file link + wildcard expansion).
|
|
31
|
+
* - `bindings` — merged bindings per module scope (local + import +
|
|
32
|
+
* wildcard + re-export), with the provider's precedence applied.
|
|
33
|
+
* - `referenceSites` — union of every file's pre-resolution usage
|
|
34
|
+
* facts. Consumed by the resolution phase (future) to emit
|
|
35
|
+
* `Reference` records into `ReferenceIndex`.
|
|
36
|
+
* - `stats` — coarse-grained counts from the shared finalize algorithm
|
|
37
|
+
* (total files/edges, linked vs unresolved, SCC topology).
|
|
38
|
+
*
|
|
39
|
+
* `ReferenceIndex` is deliberately NOT here — it is populated in a later
|
|
40
|
+
* phase (RFC §3.2 Phase 4 / Ring 2 PKG #925) and owned separately.
|
|
41
|
+
*/
|
|
42
|
+
export {};
|
|
@@ -49,6 +49,7 @@ import type { TypeRegistry, MutableTypeRegistry } from './type-registry.js';
|
|
|
49
49
|
import type { MethodRegistry, MutableMethodRegistry } from './method-registry.js';
|
|
50
50
|
import type { FieldRegistry, MutableFieldRegistry } from './field-registry.js';
|
|
51
51
|
import type { SymbolTableReader, SymbolTableWriter } from './symbol-table.js';
|
|
52
|
+
import type { ScopeResolutionIndexes } from './scope-resolution-indexes.js';
|
|
52
53
|
/**
|
|
53
54
|
* Aggregated read-only view of the semantic registries plus the nested
|
|
54
55
|
* file/callable SymbolTable.
|
|
@@ -70,6 +71,19 @@ export interface SemanticModel {
|
|
|
70
71
|
readonly methods: MethodRegistry;
|
|
71
72
|
readonly fields: FieldRegistry;
|
|
72
73
|
readonly symbols: SymbolTableReader;
|
|
74
|
+
/**
|
|
75
|
+
* Materialized scope-resolution indexes from RFC #909 Ring 2 PKG #921.
|
|
76
|
+
*
|
|
77
|
+
* `undefined` until the finalize-orchestrator attaches them. While
|
|
78
|
+
* `undefined`, the legacy DAG is the sole resolution surface; once set,
|
|
79
|
+
* resolvers whose language has `REGISTRY_PRIMARY_<LANG>=true` consult
|
|
80
|
+
* these indexes instead.
|
|
81
|
+
*
|
|
82
|
+
* The attach is a one-shot write (see `MutableSemanticModel`). Callers
|
|
83
|
+
* holding a read-only `SemanticModel` handle see either `undefined` or
|
|
84
|
+
* the final frozen bundle — never a half-populated view.
|
|
85
|
+
*/
|
|
86
|
+
readonly scopes?: ScopeResolutionIndexes;
|
|
73
87
|
}
|
|
74
88
|
/** Mutable variant — exposes the MutableX registries, a Writer-typed
|
|
75
89
|
* `symbols` facade, and a full-cascade reset. This is the interface
|
|
@@ -82,5 +96,16 @@ export interface MutableSemanticModel extends SemanticModel {
|
|
|
82
96
|
readonly symbols: SymbolTableWriter;
|
|
83
97
|
/** Clear all registries AND the nested SymbolTable. */
|
|
84
98
|
clear(): void;
|
|
99
|
+
/**
|
|
100
|
+
* Stamp the finalize-orchestrator's output onto this model.
|
|
101
|
+
*
|
|
102
|
+
* **One-shot write.** Throws when called a second time — the indexes are
|
|
103
|
+
* meant to be materialized once per ingestion run. `Object.freeze` is
|
|
104
|
+
* applied to the attached bundle so consumers cannot mutate after attach.
|
|
105
|
+
*
|
|
106
|
+
* `clear()` resets the attached bundle back to `undefined`, enabling a
|
|
107
|
+
* fresh re-ingestion to attach a new bundle.
|
|
108
|
+
*/
|
|
109
|
+
attachScopeIndexes(indexes: ScopeResolutionIndexes): void;
|
|
85
110
|
}
|
|
86
111
|
export declare const createSemanticModel: () => MutableSemanticModel;
|
|
@@ -85,6 +85,17 @@ export const createSemanticModel = () => {
|
|
|
85
85
|
}
|
|
86
86
|
return def;
|
|
87
87
|
};
|
|
88
|
+
// Scope-resolution bundle slot. Starts `undefined`; populated by a
|
|
89
|
+
// one-shot `attachScopeIndexes(...)` from the finalize-orchestrator.
|
|
90
|
+
// Held inside the factory closure so the returned `SemanticModel`
|
|
91
|
+
// surface exposes it as a plain `readonly` property without a setter.
|
|
92
|
+
let attachedScopes;
|
|
93
|
+
const attachScopeIndexes = (indexes) => {
|
|
94
|
+
if (attachedScopes !== undefined) {
|
|
95
|
+
throw new Error('SemanticModel: scope indexes already attached. ' + 'Call `clear()` before re-attaching.');
|
|
96
|
+
}
|
|
97
|
+
attachedScopes = Object.freeze(indexes);
|
|
98
|
+
};
|
|
88
99
|
// Cascade clear: single source of truth for "reset the entire model".
|
|
89
100
|
// Wired into both `model.clear()` AND `model.symbols.clear()` so that a
|
|
90
101
|
// caller holding only a SymbolTable reference can't leave the
|
|
@@ -95,6 +106,7 @@ export const createSemanticModel = () => {
|
|
|
95
106
|
methods.clear();
|
|
96
107
|
fields.clear();
|
|
97
108
|
rawSymbols.clear();
|
|
109
|
+
attachedScopes = undefined;
|
|
98
110
|
};
|
|
99
111
|
// Writer-typed facade: exposes reads + add, but NO `clear` field.
|
|
100
112
|
// Callers holding a `SemanticModel.symbols` reference cannot desync
|
|
@@ -115,6 +127,10 @@ export const createSemanticModel = () => {
|
|
|
115
127
|
methods,
|
|
116
128
|
fields,
|
|
117
129
|
symbols,
|
|
130
|
+
get scopes() {
|
|
131
|
+
return attachedScopes;
|
|
132
|
+
},
|
|
118
133
|
clear: cascadeClear,
|
|
134
|
+
attachScopeIndexes,
|
|
119
135
|
};
|
|
120
136
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { KnowledgeGraph } from '../graph/types.js';
|
|
2
2
|
import type { SymbolTableWriter, ExtractedHeritage } from './model/index.js';
|
|
3
3
|
import { ASTCache } from './ast-cache.js';
|
|
4
|
+
import type { ParsedFile } from '../../_shared/index.js';
|
|
4
5
|
import { WorkerPool } from './workers/worker-pool.js';
|
|
5
6
|
import type { ExtractedImport, ExtractedCall, ExtractedAssignment, ExtractedRoute, ExtractedFetchCall, ExtractedDecoratorRoute, ExtractedToolDef, FileConstructorBindings, FileScopeBindings, ExtractedORMQuery } from './workers/parse-worker.js';
|
|
6
7
|
export type FileProgressCallback = (current: number, total: number, filePath: string) => void;
|
|
@@ -16,6 +17,14 @@ export interface WorkerExtractedData {
|
|
|
16
17
|
ormQueries: ExtractedORMQuery[];
|
|
17
18
|
constructorBindings: FileConstructorBindings[];
|
|
18
19
|
fileScopeBindings: FileScopeBindings[];
|
|
20
|
+
/**
|
|
21
|
+
* Per-file `ParsedFile` artifacts from the new scope-based resolution
|
|
22
|
+
* pipeline (RFC #909 Ring 2). Empty until a provider implements
|
|
23
|
+
* `emitScopeCaptures` — additive to the legacy DAG path. Aggregated
|
|
24
|
+
* from every worker chunk; consumed downstream by #921's
|
|
25
|
+
* finalize-orchestrator.
|
|
26
|
+
*/
|
|
27
|
+
parsedFiles: ParsedFile[];
|
|
19
28
|
}
|
|
20
29
|
export declare const processParsing: (graph: KnowledgeGraph, files: {
|
|
21
30
|
path: string;
|
|
@@ -34,6 +34,7 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
|
|
|
34
34
|
ormQueries: [],
|
|
35
35
|
constructorBindings: [],
|
|
36
36
|
fileScopeBindings: [],
|
|
37
|
+
parsedFiles: [],
|
|
37
38
|
};
|
|
38
39
|
const total = files.length;
|
|
39
40
|
// Dispatch to worker pool — pool handles splitting into chunks and sub-batching
|
|
@@ -52,6 +53,7 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
|
|
|
52
53
|
const allORMQueries = [];
|
|
53
54
|
const allConstructorBindings = [];
|
|
54
55
|
const fileScopeBindingsByFile = [];
|
|
56
|
+
const allParsedFiles = [];
|
|
55
57
|
for (const result of chunkResults) {
|
|
56
58
|
for (const node of result.nodes) {
|
|
57
59
|
graph.addNode({
|
|
@@ -98,6 +100,13 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
|
|
|
98
100
|
if (result.fileScopeBindings)
|
|
99
101
|
for (const item of result.fileScopeBindings)
|
|
100
102
|
fileScopeBindingsByFile.push(item);
|
|
103
|
+
// RFC #909 Ring 2: aggregate per-file scope artifacts. Tolerant of
|
|
104
|
+
// workers that don't emit the field yet (older worker builds or
|
|
105
|
+
// partial rollouts), since the additive contract means undefined =
|
|
106
|
+
// "this worker produced no ParsedFiles for this chunk".
|
|
107
|
+
if (result.parsedFiles)
|
|
108
|
+
for (const item of result.parsedFiles)
|
|
109
|
+
allParsedFiles.push(item);
|
|
101
110
|
}
|
|
102
111
|
// Merge and log skipped languages from workers
|
|
103
112
|
const skippedLanguages = new Map();
|
|
@@ -126,6 +135,7 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
|
|
|
126
135
|
ormQueries: allORMQueries,
|
|
127
136
|
constructorBindings: allConstructorBindings,
|
|
128
137
|
fileScopeBindings: fileScopeBindingsByFile,
|
|
138
|
+
parsedFiles: allParsedFiles,
|
|
129
139
|
};
|
|
130
140
|
};
|
|
131
141
|
// ============================================================================
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `REGISTRY_PRIMARY_<LANG>` per-language feature flags for the scope-based
|
|
3
|
+
* resolution rollout (RFC §6.1 Ring 3; Ring 2 PKG #924).
|
|
4
|
+
*
|
|
5
|
+
* This module is the single source of truth for whether a given language
|
|
6
|
+
* has been flipped to registry-primary call resolution. When a language's
|
|
7
|
+
* flag is true, its files route through `Registry.lookup` (RFC §4) instead
|
|
8
|
+
* of the legacy call-resolution DAG; when false (the default), the legacy
|
|
9
|
+
* DAG runs unchanged.
|
|
10
|
+
*
|
|
11
|
+
* ## Contract
|
|
12
|
+
*
|
|
13
|
+
* - Env-var name per language: `REGISTRY_PRIMARY_<UPPER(enum-value)>`.
|
|
14
|
+
* Example: `SupportedLanguages.Python` → `REGISTRY_PRIMARY_PYTHON`;
|
|
15
|
+
* `SupportedLanguages.CPlusPlus` (value `'cpp'`) → `REGISTRY_PRIMARY_CPP`.
|
|
16
|
+
* - Truthy values: `'true'`, `'1'`, `'yes'` (case-insensitive,
|
|
17
|
+
* whitespace-trimmed). Anything else — including `undefined`, empty
|
|
18
|
+
* string, or unknown tokens — is `false`.
|
|
19
|
+
* - No per-process caching. `process.env` is read on every call. The
|
|
20
|
+
* flag is consulted once per file at call-resolution time, so the
|
|
21
|
+
* overhead is negligible; skipping caching keeps test isolation
|
|
22
|
+
* trivial (no `resetFlagCache()` coordination needed).
|
|
23
|
+
*
|
|
24
|
+
* ## Integration site
|
|
25
|
+
*
|
|
26
|
+
* `call-processor.ts` integration lands in **#921** (`finalize-orchestrator`)
|
|
27
|
+
* where the `SemanticModel` becomes accessible and `Registry.lookup` can
|
|
28
|
+
* actually be called with a populated context. This module ships the flag
|
|
29
|
+
* primitive in isolation so #921 has a clean, tested utility to consult.
|
|
30
|
+
*
|
|
31
|
+
* ## Shadow mode is orthogonal
|
|
32
|
+
*
|
|
33
|
+
* Shadow mode (`GITNEXUS_SHADOW_MODE=1`, introduced in #923) runs BOTH
|
|
34
|
+
* legacy and registry paths regardless of the per-language flag, so the
|
|
35
|
+
* parity dashboard has signal even for un-flipped languages. That logic
|
|
36
|
+
* lives in `shadow-harness.ts` (#923), not here.
|
|
37
|
+
*/
|
|
38
|
+
import { SupportedLanguages } from '../../_shared/index.js';
|
|
39
|
+
/**
|
|
40
|
+
* Return the env-var name that controls a given language's registry-
|
|
41
|
+
* primary flag. Exported for test assertions and for the PR-labeling
|
|
42
|
+
* CI job that cross-references per-language flag changes.
|
|
43
|
+
*/
|
|
44
|
+
export declare function envVarNameFor(lang: SupportedLanguages): string;
|
|
45
|
+
/**
|
|
46
|
+
* Whether `lang` has been flipped to registry-primary call resolution.
|
|
47
|
+
*
|
|
48
|
+
* Returns `false` by default — a language must explicitly set its env
|
|
49
|
+
* var to a truthy value to opt in. The flag is the sole control surface:
|
|
50
|
+
* flipping it requires no code change, and reverting it requires no code
|
|
51
|
+
* change.
|
|
52
|
+
*/
|
|
53
|
+
export declare function isRegistryPrimary(lang: SupportedLanguages): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* All languages whose registry-primary flag is currently on. Useful for
|
|
56
|
+
* startup-time logging + the shadow-harness dashboard, which wants to
|
|
57
|
+
* distinguish "primary: legacy" from "primary: registry" rows.
|
|
58
|
+
*/
|
|
59
|
+
export declare function primaryLanguages(): ReadonlySet<SupportedLanguages>;
|