diff --git a/.claude/scheduled_tasks.lock b/.claude/scheduled_tasks.lock new file mode 100644 index 000000000..efd734a71 --- /dev/null +++ b/.claude/scheduled_tasks.lock @@ -0,0 +1 @@ +{"sessionId":"67109eaf-0d84-41ff-9cdf-1cd9715e8283","pid":2680,"acquiredAt":1776588137183} \ No newline at end of file diff --git a/gitnexus/src/core/ingestion/emit-core/index.ts b/gitnexus/src/core/ingestion/emit-core/index.ts deleted file mode 100644 index cdc667564..000000000 --- a/gitnexus/src/core/ingestion/emit-core/index.ts +++ /dev/null @@ -1,57 +0,0 @@ -/** - * `emit-core/` — language-agnostic graph-feeding primitives for the - * registry-primary scope-resolution pipeline. - * - * Responsibility boundary: - * - `gitnexus-shared/src/scope-resolution/` owns the semantic model - * (indexes, ParsedFile, registries, TypeRef, Reference). - * - `emit-core/` owns the bridge from that model to the legacy - * `KnowledgeGraph` edge format. Lives here (CLI, not shared) - * because graph bridging depends on `KnowledgeGraph` + `generateId` - * which are CLI-local. - * - `languages//emit/` owns per-language post-passes that - * compose these primitives with language-specific captures and - * strategies (MRO, ownership, receiver conventions). - * - * Next-consumer contract: when the next language provider migrates - * (TypeScript #927, JavaScript #928, etc.), it imports from this - * module's public surface and never re-implements any of these - * functions. See the per-file JSDoc for per-function reuse notes. - */ - -export { - buildGraphNodeLookup, - isLinkableLabel, - type GraphNodeLookup, -} from './graph-node-lookup.js'; -export { resolveCallerGraphId, resolveDefGraphId, simpleQualifiedName } from './graph-id.js'; -export { mapReferenceKindToEdgeType, tryEmitEdge } from './emit-edge.js'; -export { emitReferencesViaLookup } from './emit-references.js'; -export { emitImportEdges } from './emit-imports.js'; -export { - findReceiverTypeBinding, - findClassBindingInScope, - findCallableBindingInScope, - findEnclosingClassDef, - findExportedDefByName, - findOwnedMember, - findExportedDef, - populateClassOwnedMembers, -} from './scope-walkers.js'; -export { emitFreeCallFallback } from './emit-free-call.js'; -export { emitReceiverBoundCalls } from './emit-receiver-bound.js'; -export { - matchingOpenParen, - resolveCompoundReceiverClass, - type ResolveCompoundReceiverOptions, -} from './emit-compound-receiver.js'; -export { followChainPostFinalize, propagateImportedReturnTypes } from './propagate-return-types.js'; -export { collectNamespaceTargets } from './namespace-targets.js'; -export { buildPopulatedMethodDispatch } from './method-dispatch-bridge.js'; -export type { ArityVerdict, EmitProvider, LinearizeStrategy } from './emit-provider.js'; -export { buildMro, defaultLinearize } from './build-mro.js'; -export { - runScopeResolution, - type RunScopeResolutionInput, - type RunScopeResolutionStats, -} from './orchestrator.js'; diff --git a/gitnexus/src/core/ingestion/emit-providers-registry.ts b/gitnexus/src/core/ingestion/emit-providers-registry.ts deleted file mode 100644 index 800e9e7a3..000000000 --- a/gitnexus/src/core/ingestion/emit-providers-registry.ts +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Per-language `EmitProvider` registry — the lookup the generic - * `scopeResolutionPhase` uses to pick the right provider for each - * migrated language. - * - * Adding a language is two lines: implement an `EmitProvider` in - * `languages//emit/index.ts` and register it here. The phase - * picks it up automatically — no workflow changes, no per-language - * pipeline phase file. - */ - -import { SupportedLanguages } from 'gitnexus-shared'; -import type { EmitProvider } from './emit-core/emit-provider.js'; -import { pythonEmitProvider } from './languages/python/emit/index.js'; - -/** Map of `SupportedLanguages` → `EmitProvider`. The phase iterates - * this map intersected with `MIGRATED_LANGUAGES` (the per-language - * flag set) so adding a provider here without flipping the flag is - * safe — the provider sits idle until the language is migrated. */ -export const EMIT_PROVIDERS: ReadonlyMap = new Map< - SupportedLanguages, - EmitProvider ->([[SupportedLanguages.Python, pythonEmitProvider]]); - -export function getEmitProvider(lang: SupportedLanguages): EmitProvider | undefined { - return EMIT_PROVIDERS.get(lang); -} diff --git a/gitnexus/src/core/ingestion/languages/python/emit-captures.ts b/gitnexus/src/core/ingestion/languages/python/captures.ts similarity index 100% rename from gitnexus/src/core/ingestion/languages/python/emit-captures.ts rename to gitnexus/src/core/ingestion/languages/python/captures.ts diff --git a/gitnexus/src/core/ingestion/languages/python/index.ts b/gitnexus/src/core/ingestion/languages/python/index.ts index f2cb66882..9e6c13de8 100644 --- a/gitnexus/src/core/ingestion/languages/python/index.ts +++ b/gitnexus/src/core/ingestion/languages/python/index.ts @@ -12,7 +12,7 @@ * - `ast-utils.ts` — generic `SyntaxNode` helpers * - `import-decomposer.ts` — `import a, b` / `from m import x, y` → one match per name * - `receiver-binding.ts` — synthesize `self`/`cls` type bindings on methods - * - `emit-captures.ts` — `emitPythonScopeCaptures` (top-level orchestrator) + * - `captures.ts` — `emitPythonScopeCaptures` (top-level orchestrator) * - `interpret.ts` — capture-match → `ParsedImport` / `ParsedTypeBinding` * - `merge-bindings.ts` — Python LEGB precedence * - `arity.ts` — Python arity check (`*args`, `**kwargs`, defaults) @@ -21,7 +21,7 @@ */ export { PYTHON_SCOPE_QUERY } from './query.js'; -export { emitPythonScopeCaptures } from './emit-captures.js'; +export { emitPythonScopeCaptures } from './captures.js'; export { interpretPythonImport, interpretPythonTypeBinding } from './interpret.js'; export { pythonMergeBindings } from './merge-bindings.js'; export { pythonArityCompatibility } from './arity.js'; diff --git a/gitnexus/src/core/ingestion/languages/python/emit/index.ts b/gitnexus/src/core/ingestion/languages/python/scope-resolver.ts similarity index 78% rename from gitnexus/src/core/ingestion/languages/python/emit/index.ts rename to gitnexus/src/core/ingestion/languages/python/scope-resolver.ts index 89900ffdb..485845f5a 100644 --- a/gitnexus/src/core/ingestion/languages/python/emit/index.ts +++ b/gitnexus/src/core/ingestion/languages/python/scope-resolver.ts @@ -1,14 +1,14 @@ /** - * Python `EmitProvider` and the `runPythonScopeResolution` entry point. + * Python `ScopeResolver` and the `resolvePythonScope` entry point. * * The provider is a thin wiring object — Python's specific bits * (super recognizer, LEGB merge precedence, Python's relative-import * resolver, the simplified MRO walk) plug into the generic - * `runScopeResolution` orchestrator from `emit-core/`. + * `runScopeResolution` orchestrator from `scope-resolution/`. * * Migration reference: when bringing up the next language * (TypeScript / Java / Kotlin / Ruby), copy this file's structure — - * implement the 6 required `EmitProvider` fields, optionally toggle + * implement the 6 required `ScopeResolver` fields, optionally toggle * the 2 booleans, and call `runScopeResolution(input, provider)`. */ @@ -19,19 +19,19 @@ import { defaultLinearize, populateClassOwnedMembers, runScopeResolution, - type EmitProvider, + type ScopeResolver, type RunScopeResolutionInput, type RunScopeResolutionStats, -} from '../../../emit-core/index.js'; -import { pythonProvider } from '../../python.js'; +} from '../../scope-resolution/index.js'; +import { pythonProvider } from '../python.js'; import { pythonArityCompatibility, pythonMergeBindings, resolvePythonImportTarget, type PythonResolveContext, -} from '../index.js'; +} from './index.js'; -const pythonEmitProvider: EmitProvider = { +const pythonScopeResolver: ScopeResolver = { language: SupportedLanguages.Python, languageProvider: pythonProvider, importEdgeReason: 'python-scope: import', @@ -77,13 +77,11 @@ const pythonEmitProvider: EmitProvider = { propagatesReturnTypesAcrossImports: true, }; -export { pythonEmitProvider }; +export { pythonScopeResolver }; -export interface RunPythonScopeResolutionInput extends RunScopeResolutionInput {} -export interface RunPythonScopeResolutionStats extends RunScopeResolutionStats {} +export interface ResolvePythonScopeInput extends RunScopeResolutionInput {} +export interface ResolvePythonScopeStats extends RunScopeResolutionStats {} -export function runPythonScopeResolution( - input: RunPythonScopeResolutionInput, -): RunPythonScopeResolutionStats { - return runScopeResolution(input, pythonEmitProvider); +export function resolvePythonScope(input: ResolvePythonScopeInput): ResolvePythonScopeStats { + return runScopeResolution(input, pythonScopeResolver); } diff --git a/gitnexus/src/core/ingestion/pipeline-phases/index.ts b/gitnexus/src/core/ingestion/pipeline-phases/index.ts index 5dcb68593..b1dcf9082 100644 --- a/gitnexus/src/core/ingestion/pipeline-phases/index.ts +++ b/gitnexus/src/core/ingestion/pipeline-phases/index.ts @@ -16,7 +16,10 @@ export { routesPhase, type RoutesOutput, type RouteEntry } from './routes.js'; export { toolsPhase, type ToolsOutput, type ToolDef } from './tools.js'; export { ormPhase, type ORMOutput } from './orm.js'; export { crossFilePhase, type CrossFileOutput } from './cross-file.js'; -export { scopeResolutionPhase, type ScopeResolutionOutput } from './scope-resolution.js'; +export { + scopeResolutionPhase, + type ScopeResolutionOutput, +} from '../scope-resolution/pipeline/phase.js'; export { mroPhase, type MROOutput } from './mro.js'; export { communitiesPhase, type CommunitiesOutput } from './communities.js'; export { processesPhase, type ProcessesOutput } from './processes.js'; diff --git a/gitnexus/src/core/ingestion/emit-core/emit-provider.ts b/gitnexus/src/core/ingestion/scope-resolution/contract/scope-resolver.ts similarity index 91% rename from gitnexus/src/core/ingestion/emit-core/emit-provider.ts rename to gitnexus/src/core/ingestion/scope-resolution/contract/scope-resolver.ts index 53bc1868c..cafc5693b 100644 --- a/gitnexus/src/core/ingestion/emit-core/emit-provider.ts +++ b/gitnexus/src/core/ingestion/scope-resolution/contract/scope-resolver.ts @@ -1,20 +1,20 @@ /** - * `EmitProvider` — the per-language contract consumed by the generic + * `ScopeResolver` — the per-language contract consumed by the generic * scope-resolution orchestrator (`runScopeResolution`). * * ## Migration cookbook (next language) * * To add a language to the registry-primary path: * - * 1. Implement `EmitProvider` in - * `gitnexus/src/core/ingestion/languages//emit/index.ts`. + * 1. Implement `ScopeResolver` in + * `gitnexus/src/core/ingestion/languages//scope-resolver.ts`. * Six required fields (language, languageProvider, * importEdgeReason, resolveImportTarget, mergeBindings, * arityCompatibility, buildMro, populateOwners, isSuperReceiver) * plus two optional booleans (propagatesReturnTypesAcrossImports, * fieldFallbackOnMethodLookup). * 2. Export a thin entry point: - * `runYourLangScopeResolution(input) = runScopeResolution(input, yourEmitProvider)`. + * `runYourLangScopeResolution(input) = runScopeResolution(input, yourScopeResolver)`. * 3. Register the provider in * `gitnexus/src/core/ingestion/emit-providers-registry.ts`. * 4. Add `SupportedLanguages.YourLang` to `MIGRATED_LANGUAGES` in @@ -28,7 +28,7 @@ * change. The generic `scopeResolutionPhase` and the CI parity * workflow auto-discover everything via `MIGRATED_LANGUAGES`. * - * ## EmitProvider vs LanguageProvider + * ## ScopeResolver vs LanguageProvider * * The codebase has two provider contracts. Their lifecycles differ: * @@ -37,7 +37,7 @@ * scopes, interpret imports / typeBindings. ~40 fields covering * both legacy and new pipelines. Consumed by `ScopeExtractor`, * once per file at extract time. - * - `EmitProvider` (this file) is the **emit-side** contract — how + * - `ScopeResolver` (this file) is the **emit-side** contract — how * the resolution pipeline dispatches references to graph edges. * 8 fields total. Consumed by `runScopeResolution`, once per * workspace at resolve time. @@ -51,8 +51,8 @@ * * ## Reference implementation * - * `gitnexus/src/core/ingestion/languages/python/emit/index.ts` — - * `pythonEmitProvider` is the canonical example. Read that file when + * `gitnexus/src/core/ingestion/languages/python/scope-resolver.ts` — + * `pythonScopeResolver` is the canonical example. Read that file when * migrating a new language; this interface lists the fields that * implementation populates. * @@ -81,9 +81,9 @@ import type { SupportedLanguages, SymbolDefinition, } from 'gitnexus-shared'; -import type { KnowledgeGraph } from '../../graph/types.js'; -import type { GraphNodeLookup } from './graph-node-lookup.js'; -import { LanguageProvider } from '../language-provider.js'; +import type { KnowledgeGraph } from '../../../graph/types.js'; +import type { GraphNodeLookup } from '../graph-bridge/node-lookup.js'; +import { LanguageProvider } from '../../language-provider.js'; /** A LinearizeStrategy receives the full ancestor map so C3-style * algorithms (which need to merge each parent's MRO) can implement @@ -95,10 +95,10 @@ export type LinearizeStrategy = ( parentsByDefId: ReadonlyMap, ) => string[]; -/** Result of `EmitProvider.arityCompatibility` — mirrors `RegistryProviders.arityCompatibility`. */ +/** Result of `ScopeResolver.arityCompatibility` — mirrors `RegistryProviders.arityCompatibility`. */ export type ArityVerdict = 'compatible' | 'unknown' | 'incompatible'; -export interface EmitProvider { +export interface ScopeResolver { /** Identity for telemetry + per-language flag check. */ readonly language: SupportedLanguages; diff --git a/gitnexus/src/core/ingestion/emit-core/emit-edge.ts b/gitnexus/src/core/ingestion/scope-resolution/graph-bridge/edges.ts similarity index 90% rename from gitnexus/src/core/ingestion/emit-core/emit-edge.ts rename to gitnexus/src/core/ingestion/scope-resolution/graph-bridge/edges.ts index 0f5fe2fc2..462ce61e1 100644 --- a/gitnexus/src/core/ingestion/emit-core/emit-edge.ts +++ b/gitnexus/src/core/ingestion/scope-resolution/graph-bridge/edges.ts @@ -16,10 +16,10 @@ */ import type { Reference, ScopeId, SymbolDefinition } from 'gitnexus-shared'; -import type { KnowledgeGraph } from '../../graph/types.js'; -import type { ScopeResolutionIndexes } from '../model/scope-resolution-indexes.js'; -import type { GraphNodeLookup } from './graph-node-lookup.js'; -import { resolveCallerGraphId, resolveDefGraphId } from './graph-id.js'; +import type { KnowledgeGraph } from '../../../graph/types.js'; +import type { ScopeResolutionIndexes } from '../../model/scope-resolution-indexes.js'; +import type { GraphNodeLookup } from '../graph-bridge/node-lookup.js'; +import { resolveCallerGraphId, resolveDefGraphId } from '../graph-bridge/ids.js'; /** * Map a `Reference.kind` to a graph edge type. `import-use` is dropped diff --git a/gitnexus/src/core/ingestion/emit-core/graph-id.ts b/gitnexus/src/core/ingestion/scope-resolution/graph-bridge/ids.ts similarity index 93% rename from gitnexus/src/core/ingestion/emit-core/graph-id.ts rename to gitnexus/src/core/ingestion/scope-resolution/graph-bridge/ids.ts index 45afecf58..e3dc44a4f 100644 --- a/gitnexus/src/core/ingestion/emit-core/graph-id.ts +++ b/gitnexus/src/core/ingestion/scope-resolution/graph-bridge/ids.ts @@ -18,9 +18,9 @@ */ import type { ScopeId, SymbolDefinition } from 'gitnexus-shared'; -import type { ScopeResolutionIndexes } from '../model/scope-resolution-indexes.js'; -import { generateId } from '../../../lib/utils.js'; -import { isLinkableLabel, type GraphNodeLookup } from './graph-node-lookup.js'; +import type { ScopeResolutionIndexes } from '../../model/scope-resolution-indexes.js'; +import { generateId } from '../../../../lib/utils.js'; +import { isLinkableLabel, type GraphNodeLookup } from '../graph-bridge/node-lookup.js'; /** Look up a `SymbolDefinition` in the graph node lookup by file+name. */ export function resolveDefGraphId( diff --git a/gitnexus/src/core/ingestion/emit-core/emit-imports.ts b/gitnexus/src/core/ingestion/scope-resolution/graph-bridge/imports-to-edges.ts similarity index 88% rename from gitnexus/src/core/ingestion/emit-core/emit-imports.ts rename to gitnexus/src/core/ingestion/scope-resolution/graph-bridge/imports-to-edges.ts index 8b9539daa..fecf55f3d 100644 --- a/gitnexus/src/core/ingestion/emit-core/emit-imports.ts +++ b/gitnexus/src/core/ingestion/scope-resolution/graph-bridge/imports-to-edges.ts @@ -13,9 +13,9 @@ */ import type { ImportEdge, ScopeId } from 'gitnexus-shared'; -import type { KnowledgeGraph } from '../../graph/types.js'; -import type { ScopeResolutionIndexes } from '../model/scope-resolution-indexes.js'; -import { generateId } from '../../../lib/utils.js'; +import type { KnowledgeGraph } from '../../../graph/types.js'; +import type { ScopeResolutionIndexes } from '../../model/scope-resolution-indexes.js'; +import { generateId } from '../../../../lib/utils.js'; export function emitImportEdges( graph: KnowledgeGraph, diff --git a/gitnexus/src/core/ingestion/emit-core/method-dispatch-bridge.ts b/gitnexus/src/core/ingestion/scope-resolution/graph-bridge/method-dispatch.ts similarity index 100% rename from gitnexus/src/core/ingestion/emit-core/method-dispatch-bridge.ts rename to gitnexus/src/core/ingestion/scope-resolution/graph-bridge/method-dispatch.ts diff --git a/gitnexus/src/core/ingestion/emit-core/graph-node-lookup.ts b/gitnexus/src/core/ingestion/scope-resolution/graph-bridge/node-lookup.ts similarity index 97% rename from gitnexus/src/core/ingestion/emit-core/graph-node-lookup.ts rename to gitnexus/src/core/ingestion/scope-resolution/graph-bridge/node-lookup.ts index f84733a5b..2b50e6fd4 100644 --- a/gitnexus/src/core/ingestion/emit-core/graph-node-lookup.ts +++ b/gitnexus/src/core/ingestion/scope-resolution/graph-bridge/node-lookup.ts @@ -13,7 +13,7 @@ */ import type { NodeLabel } from 'gitnexus-shared'; -import type { KnowledgeGraph } from '../../graph/types.js'; +import type { KnowledgeGraph } from '../../../graph/types.js'; export type GraphNodeLookup = ReadonlyMap; diff --git a/gitnexus/src/core/ingestion/emit-core/emit-references.ts b/gitnexus/src/core/ingestion/scope-resolution/graph-bridge/references-to-edges.ts similarity index 89% rename from gitnexus/src/core/ingestion/emit-core/emit-references.ts rename to gitnexus/src/core/ingestion/scope-resolution/graph-bridge/references-to-edges.ts index d64111fa2..1331f204b 100644 --- a/gitnexus/src/core/ingestion/emit-core/emit-references.ts +++ b/gitnexus/src/core/ingestion/scope-resolution/graph-bridge/references-to-edges.ts @@ -19,11 +19,11 @@ */ import type { Reference, ScopeId } from 'gitnexus-shared'; -import type { KnowledgeGraph } from '../../graph/types.js'; -import type { ScopeResolutionIndexes } from '../model/scope-resolution-indexes.js'; -import { resolveCallerGraphId, resolveDefGraphId } from './graph-id.js'; -import { mapReferenceKindToEdgeType } from './emit-edge.js'; -import type { GraphNodeLookup } from './graph-node-lookup.js'; +import type { KnowledgeGraph } from '../../../graph/types.js'; +import type { ScopeResolutionIndexes } from '../../model/scope-resolution-indexes.js'; +import { resolveCallerGraphId, resolveDefGraphId } from '../graph-bridge/ids.js'; +import { mapReferenceKindToEdgeType } from '../graph-bridge/edges.js'; +import type { GraphNodeLookup } from '../graph-bridge/node-lookup.js'; /** * Optional opaque skip key — providers may pre-emit edges (e.g. via diff --git a/gitnexus/src/core/ingestion/scope-resolution/index.ts b/gitnexus/src/core/ingestion/scope-resolution/index.ts new file mode 100644 index 000000000..7716bceb9 --- /dev/null +++ b/gitnexus/src/core/ingestion/scope-resolution/index.ts @@ -0,0 +1,76 @@ +/** + * `scope-resolution/` — registry-primary call/reference resolution. + * + * Public surface, grouped by concern. New language migrations should + * read `contract/scope-resolver.ts` first — it lists every hook the + * generic pipeline needs from a per-language adapter. + * + * Folder layout: + * - `contract/` — `ScopeResolver` interface + shared types + * - `pipeline/` — orchestrator, registry, pipeline-phase wrapper + * - `passes/` — reference-resolution passes (receiver-bound, + * free-call fallback, compound-receiver, MRO, + * cross-file return-type propagation) + * - `graph-bridge/` — CLI-local layer that translates resolved + * references into `KnowledgeGraph` edges + * - `scope/` — generic scope-chain walkers + namespace targets + * + * The `scope/` and `passes/` content is pure logic with no graph + * dependency; if a future consumer (gitnexus-web) needs the resolver + * without the graph, those two folders are the natural promotion path + * to `gitnexus-shared/`. + */ + +// ── Contract ────────────────────────────────────────────────────────────── +export type { ArityVerdict, LinearizeStrategy, ScopeResolver } from './contract/scope-resolver.js'; + +// ── Pipeline ────────────────────────────────────────────────────────────── +export { + runScopeResolution, + type RunScopeResolutionInput, + type RunScopeResolutionStats, +} from './pipeline/run.js'; +export { SCOPE_RESOLVERS, getScopeResolver } from './pipeline/registry.js'; + +// ── Passes ──────────────────────────────────────────────────────────────── +export { emitReceiverBoundCalls } from './passes/receiver-bound-calls.js'; +export { emitFreeCallFallback } from './passes/free-call-fallback.js'; +export { + matchingOpenParen, + resolveCompoundReceiverClass, + type ResolveCompoundReceiverOptions, +} from './passes/compound-receiver.js'; +export { + followChainPostFinalize, + propagateImportedReturnTypes, +} from './passes/imported-return-types.js'; +export { buildMro, defaultLinearize } from './passes/mro.js'; + +// ── Graph bridge (CLI-local) ────────────────────────────────────────────── +export { + buildGraphNodeLookup, + isLinkableLabel, + type GraphNodeLookup, +} from './graph-bridge/node-lookup.js'; +export { + resolveCallerGraphId, + resolveDefGraphId, + simpleQualifiedName, +} from './graph-bridge/ids.js'; +export { mapReferenceKindToEdgeType, tryEmitEdge } from './graph-bridge/edges.js'; +export { emitReferencesViaLookup } from './graph-bridge/references-to-edges.js'; +export { emitImportEdges } from './graph-bridge/imports-to-edges.js'; +export { buildPopulatedMethodDispatch } from './graph-bridge/method-dispatch.js'; + +// ── Scope walkers ───────────────────────────────────────────────────────── +export { + findReceiverTypeBinding, + findClassBindingInScope, + findCallableBindingInScope, + findEnclosingClassDef, + findExportedDefByName, + findOwnedMember, + findExportedDef, + populateClassOwnedMembers, +} from './scope/walkers.js'; +export { collectNamespaceTargets } from './scope/namespace-targets.js'; diff --git a/gitnexus/src/core/ingestion/emit-core/emit-compound-receiver.ts b/gitnexus/src/core/ingestion/scope-resolution/passes/compound-receiver.ts similarity index 97% rename from gitnexus/src/core/ingestion/emit-core/emit-compound-receiver.ts rename to gitnexus/src/core/ingestion/scope-resolution/passes/compound-receiver.ts index 2813ae323..a88fb274e 100644 --- a/gitnexus/src/core/ingestion/emit-core/emit-compound-receiver.ts +++ b/gitnexus/src/core/ingestion/scope-resolution/passes/compound-receiver.ts @@ -13,7 +13,7 @@ * receiver class has no `methodName`, walk its fields and try the * lookup on each field's type. Useful for dynamically-typed languages * (Python). Strictly-typed languages should pass - * `fieldFallbackOnMethodLookup: false` via `EmitProvider`. + * `fieldFallbackOnMethodLookup: false` via `ScopeResolver`. * * Generic for any C-family language (`.` member access, `()` call * syntax). Languages with non-C-family syntax (Ruby blocks, COBOL) @@ -22,12 +22,12 @@ import type { ParsedFile, ScopeId, SymbolDefinition, TypeRef } from 'gitnexus-shared'; import type { Scope } from 'gitnexus-shared'; -import type { ScopeResolutionIndexes } from '../model/scope-resolution-indexes.js'; +import type { ScopeResolutionIndexes } from '../../model/scope-resolution-indexes.js'; import { findClassBindingInScope, findExportedDefByName, findReceiverTypeBinding, -} from './scope-walkers.js'; +} from '../scope/walkers.js'; /** Max depth for compound-receiver chain resolution (`a().b().c().d()`). * Practical code rarely exceeds 3-4 hops; the cap prevents diff --git a/gitnexus/src/core/ingestion/emit-core/emit-free-call.ts b/gitnexus/src/core/ingestion/scope-resolution/passes/free-call-fallback.ts similarity index 85% rename from gitnexus/src/core/ingestion/emit-core/emit-free-call.ts rename to gitnexus/src/core/ingestion/scope-resolution/passes/free-call-fallback.ts index e56f5602a..c35d2e3f3 100644 --- a/gitnexus/src/core/ingestion/emit-core/emit-free-call.ts +++ b/gitnexus/src/core/ingestion/scope-resolution/passes/free-call-fallback.ts @@ -13,16 +13,16 @@ * dedup semantics (what the `default-params` / `variadic` / `overload` * fixtures expect). Member calls keep position-based dedup elsewhere. * - * Generic; promoted from `python-scope-emit.ts` per the emit-core + * Generic; promoted from `languages/python/scope-resolver.ts` per the scope-resolution * generalization plan. */ import type { ParsedFile, Reference, ScopeId } from 'gitnexus-shared'; -import type { KnowledgeGraph } from '../../graph/types.js'; -import type { ScopeResolutionIndexes } from '../model/scope-resolution-indexes.js'; -import type { GraphNodeLookup } from './graph-node-lookup.js'; -import { resolveCallerGraphId, resolveDefGraphId } from './graph-id.js'; -import { findCallableBindingInScope } from './scope-walkers.js'; +import type { KnowledgeGraph } from '../../../graph/types.js'; +import type { ScopeResolutionIndexes } from '../../model/scope-resolution-indexes.js'; +import type { GraphNodeLookup } from '../graph-bridge/node-lookup.js'; +import { resolveCallerGraphId, resolveDefGraphId } from '../graph-bridge/ids.js'; +import { findCallableBindingInScope } from '../scope/walkers.js'; export function emitFreeCallFallback( graph: KnowledgeGraph, diff --git a/gitnexus/src/core/ingestion/emit-core/propagate-return-types.ts b/gitnexus/src/core/ingestion/scope-resolution/passes/imported-return-types.ts similarity index 95% rename from gitnexus/src/core/ingestion/emit-core/propagate-return-types.ts rename to gitnexus/src/core/ingestion/scope-resolution/passes/imported-return-types.ts index 45b0c7df7..c58c0933c 100644 --- a/gitnexus/src/core/ingestion/emit-core/propagate-return-types.ts +++ b/gitnexus/src/core/ingestion/scope-resolution/passes/imported-return-types.ts @@ -2,7 +2,7 @@ * Cross-file return-type typeBinding propagation + post-finalize * chain re-follow. * - * **Why this lives in emit-core:** the algorithm is language-agnostic. + * **Why this lives in scope-resolution:** the algorithm is language-agnostic. * Every language with cross-file callable imports needs the same * mirror-binding step, otherwise `u = f(); u.save()` only resolves * when `f` is in the same file as the call. @@ -14,12 +14,12 @@ * populated) but BEFORE `resolveReferenceSites` (so resolution * sees the propagated types). * - * Generic; promoted from `python-scope-emit.ts` per the emit-core + * Generic; promoted from `languages/python/scope-resolver.ts` per the scope-resolution * generalization plan. */ import type { ParsedFile, Scope, ScopeId, TypeRef } from 'gitnexus-shared'; -import type { ScopeResolutionIndexes } from '../model/scope-resolution-indexes.js'; +import type { ScopeResolutionIndexes } from '../../model/scope-resolution-indexes.js'; /** Max chain depth for the post-finalize re-follow. */ const RECHAIN_MAX_DEPTH = 8; diff --git a/gitnexus/src/core/ingestion/emit-core/build-mro.ts b/gitnexus/src/core/ingestion/scope-resolution/passes/mro.ts similarity index 93% rename from gitnexus/src/core/ingestion/emit-core/build-mro.ts rename to gitnexus/src/core/ingestion/scope-resolution/passes/mro.ts index 5df478c14..fac7ad5cc 100644 --- a/gitnexus/src/core/ingestion/emit-core/build-mro.ts +++ b/gitnexus/src/core/ingestion/scope-resolution/passes/mro.ts @@ -20,10 +20,10 @@ */ import type { ParsedFile } from 'gitnexus-shared'; -import type { KnowledgeGraph } from '../../graph/types.js'; -import type { GraphNodeLookup } from './graph-node-lookup.js'; -import type { LinearizeStrategy } from './emit-provider.js'; -import { resolveDefGraphId } from './graph-id.js'; +import type { KnowledgeGraph } from '../../../graph/types.js'; +import type { GraphNodeLookup } from '../graph-bridge/node-lookup.js'; +import type { LinearizeStrategy } from '../contract/scope-resolver.js'; +import { resolveDefGraphId } from '../graph-bridge/ids.js'; /** * Build an MRO map keyed by scope-resolution Class `DefId`. diff --git a/gitnexus/src/core/ingestion/emit-core/emit-receiver-bound.ts b/gitnexus/src/core/ingestion/scope-resolution/passes/receiver-bound-calls.ts similarity index 94% rename from gitnexus/src/core/ingestion/emit-core/emit-receiver-bound.ts rename to gitnexus/src/core/ingestion/scope-resolution/passes/receiver-bound-calls.ts index 5ff7dcdcb..207d63b6b 100644 --- a/gitnexus/src/core/ingestion/emit-core/emit-receiver-bound.ts +++ b/gitnexus/src/core/ingestion/scope-resolution/passes/receiver-bound-calls.ts @@ -1,6 +1,6 @@ /** * Receiver-bound CALLS / ACCESSES emit pass — generic 7-case - * dispatcher consuming `EmitProvider` for the language-specific bits + * dispatcher consuming `ScopeResolver` for the language-specific bits * (super recognizer, field-fallback toggle). * * **Contract Invariant I4 — case order is load-bearing.** The cases @@ -31,26 +31,26 @@ import type { ParsedFile, SymbolDefinition } from 'gitnexus-shared'; import type { Scope } from 'gitnexus-shared'; -import type { KnowledgeGraph } from '../../graph/types.js'; -import type { ScopeResolutionIndexes } from '../model/scope-resolution-indexes.js'; -import type { EmitProvider } from './emit-provider.js'; -import type { GraphNodeLookup } from './graph-node-lookup.js'; -import { collectNamespaceTargets } from './namespace-targets.js'; +import type { KnowledgeGraph } from '../../../graph/types.js'; +import type { ScopeResolutionIndexes } from '../../model/scope-resolution-indexes.js'; +import type { ScopeResolver } from '../contract/scope-resolver.js'; +import type { GraphNodeLookup } from '../graph-bridge/node-lookup.js'; +import { collectNamespaceTargets } from '../scope/namespace-targets.js'; import { findClassBindingInScope, findEnclosingClassDef, findExportedDef, findOwnedMember, findReceiverTypeBinding, -} from './scope-walkers.js'; -import { tryEmitEdge } from './emit-edge.js'; -import { resolveCompoundReceiverClass } from './emit-compound-receiver.js'; +} from '../scope/walkers.js'; +import { tryEmitEdge } from '../graph-bridge/edges.js'; +import { resolveCompoundReceiverClass } from '../passes/compound-receiver.js'; -/** Subset of `EmitProvider` consumed by this pass. Accepting the +/** Subset of `ScopeResolver` consumed by this pass. Accepting the * subset rather than the full provider keeps tests and partial * refactors lighter — callers only need to populate what we read. */ export type ReceiverBoundProviderSubset = Pick< - EmitProvider, + ScopeResolver, 'isSuperReceiver' | 'fieldFallbackOnMethodLookup' >; diff --git a/gitnexus/src/core/ingestion/pipeline-phases/scope-resolution.ts b/gitnexus/src/core/ingestion/scope-resolution/pipeline/phase.ts similarity index 88% rename from gitnexus/src/core/ingestion/pipeline-phases/scope-resolution.ts rename to gitnexus/src/core/ingestion/scope-resolution/pipeline/phase.ts index a64ada497..5add29ba3 100644 --- a/gitnexus/src/core/ingestion/pipeline-phases/scope-resolution.ts +++ b/gitnexus/src/core/ingestion/scope-resolution/pipeline/phase.ts @@ -4,7 +4,7 @@ * Generic registry-primary resolution phase (RFC #909 Ring 4). * * For every language in `MIGRATED_LANGUAGES` (per-language flag set) - * whose provider is registered in `EMIT_PROVIDERS`: + * whose provider is registered in `SCOPE_RESOLVERS`: * 1. Filter scanned files by language extension. * 2. Read file contents. * 3. Drive the scope-based pipeline end-to-end via the generic @@ -16,7 +16,7 @@ * primary, so we don't double-emit edges from both code paths. * * Adding a language is two changes: - * - Implement `EmitProvider` in `languages//emit/index.ts` + * - Implement `ScopeResolver` in `languages//emit/index.ts` * and register it in `emit-providers-registry.ts`. * - Add the language to `MIGRATED_LANGUAGES` in * `registry-primary-flag.ts`. @@ -27,15 +27,15 @@ * @writes graph (IMPORTS, CALLS, ACCESSES, INHERITS, USES) */ -import type { PipelinePhase, PipelineContext, PhaseResult } from './types.js'; -import { getPhaseOutput } from './types.js'; -import type { StructureOutput } from './structure.js'; -import { isRegistryPrimary } from '../registry-primary-flag.js'; +import type { PipelinePhase, PipelineContext, PhaseResult } from '../../pipeline-phases/types.js'; +import { getPhaseOutput } from '../../pipeline-phases/types.js'; +import type { StructureOutput } from '../../pipeline-phases/structure.js'; +import { isRegistryPrimary } from '../../registry-primary-flag.js'; import { SupportedLanguages, getLanguageFromFilename } from 'gitnexus-shared'; -import { readFileContents } from '../filesystem-walker.js'; -import { runScopeResolution } from '../emit-core/index.js'; -import { EMIT_PROVIDERS } from '../emit-providers-registry.js'; -import { isDev } from '../utils/env.js'; +import { readFileContents } from '../../filesystem-walker.js'; +import { runScopeResolution } from './run.js'; +import { SCOPE_RESOLVERS } from './registry.js'; +import { isDev } from '../../utils/env.js'; export interface ScopeResolutionOutput { /** True when at least one language ran. */ @@ -92,7 +92,7 @@ export const scopeResolutionPhase: PipelinePhase = { } >(); - for (const [lang, provider] of EMIT_PROVIDERS) { + for (const [lang, provider] of SCOPE_RESOLVERS) { if (!isRegistryPrimary(lang)) continue; const langFiles = scannedFiles.filter((f) => getLanguageFromFilename(f.path) === lang); diff --git a/gitnexus/src/core/ingestion/scope-resolution/pipeline/registry.ts b/gitnexus/src/core/ingestion/scope-resolution/pipeline/registry.ts new file mode 100644 index 000000000..2f6093b6c --- /dev/null +++ b/gitnexus/src/core/ingestion/scope-resolution/pipeline/registry.ts @@ -0,0 +1,27 @@ +/** + * Per-language `ScopeResolver` registry — the lookup the generic + * `scopeResolutionPhase` uses to pick the right resolver for each + * migrated language. + * + * Adding a language is two lines: implement a `ScopeResolver` in + * `languages//scope-resolver.ts` and register it here. The + * phase picks it up automatically — no workflow changes, no + * per-language pipeline phase file. + */ + +import { SupportedLanguages } from 'gitnexus-shared'; +import type { ScopeResolver } from '../contract/scope-resolver.js'; +import { pythonScopeResolver } from '../../languages/python/scope-resolver.js'; + +/** Map of `SupportedLanguages` → `ScopeResolver`. The phase iterates + * this map intersected with `MIGRATED_LANGUAGES` (the per-language + * flag set) so adding a resolver here without flipping the flag is + * safe — the resolver sits idle until the language is migrated. */ +export const SCOPE_RESOLVERS: ReadonlyMap = new Map< + SupportedLanguages, + ScopeResolver +>([[SupportedLanguages.Python, pythonScopeResolver]]); + +export function getScopeResolver(lang: SupportedLanguages): ScopeResolver | undefined { + return SCOPE_RESOLVERS.get(lang); +} diff --git a/gitnexus/src/core/ingestion/emit-core/orchestrator.ts b/gitnexus/src/core/ingestion/scope-resolution/pipeline/run.ts similarity index 82% rename from gitnexus/src/core/ingestion/emit-core/orchestrator.ts rename to gitnexus/src/core/ingestion/scope-resolution/pipeline/run.ts index db510e0c7..c8e0894c6 100644 --- a/gitnexus/src/core/ingestion/emit-core/orchestrator.ts +++ b/gitnexus/src/core/ingestion/scope-resolution/pipeline/run.ts @@ -17,25 +17,25 @@ * KnowledgeGraph * * Per-language entry points (e.g. `runPythonScopeResolution` in - * `languages/python/emit/index.ts`) construct an `EmitProvider` and + * `languages/python/scope-resolver.ts`) construct an `ScopeResolver` and * delegate here. * * Plan: `docs/plans/2026-04-20-001-refactor-emit-pipeline-generalization-plan.md`. */ import type { ParsedFile, RegistryProviders } from 'gitnexus-shared'; -import type { KnowledgeGraph } from '../../graph/types.js'; -import { extractParsedFile } from '../scope-extractor-bridge.js'; -import { finalizeScopeModel } from '../finalize-orchestrator.js'; -import { resolveReferenceSites, type ResolveStats } from '../resolve-references.js'; -import { buildGraphNodeLookup } from './graph-node-lookup.js'; -import { buildPopulatedMethodDispatch } from './method-dispatch-bridge.js'; -import { propagateImportedReturnTypes } from './propagate-return-types.js'; -import { emitReceiverBoundCalls } from './emit-receiver-bound.js'; -import { emitFreeCallFallback } from './emit-free-call.js'; -import { emitReferencesViaLookup } from './emit-references.js'; -import { emitImportEdges } from './emit-imports.js'; -import type { EmitProvider } from './emit-provider.js'; +import type { KnowledgeGraph } from '../../../graph/types.js'; +import { extractParsedFile } from '../../scope-extractor-bridge.js'; +import { finalizeScopeModel } from '../../finalize-orchestrator.js'; +import { resolveReferenceSites, type ResolveStats } from '../../resolve-references.js'; +import { buildGraphNodeLookup } from '../graph-bridge/node-lookup.js'; +import { buildPopulatedMethodDispatch } from '../graph-bridge/method-dispatch.js'; +import { propagateImportedReturnTypes } from '../passes/imported-return-types.js'; +import { emitReceiverBoundCalls } from '../passes/receiver-bound-calls.js'; +import { emitFreeCallFallback } from '../passes/free-call-fallback.js'; +import { emitReferencesViaLookup } from '../graph-bridge/references-to-edges.js'; +import { emitImportEdges } from '../graph-bridge/imports-to-edges.js'; +import type { ScopeResolver } from '../contract/scope-resolver.js'; export interface RunScopeResolutionInput { readonly graph: KnowledgeGraph; @@ -54,7 +54,7 @@ export interface RunScopeResolutionStats { export function runScopeResolution( input: RunScopeResolutionInput, - provider: EmitProvider, + provider: ScopeResolver, ): RunScopeResolutionStats { const { graph, files } = input; const onWarn = input.onWarn ?? (() => {}); diff --git a/gitnexus/src/core/ingestion/emit-core/namespace-targets.ts b/gitnexus/src/core/ingestion/scope-resolution/scope/namespace-targets.ts similarity index 94% rename from gitnexus/src/core/ingestion/emit-core/namespace-targets.ts rename to gitnexus/src/core/ingestion/scope-resolution/scope/namespace-targets.ts index 866a2e40f..531a106e1 100644 --- a/gitnexus/src/core/ingestion/emit-core/namespace-targets.ts +++ b/gitnexus/src/core/ingestion/scope-resolution/scope/namespace-targets.ts @@ -20,7 +20,7 @@ */ import type { ParsedFile } from 'gitnexus-shared'; -import type { ScopeResolutionIndexes } from '../model/scope-resolution-indexes.js'; +import type { ScopeResolutionIndexes } from '../../model/scope-resolution-indexes.js'; export function collectNamespaceTargets( parsed: ParsedFile, diff --git a/gitnexus/src/core/ingestion/emit-core/scope-walkers.ts b/gitnexus/src/core/ingestion/scope-resolution/scope/walkers.ts similarity index 98% rename from gitnexus/src/core/ingestion/emit-core/scope-walkers.ts rename to gitnexus/src/core/ingestion/scope-resolution/scope/walkers.ts index e57c2f0dc..d4b214611 100644 --- a/gitnexus/src/core/ingestion/emit-core/scope-walkers.ts +++ b/gitnexus/src/core/ingestion/scope-resolution/scope/walkers.ts @@ -20,8 +20,8 @@ */ import type { ParsedFile, ScopeId, SymbolDefinition, TypeRef } from 'gitnexus-shared'; -import type { ScopeResolutionIndexes } from '../model/scope-resolution-indexes.js'; -import { simpleQualifiedName } from './graph-id.js'; +import type { ScopeResolutionIndexes } from '../../model/scope-resolution-indexes.js'; +import { simpleQualifiedName } from '../graph-bridge/ids.js'; /** * Walk the scope chain from `startScope` looking for a typeBinding