/** * Per-file receiver type registries (change: shrink-receiver-resolution-boundary). * * The call graph resolves `this.m()` / `self.m()` by walking the enclosing class chain. The one * intra-object shape it cannot see at all is the CHAINED receiver — `this..()` / * `self..()`. The call query only ever captured an `(identifier)`, `(this)` or * `(super)` receiver, so a chained receiver matched no alternative: it produced no raw edge, no * resolved edge, and no `external::` leaf. It was the last call shape that was *silently* absent * rather than disclosed — `exception-flow.ts` classified it `other` and promised it resolved "to an * internal edge or an `external::obj.x` edge", which was not true for this shape. * * This module records the deterministic facts needed to type such a receiver: a class field's * declared type, and — where a field is initialized from a call to a locally-declared function — * that function's declared return type. Local *variable* types are already covered by * `type-inference-engine.ts`; this is the field/return dimension it never had. * * Four rules are load-bearing: * * 1. **Declared types only, never inferred shapes.** A field types the receiver when the source * SAYS its type (an annotation, a `new T()`, a call to a local function with a declared return * type). Nothing is guessed from naming, usage, or assignment flow. * 2. **Conflict refuses.** One `Class.field` carrying two different types anywhere in the file is * dropped outright — the receiver stays a disclosed boundary rather than binding to whichever * declaration parsed first. * 3. **No second parse.** Facts are collected from the tree Pass 1 already owns, through the same * query runner `collectClassRelationshipFacts` uses, and are plain data so they survive the * extraction-worker structured clone and the Pass-1 fact cache JSON. * 4. **Fail-soft.** A grammar without the queried node types yields nothing (the runner already * swallows query errors), which is the same deterministic answer on every lane. */ /** Languages whose extractors contribute receiver-field facts. Authoritative source for the * `receiverResolution` capability flag in the declarative language-support registry; a behavioral * test asserts a fixture in each member yields facts and a non-member yields none. */ export declare const RECEIVER_REGISTRY_LANGUAGES: ReadonlySet; /** * One `Class.field → Type` observation. Plain data: it crosses the worker structured-clone and the * fact-cache JSON boundary exactly like {@link ClassRelationshipFact}. Observations are appended, * never merged, so a conflict stays visible to the builder, which refuses it. */ export interface ReceiverFieldFact { /** Enclosing class of the field declaration. */ className: string; /** Field name as written (`repo` in `this.repo`). */ field: string; /** Declared type name. Always capitalized — see {@link isTypeName}. */ type: string; } /** Minimal structural view of a tree-sitter node — the subset this module walks. */ interface RegistryNode { type: string; text: string; parent: RegistryNode | null; childForFieldName(name: string): RegistryNode | null; } /** Minimal structural view of a tree-sitter query match. */ interface RegistryMatch { captures: Array<{ name: string; node: RegistryNode; }>; } /** * Collect `Class.field → Type` facts while Pass 1 still owns the syntax tree. * * `runQuery` is the same fail-soft runner {@link collectClassRelationshipFacts} uses: a query the * installed grammar rejects returns no matches instead of throwing. */ export declare function collectReceiverFieldFacts(language: string, runQuery: (source: string) => RegistryMatch[]): ReceiverFieldFact[]; /** * Maximum facts retained per file. A generated file — 2,000 classes of 20 annotated fields each — * would otherwise serialize a 2 MB `pass1_facts` row and hold it for the whole build, crossing the * extraction-worker structured clone on the way. Real code is nowhere near this (60 facts across * this repository's 997 TypeScript files), so the cap is a hazard bound, not a working limit. * Truncation costs recall on the overflow, never correctness: an absent fact refuses the receiver, * which is the registry's own contract. */ export declare const RECEIVER_FIELD_FACT_CAP = 2000; /** Deduplicate and order facts so two analyses of an unchanged file emit byte-identical payloads. */ export declare function finalizeReceiverFieldFacts(facts: ReceiverFieldFact[]): ReceiverFieldFact[]; /** * The resolved per-repository field registry: `filePath::Class.field → type`, with every * conflicting observation removed. Built once in Pass 2 from the collected facts. */ export type ReceiverFieldRegistry = ReadonlyMap; /** Registry key for one field. Exported so tests and callers agree on the shape. */ export declare function receiverFieldKey(filePath: string, className: string, field: string): string; /** * Fold per-file facts into the registry, dropping any `Class.field` observed with more than one * type. Refusal is per key, so one conflicted field never suppresses its siblings. */ export declare function buildReceiverFieldRegistry(factsByFile: Iterable): ReceiverFieldRegistry; export {}; //# sourceMappingURL=receiver-registry.d.ts.map