mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-09 03:17:54 +00:00
refactor(scope-resolution): rename emit-core/ → scope-resolution/, EmitProvider → ScopeResolver
Reorganizes the registry-primary resolution layer for clarity and
contributor onboarding. Driven by feedback that "emit" was triple-
overloaded (graph-edge emission + tree-sitter capture extraction +
the provider name itself), and the flat 16-file emit-core/ folder
mixed five concerns.
External research (rust-analyzer hir-def/nameres, Pyright analyzer/,
TypeScript binder/checker, Roslyn Binder, IntelliJ Resolver, swc
semantic/, biome semantic/, semgrep naming/, JDT Binding, clangd
Sema) consistently uses **the phase name** for this layer, never an
output verb. "Scope resolution" matches our pipeline-phase name, the
plan, and the RFC.
## Folder rename
emit-core/ → scope-resolution/
├── (16 flat files) → ├── contract/scope-resolver.ts
├── pipeline/{run,registry,phase}.ts
├── passes/{receiver-bound-calls,
│ free-call-fallback,
│ compound-receiver,
│ imported-return-types,
│ mro}.ts
├── graph-bridge/{node-lookup,ids,
│ edges,references-to-edges,
│ imports-to-edges,
│ method-dispatch}.ts
└── scope/{walkers,namespace-targets}.ts
Each subfolder maps to one concern a new contributor needs to find:
*the contract I implement / the runner that calls me / the helpers I
reuse / the graph layer I shouldn't touch / the scope walkers*.
## Symbol renames
EmitProvider → ScopeResolver
pythonEmitProvider → pythonScopeResolver
runPythonScopeResolution → resolvePythonScope
EMIT_PROVIDERS → SCOPE_RESOLVERS
getEmitProvider → getScopeResolver
RunPythonScopeResolution{Input,Stats} → ResolvePythonScope{Input,Stats}
## File renames (per-language)
languages/python/emit/index.ts → languages/python/scope-resolver.ts
languages/python/emit-captures.ts → languages/python/captures.ts
(kills the parse-side "emit" collision)
## Mechanics
- Used `git mv` for all files so blame history is preserved.
- Updated ~30 import lines across 18 files plus the pipeline-phases
barrel and pipeline.ts.
- Updated JSDoc cross-references throughout to match the new vocabulary.
Verification:
- REGISTRY_PRIMARY_PYTHON=0 (legacy): 191/191.
- REGISTRY_PRIMARY_PYTHON=1 (registry): 191/191.
- Default (post MIGRATED_LANGUAGES flip): 191/191.
- tsc --noEmit clean.
Migration cookbook in `scope-resolution/contract/scope-resolver.ts`
JSDoc points the next-language porter at all the new names and
folder locations.
This commit is contained in:
parent
cbc941461c
commit
c3d0f0ae92
25 changed files with 207 additions and 186 deletions
1
.claude/scheduled_tasks.lock
Normal file
1
.claude/scheduled_tasks.lock
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"sessionId":"67109eaf-0d84-41ff-9cdf-1cd9715e8283","pid":2680,"acquiredAt":1776588137183}
|
||||
|
|
@ -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/<lang>/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';
|
||||
|
|
@ -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/<lang>/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<SupportedLanguages, EmitProvider> = new Map<
|
||||
SupportedLanguages,
|
||||
EmitProvider
|
||||
>([[SupportedLanguages.Python, pythonEmitProvider]]);
|
||||
|
||||
export function getEmitProvider(lang: SupportedLanguages): EmitProvider | undefined {
|
||||
return EMIT_PROVIDERS.get(lang);
|
||||
}
|
||||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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/<lang>/emit/index.ts`.
|
||||
* 1. Implement `ScopeResolver` in
|
||||
* `gitnexus/src/core/ingestion/languages/<lang>/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, readonly string[]>,
|
||||
) => 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;
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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(
|
||||
|
|
@ -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,
|
||||
|
|
@ -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<string, string>;
|
||||
|
||||
|
|
@ -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
|
||||
76
gitnexus/src/core/ingestion/scope-resolution/index.ts
Normal file
76
gitnexus/src/core/ingestion/scope-resolution/index.ts
Normal file
|
|
@ -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';
|
||||
|
|
@ -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
|
||||
|
|
@ -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,
|
||||
|
|
@ -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;
|
||||
|
|
@ -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`.
|
||||
|
|
@ -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'
|
||||
>;
|
||||
|
||||
|
|
@ -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/<lang>/emit/index.ts`
|
||||
* - Implement `ScopeResolver` in `languages/<lang>/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<ScopeResolutionOutput> = {
|
|||
}
|
||||
>();
|
||||
|
||||
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);
|
||||
|
|
@ -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/<lang>/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<SupportedLanguages, ScopeResolver> = new Map<
|
||||
SupportedLanguages,
|
||||
ScopeResolver
|
||||
>([[SupportedLanguages.Python, pythonScopeResolver]]);
|
||||
|
||||
export function getScopeResolver(lang: SupportedLanguages): ScopeResolver | undefined {
|
||||
return SCOPE_RESOLVERS.get(lang);
|
||||
}
|
||||
|
|
@ -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 ?? (() => {});
|
||||
|
|
@ -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,
|
||||
|
|
@ -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
|
||||
Loading…
Add table
Reference in a new issue