refactor(shared): move MixedChainStep into gitnexus-shared

U3. The shared package owns the ScopeExtractor output contract, and a receiver
chain is about to become part of it, so the type moves to sit beside
`ReferenceSite` — the interface that will carry it.

Type-only move. `extractMixedChain` stays in the analyzer: it walks a
tree-sitter AST, so it cannot follow. `MAX_CHAIN_DEPTH` stays with it for the
same reason — nothing shared needs the bound yet, and moving it now would be
moving it on speculation.

`call-analysis.ts` re-exports the type so its existing importers keep a single
import site. The re-export is `import type` + `export type` rather than a bare
`export type { X } from`, which creates no local binding and left the file's own
two uses of the name unresolved.

Verified: `tsc --noEmit` clean in both packages, and the receiver-resolution
gate green end to end.

(The unit suite has seven failures on this tree, all subprocess-spawning CLI
tests timing out. Three pass in isolation — load flake. The fourth,
`skip-git-cli.test.ts`, fails harder on untouched `main` in this sandbox — six
failures there against four here — so it is environmental and predates this
branch.)
This commit is contained in:
Gergo Magyar 2026-07-30 08:23:53 +00:00
parent caf6b6a321
commit 975dedb6d2
3 changed files with 31 additions and 3 deletions

View file

@ -83,7 +83,12 @@ export type { ResolveTypeRefContext } from './scope-resolution/resolve-type-ref.
// ScopeExtractor output contracts (RFC §3.2 Phase 1; Ring 2 PKG #919)
export type { ParsedFile } from './scope-resolution/parsed-file.js';
export type { ReferenceSite, ReferenceKind, CallForm } from './scope-resolution/reference-site.js';
export type {
ReferenceSite,
ReferenceKind,
CallForm,
MixedChainStep,
} from './scope-resolution/reference-site.js';
export type {
CallableFlowOperand,
CallableFlowExpectedSignature,

View file

@ -124,3 +124,18 @@ export interface ReferenceSite {
*/
readonly argumentTypeClasses?: readonly ParameterTypeClass[];
}
/**
* One step in a mixed receiver chain — the decoded form of a receiver that is
* itself an expression rather than a bare name.
*
* For `svc.getUser().address.save()`, the receiver of `save` decodes to
* `[{ kind: 'call', name: 'getUser' }, { kind: 'field', name: 'address' }]`
* over a base receiver of `svc`.
*
* Lives here rather than beside its producer because it is part of the
* ScopeExtractor output contract that this package owns: the producer
* (`extractMixedChain`) walks a tree-sitter AST and so must stay in the
* analyzer, but the shape it yields crosses into resolution.
*/
export type MixedChainStep = { kind: 'field' | 'call'; name: string };

View file

@ -1,3 +1,5 @@
import type { MixedChainStep } from 'gitnexus-shared';
import type { SyntaxNode } from './ast-helpers.js';
import { CALL_ARGUMENT_LIST_TYPES } from './ast-helpers.js';
@ -362,8 +364,14 @@ const FIELD_ACCESS_NODE_TYPES = new Set([
'member_binding_expression', // C# null-conditional (user?.Address)
]);
/** One step in a mixed receiver chain. */
export type MixedChainStep = { kind: 'field' | 'call'; name: string };
/**
* One step in a mixed receiver chain.
*
* Owned by `gitnexus-shared` — it is part of the ScopeExtractor output
* contract, and resolution consumes it. Re-exported here so the producer's
* existing importers keep a single import site.
*/
export type { MixedChainStep };
/**
* Walk a receiver AST node that is itself a call expression, accumulating the