/** * Linker data structures for semantic cross-shard resolution (plan #2, Phase 1). * * Two pure "symbol tables" the boundary resolver (Phase 2) links against — * derivable entirely from data already present in a merged catalog plus the * resolved `Shard[]`: * * 1. {@link ExportIndex} — per-package map of exported function name → * occurrences (`visibility === 'exported'`). The export symbol table: * "given a package and a callee name, which exported occurrences match?" * 2. {@link PackageManifestIndex} — package `name` → its on-disk manifest * (`name`, dir, `exports` map). Lets {@link resolveSpecifierToPackage} * turn a bare import specifier (`@scope/pkg[/subpath]`) into the package * group the {@link ExportIndex} is keyed by. * * Engine-layer and language-agnostic: no TypeScript parser, no AST. The only * effect is reading each package's `package.json` from disk in * {@link buildPackageManifestIndex}; everything else is plain map/path/JSON * math. These structures are UNUSED by resolution logic in Phase 1 — Phase 2 * wires them into `resolveCrossBoundaryCalls`. * * Package-key alignment (the linchpin Phase 2 depends on): the boundary * resolver buckets occurrences, and {@link resolveSpecifierToPackage} returns a * `packageGroup`, by ONE shared key function — {@link packageGroupOf}. With a * {@link PackageManifestIndex} (the production path — every real caller passes * one) the key is the OWNING package's `name`, found by the longest manifest-dir * prefix of the file path. That is layout-AGNOSTIC: it works for `apps/`, `libs/`, * `crates/`, nested `packages///`, or a single-package repo — anywhere a * `package.json` lives — not just a flat `packages//` tree. Without a * manifest (legacy / unit-test callers only) it falls back to the historical * `packages/` path heuristic. Both {@link buildExportIndex} and * {@link resolveSpecifierToPackage} use the SAME function with the SAME manifest, * so a specifier's resolved group matches the `ExportIndex` keys verbatim — the * linchpin holds on any layout. */ import type { PackageManifestIndex } from './package-group.js'; import type { Shard } from '../cli/orchestrate/shard-model.js'; import type { Catalog, FunctionOccurrence } from '../types.js'; export { packageGroupOf } from './package-group.js'; export type { PackageManifest, PackageManifestIndex } from './package-group.js'; /** * Per-package export symbol table: `package` → (`name` → exported occurrences). * * The outer key is {@link packageGroupOf}`(filePath, manifestIndex)` — the * owning package's `name` when a manifest is supplied (layout-agnostic), else * the `packages/` heuristic — matching the bucketing the boundary * resolver uses; the inner key is a function's `simpleName`. Only * `visibility === 'exported'` occurrences are present — module-local and private * occurrences are excluded, since an import specifier can only reach a package's * exports. * * Insertion order follows catalog iteration. Consumers MUST match by name, not * order; the inner arrays are the deterministic candidate set for a name. */ export type ExportIndex = ReadonlyMap>; /** * Bucket every exported occurrence in `catalog` by its package group then by * its simple name. Deterministic and allocation-lean: one pass over * `catalog.functions`, no sorting (matching is by name, not order). * * The package key is `packageGroupOf(occ.filePath, manifestIndex)` — identical * to what the cross-shard resolver buckets by — so Phase 2 can look up * `exportIndex.get(packageGroup)` where `packageGroup` comes from * {@link resolveSpecifierToPackage} (with the SAME manifest). Passing the * manifest is what makes the index layout-agnostic (keyed by package `name`); * omitting it falls back to the `packages/` heuristic. */ export declare function buildExportIndex(catalog: Catalog, manifestIndex?: PackageManifestIndex): ExportIndex; /** * Read each shard's `package.json` (`name`, `exports`) and index it by package * name. Reuses the already-resolved `Shard[]` (no re-discovery); a shard whose * `rootDir` has no readable/parseable `package.json`, or whose manifest has no * string `name`, is skipped (it simply won't be specifier-resolvable). * * `projectRoot` is the common root all shard file paths are relativized * against, so each manifest's `dir` is in the same project-relative form * `packageGroupOf` matches against. */ export declare function buildPackageManifestIndex(shards: readonly Shard[], projectRoot: string): PackageManifestIndex; /** * Build a {@link PackageManifestIndex} from a bare list of package ROOT dirs * (absolute), reading each `/package.json`. The `Shard`-free entry the * single-program (exact) engine uses: it has no `Shard[]` to hand the shard * overload, only the package roots it derived from the catalog. Same best-effort * semantics — a root with no readable/parseable manifest, or a manifest with no * string `name`, is skipped (it won't be specifier-resolvable). * * Duplicate `package.json#name` FAILS CLOSED (P2 Phase 0.4): the first time a * name is seen twice it is tombstoned and removed from the index, so * {@link resolveSpecifierToPackage} declines that name regardless of root order. * A guessed first-write-wins attribution across an ambiguous workspace name is * strictly worse than an honest decline. Only a bounded diagnostic COUNT is * logged — never the ambiguous names or paths. */ export declare function buildPackageManifestIndexFromRoots(rootDirs: readonly string[], projectRoot: string): PackageManifestIndex; /** The outcome of resolving a bare import specifier to a workspace package. */ export interface ResolvedSpecifier { /** The {@link packageGroupOf}-aligned group key (the package `name`) — looks * up into an {@link ExportIndex} built with the same manifest. */ readonly packageGroup: string; /** The `exports` subpath (`./errors`) when the specifier addressed one. */ readonly subpath?: string; } /** * Resolve a bare import specifier (`@scope/pkg` or `@scope/pkg/subpath`, or the * unscoped `pkg` / `pkg/subpath`) to the package group an {@link ExportIndex} * is keyed by, plus the addressed `exports` subpath when present. * * Returns `undefined` (→ Phase 2 declines, emits no edge) when: * - the specifier is relative (`./x`) or empty — not a bare package import; * - the package name is not in `manifestIndex` (external / untracked dep); * - a subpath is present but is NOT declared in the package's `exports` map. * * **V1 subpath scope (open question decided here):** resolve the package ROOT * export and only those subpaths LITERALLY declared as keys in `exports` * (`./errors`, `./languages/parse-cache.js`). Glob/conditional `exports` * resolution is deferred. A package with no object `exports` is treated as * exposing only its root — any subpath against it is unmappable → `undefined`. * The returned `packageGroup` is the same for root and subpath (the subpath * lives inside the same package); Phase 2 narrows by name within that group. */ export declare function resolveSpecifierToPackage(specifier: string, manifestIndex: PackageManifestIndex): ResolvedSpecifier | undefined; //# sourceMappingURL=export-index.d.ts.map