/**
 * Cross-component imports graph (engines 6.32.6+).
 *
 * Phase A of Dom Williams's "shared library / reference vs implicit
 * include" feedback (2026-05-07). When the analysed source is a
 * monorepo with shared/ libraries (idle_meta has shared/services/,
 * shared/ui/, shared/data/, shared/schemas/), the prepass already
 * decomposes the source into one component per top-level dir — but
 * never models the dependency direction. `IdleApiService` ends up
 * with action steps like `[call] AuthService.login` without any
 * spec-level binding to the `Services` component that owns AuthService.
 *
 * This module walks each component's TS/JS files for `import { X } from
 * '...'` statements, resolves the import path relative to the source
 * tree, and matches the resolved path against the other components'
 * sourceDirs. Result: a map of consumer → (target component → set of
 * imported symbol names). The skeleton-emitter consumes that map to
 * emit `import:` blocks per consumer component.
 *
 * Detection is regex-based — same approach as the express-routes /
 * zod-schemas adapters. Good enough for ES module + CommonJS source;
 * misses dynamic `await import()` and `require(variable)` (rare in
 * spec-able codebases). Type-only imports are included; the realize
 * engine will ignore unused selects.
 */
import type { StructuralPrepass } from './interface.js';
import type { SpecVerseFacts } from './index.js';
export interface ParsedImport {
    /** Raw module specifier from `from '...'`. */
    source: string;
    /**
     * Imported symbol names — what the spec's `import: select:` should
     * list. Default-imports contribute their local name; named imports
     * contribute the imported (not local-aliased) name. Namespace
     * imports (`import * as M from 'mod'`) DO NOT contribute — `M` is a
     * local module alias, not an exported symbol; emitting it as
     * `select: [M]` would be misleading. The `namespaceAlias` field
     * captures it separately for downstream tools that care.
     */
    names: string[];
    /** Local alias for `import * as <X> from 'mod'`, when present. */
    namespaceAlias?: string;
    /** True for type-only imports (`import type { ... } from '...'`). */
    typeOnly: boolean;
}
/**
 * Extract all import statements from a TS/JS source file. Handles:
 *   - `import { A, B as C } from 'mod'` — named
 *   - `import D from 'mod'` — default
 *   - `import * as M from 'mod'` — namespace
 *   - `import 'mod'` — side-effect (returns names: [])
 *   - `import type { A } from 'mod'` — type-only
 *   - `const { A } = require('mod')` — CommonJS destructuring
 *
 * Returns an empty array on empty input. Skips comments and string
 * literals (basic heuristic — strips block comments and line comments).
 */
export declare function parseImports(source: string): ParsedImport[];
/**
 * Resolve a relative import path against the file that contains the
 * import. Returns a normalised path (no `..` / `.` segments, no leading
 * `./`). Non-relative specifiers (`react`, `@scope/pkg`) return null
 * unless they match an alias in `aliases` (Engines 6.32.7+).
 *
 * The result is the path as it would appear in the source tree, NOT
 * the absolute disk path. Caller compares it against component
 * sourceDirs (which are also tree-relative) to see if the import
 * crosses a component boundary.
 *
 * @param aliases Optional map of alias resolutions from a tsconfig
 *                 `paths` block. Keys are alias patterns (e.g. `@shared/ui`,
 *                 `@/*`); values are pre-resolved tree-paths. The resolver
 *                 substitutes a longest-prefix match before falling back
 *                 to relative-only resolution.
 */
export declare function resolveImportPath(fromFile: string, importSpec: string, aliases?: Record<string, string>): string | null;
/**
 * Engines 6.32.7+ — parse the `compilerOptions.paths` block from a
 * tsconfig.json and return an absolute alias map.
 *
 * tsconfig paths are relative to the tsconfig's directory (or to
 * `compilerOptions.baseUrl` if set). This function resolves them to
 * tree-relative absolute paths so the import resolver can match them
 * against component sourceDirs without further normalisation.
 *
 * Returns an empty object when the tsconfig has no paths block, or
 * when parsing fails (best-effort — broken tsconfigs shouldn't break
 * the analyse pipeline).
 *
 * Note: paths entries like `[ "../../shared/ui/src/index.ts" ]` — we
 * strip the trailing `index.ts` segment so the alias maps to the
 * directory level (which is what the import resolver needs to match
 * against component sourceDirs).
 */
export declare function parseTsconfigPaths(tsconfigSource: string, tsconfigDir: string): Record<string, string>;
/**
 * Match a resolved import path against component sourceDirs and return
 * the owning component's suggestedName. Picks the LONGEST matching
 * sourceDir prefix (handles the case where one component's dir is
 * nested inside another's). Returns null if no component owns the path.
 */
export declare function findOwningComponent(resolvedPath: string, components: NonNullable<SpecVerseFacts['suggestedComponents']>): string | null;
/**
 * Per-consumer import index: `{ [consumer]: { [target]: [...names] } }`.
 *
 * Symbols are imported names (we don't dedup against locally-defined
 * symbols; the spec-level `import:` block lists what's pulled in, not
 * what's used). Plain-object shape so it serialises cleanly into
 * facts.json and can be re-loaded by downstream consumers (the
 * skeleton emitter, future tools that want a cross-component
 * dependency view, etc.).
 */
export type ImportsByComponent = Record<string, Record<string, string[]>>;
/**
 * V2 (Component Dependencies V2 — 2026-05-08) per-target metadata
 * accompanying the bare-name index above. Optional fields populated when
 * derivable from package.json or the consumer's source code; absent
 * fields signal "no info" rather than "no version" / "no dotted ops".
 *
 * The shape sits parallel to ImportsByComponent rather than replacing
 * its value type, preserving backward compatibility for the existing
 * skeleton-emitter and test surface (which both spread `target → names`
 * directly). V2-aware emitters consult both indexes side-by-side.
 */
export interface ImportTargetMetadata {
    /**
     * Resolved version range from the target component's package.json
     * `version` field (when one exists). Format-flexible string — ranges
     * like ^1.0 or pins like 1.4.2 both pass through. Absent when the
     * target lives outside the npm-package-shaped slice of the source
     * tree (in-tree component without its own package.json).
     */
    version?: string;
    /**
     * Dotted operation references discovered in the consumer's source
     * code at sites that call into the target component. Examples:
     *   `stripe.charges.create(...)` → `charges.create`
     *   `await calculator.calculate({ ... })` → `calculate`
     * The recogniser scans property-access chains rooted at imported
     * symbols. Sorted alphabetically; deduped.
     */
    dottedOps?: string[];
}
export type ImportsMetadataByComponent = Record<string, Record<string, ImportTargetMetadata>>;
export interface BuildImportsByComponentOpts {
    facts: SpecVerseFacts;
    /** Async file reader — accepts a tree-relative or absolute path. */
    readFile: (path: string) => Promise<string>;
    /** Optional: limit which file extensions get parsed. Defaults to TS/JS. */
    extensionFilter?: (path: string) => boolean;
}
/**
 * Result bundle for the V2-aware build helper. The `imports` field
 * preserves the pre-V2 shape (string[]) for downstream callers that
 * already know how to consume it. The `metadata` field carries V2's
 * per-target version and dotted-op information.
 */
export interface BuildImportsByComponentResult {
    imports: ImportsByComponent;
    metadata: ImportsMetadataByComponent;
}
/**
 * Build the per-consumer imports graph. Each component's files are
 * walked, their imports parsed, and resolved against the source tree;
 * imports that cross into another component's sourceDir are aggregated.
 */
export declare function buildImportsByComponent(opts: BuildImportsByComponentOpts): Promise<ImportsByComponent>;
/**
 * Convenience: build the imports graph from a StructuralPrepass backend.
 * The backend's `fileSourceText` provides the file reader; this is the
 * same surface the adapters use to read files.
 */
export declare function buildImportsByComponentFromBackend(facts: SpecVerseFacts, backend: StructuralPrepass): Promise<ImportsByComponent>;
/**
 * V2 (Component Dependencies V2 — 2026-05-08) — extract dotted operation
 * references from a consumer source file. Walks property-access chains
 * rooted at the import-bound symbol names supplied in `bindings` and
 * returns each chain's tail (`charges.create`, `Calculator.calculate`,
 * etc.). The leading symbol is stripped because it names a JS-side
 * binding, not a SpecVerse-side `select:` entry — the dotted op is what
 * matters for V2's `select: [Charge.create]` grammar extension.
 *
 * Heuristic: regex over `<symbol>(.<segment>)+` where each segment is a
 * camelCase or PascalCase identifier. Skips comments via the same naive
 * stripper as `parseImports`. Two-segment chains (`s.charges`) are
 * dropped — those are property accesses, not operation calls. Three-
 * segment-or-more chains (`stripe.charges.create`) keep the trailing two
 * segments (`charges.create`) as the dotted op. Single bound-symbol
 * call sites (`calculator(...)`) emit nothing — there's no operation
 * to name.
 *
 * The recogniser runs per-file and returns a Set so the caller can
 * dedup across files. Empty input → empty Set.
 */
export declare function detectDottedOps(source: string, bindings: Iterable<string>): Set<string>;
/**
 * V2 — build both the bare-names imports graph (existing) AND the V2
 * per-target metadata index (version + dotted ops). The bare-names half
 * is identical to `buildImportsByComponent`; the metadata half walks
 * each target component's package.json (for `version`) and re-scans the
 * consumer's source files for dotted-op patterns rooted at symbols
 * bound by imports from that target.
 *
 * Backward-compat: callers that don't need V2 metadata keep using
 * `buildImportsByComponent` directly. The V2-aware skeleton emitter
 * can switch to this two-output variant when emitting `version:` and
 * dotted-form `select:` entries.
 */
export declare function buildImportsByComponentWithMetadata(opts: BuildImportsByComponentOpts): Promise<BuildImportsByComponentResult>;
/**
 * Categories for the four V2 Phase 2 patterns. Maps directly onto the
 * existing `instances.<category>:` keys in the deployment schema. There
 * is no new `runtime:` enum (V2 mid-design retraction).
 *
 * `infrastructure` — subprocess CLIs and managed SaaS SDKs both land
 * here because they're external runtime dependencies the deployment
 * provisions but doesn't host. The factory metadata distinguishes them.
 *
 * `services` — HTTP/RPC clients consumed by the deployment. The factory
 * choice (e.g. `FastifyAPI` vs `StripeRestSDK`) determines whether a
 * server is also emitted; here we only model the client side.
 *
 * `communications` — async brokers (rabbitmq / kafka / event bus).
 */
export type NonLibraryCategory = 'infrastructure' | 'services' | 'communications';
/**
 * One detected non-library dependency. Two-sided shape — the same hint
 * drives the consumer-side `import:` block AND the deployment-side
 * instance entry. Both sides of the V2 bridge produced from one walker
 * pass.
 *
 * - `from:` becomes the consumer's `import: - from: <X>` value.
 * - `select:` becomes the consumer's `select: [...]` list (dotted ops
 *   when method calls were observed; bare names when only the SDK
 *   instance was constructed).
 * - `version:` is the package version when derivable from package.json
 *   (managed SDKs); absent for subprocess + HTTP-baseURL detections
 *   where there's no version handle in source.
 * - `deploymentHint.category:` chooses the instance category (one of
 *   the existing 8 in the schema; we use 3 of them).
 * - `deploymentHint.instanceName:` must be unique within its category;
 *   the orchestrator handles cross-component dedup downstream.
 * - `deploymentHint.advertises:` is the capability tag the instance
 *   presents (existing field, free-form CapabilityList).
 * - `deploymentHint.config:` carries binding parameters specific to the
 *   pattern — `binary:` for subprocess, `endpoint.env:` for service
 *   clients, `provider:` + `authEnv:` for managed SDKs, etc.
 * - `pattern:` is the detection rule that fired, useful for telemetry
 *   and for the deployment-emitter to know which factory family to
 *   suggest later.
 */
export interface NonLibraryImportHint {
    /** Provider name. Used as the import-block `from:` value. */
    from: string;
    /** Optional version range when derivable. */
    version?: string;
    /** Operation/method names the consumer references (dotted or bare). */
    select?: string[];
    /** Which detection pattern produced this hint. */
    pattern: 'subprocess' | 'service-client' | 'messaging' | 'managed-sdk';
    /** Source file the detection fired in (first-seen only). */
    sourceFile?: string;
    /** Hint for the deployment-emitter to fold into the production-default. */
    deploymentHint: {
        category: NonLibraryCategory;
        instanceName: string;
        advertises: string[];
        config: Record<string, unknown>;
    };
}
/**
 * Detect subprocess invocations:
 *   - `spawnSync('git', [...])`
 *   - `execSync('gitnexus analyze', ...)`
 *   - `child_process.spawn('ffmpeg', ...)`
 *   - `Bun.spawn(['<binary>', ...])`
 *
 * Heuristics:
 *   1. First positional argument is a string literal — treat as the
 *      binary name (`spawnSync('git', [...])` → binary `git`).
 *   2. `Bun.spawn([...])` — first array element string literal is the
 *      binary (`Bun.spawn(['ffmpeg', ...])` → `ffmpeg`).
 *   3. `execSync('foo bar baz')` — command string is shell-style; we
 *      take the first whitespace-delimited token as the binary
 *      (`execSync('git status')` → `git`).
 *   4. Variable arguments (`spawnSync(cmd, args)`) — skipped, can't
 *      reliably name the binary.
 *
 * Multiple invocations of the same binary in the same source produce
 * one hint (deduped by binary name).
 *
 * Each hint emits:
 *   - `import:` entry with `from: <binary>` (kebab-cased)
 *   - deployment instance under `infrastructure:`, `advertises:
 *     ["executable.<binary>"]`, `config: { binary: <binary> }`
 */
export declare function detectSubprocessCalls(source: string, sourceFile?: string): NonLibraryImportHint[];
/**
 * Detect HTTP/RPC service-client construction:
 *   - `axios.create({ baseURL: '...' })` — REST client
 *   - `axios.create({ baseURL: process.env.X })` — env-driven REST client
 *   - `fetch(BASE_URL + ...)` / `fetch(\`${BASE}/foo\`)` — bare fetch
 *   - `new GreeterClient('host:port', ...)` — gRPC stub instantiation
 *   - `new Client({ url: ... })` — generic MCP / RPC client
 *
 * Heuristics:
 *   1. axios.create({ baseURL }) — extracts the baseURL string when literal,
 *      or the env-var name when the value is `process.env.<X>`.
 *   2. Bare `fetch(<expr>)` — only when called against an env-var-shaped
 *      identifier (`process.env.X` or an UPPER_CASE constant the consumer
 *      owns); otherwise too noisy. The env-var becomes the hint's
 *      `endpoint.env`.
 *   3. gRPC stubs are tagged by the `*Client` suffix on a constructor
 *      whose first arg is a hostname-shaped string ('host:port').
 *
 * Returns an empty array when no patterns match. Multiple distinct
 * baseURLs in one file produce multiple hints.
 *
 * Each hint emits:
 *   - `import:` entry with `from: <baseURL-host or env-var>`
 *   - deployment instance under `services:`, `advertises:
 *     ["api.rest"]` (or `api.grpc` / `api.rpc`), `config:
 *     { endpoint: { env: <ENV_NAME> | url: <URL> } }`
 */
export declare function detectServiceClients(source: string, sourceFile?: string): NonLibraryImportHint[];
/**
 * Detect async messaging crossings:
 *   - `rabbit.subscribe('queue', handler)` / `rabbitMq.publish(...)`
 *   - `kafka.consume(...)` / `kafka.subscribe(...)` / `kafkaProducer.send(...)`
 *   - `eventBus.publish(...)` / `eventBus.subscribe(...)` (in-memory or
 *      cross-component bus crossings)
 *   - `nats.subscribe(...)` / `nats.publish(...)`
 *   - `redis.xadd(...)` (streams) / `redis.publish(...)` (pub-sub)
 *
 * Heuristic:
 *   - Match `<broker-handle>.<verb>(...)` where verb ∈ {subscribe,
 *     consume, publish, send, xadd}.
 *   - Broker name comes from the receiver identifier (`rabbitMq`,
 *     `kafka`, `eventBus`).
 *   - First positional arg, if a string literal, is recorded as a
 *     `queues[]` / `topics[]` entry on the deployment hint.
 *
 * Each hint emits:
 *   - `import:` entry with `from: <broker>` (lowercased)
 *   - deployment instance under `communications:`, `advertises:
 *     ["messaging.<broker>"]`, `config: { broker, queues: [...] }`
 */
export declare function detectMessagingCrossings(source: string, sourceFile?: string): NonLibraryImportHint[];
/**
 * Detect known managed-SaaS SDK initialisations:
 *   - `new Stripe(apiKey, ...)` → from: `@stripe/stripe-js`, advertises:
 *     `managed.payments`
 *   - `new OpenAI({ apiKey })` → from: `openai`, advertises: `managed.ai`
 *   - `new Anthropic({ apiKey })` → from: `@anthropic-ai/sdk`, advertises:
 *     `managed.ai`
 *   - `new SESClient({ region })` / AWS SDK init → from: `@aws-sdk/<x>`
 *   - `Twilio(sid, token)` → from: `twilio`, advertises: `managed.sms`
 *   - `new SendGridClient({ apiKey })` / `sgMail.setApiKey(...)` →
 *     from: `@sendgrid/mail`, advertises: `managed.email`
 *
 * The lookup table is INTENTIONALLY conservative — only well-known SDKs
 * with stable name signatures. For unknown providers, the spec author
 * adds the `import:` block manually.
 *
 * Authentication env-var inference:
 *   - When the constructor is called with `process.env.X`, that's the
 *     authEnv.
 *   - Otherwise we leave `authEnv` unset; the deployment-instance config
 *     just carries `provider:` and the spec author fills the env wiring.
 *
 * Each hint emits:
 *   - `import:` entry with `from: <scoped-package-name>` and version
 *     when the consumer's package.json names it as a dependency.
 *   - deployment instance under `infrastructure:`, `advertises:
 *     ["managed.<domain>"]`, `config: { provider: <name>, authEnv: <ENV> }`
 */
export declare function detectManagedSdkInit(source: string, sourceFile?: string): NonLibraryImportHint[];
/**
 * Run all four V2 Phase 2 detections against a single source file and
 * return a merged hint list. Convenience wrapper used by the prepass
 * orchestrator.
 */
export declare function detectNonLibraryDeps(source: string, sourceFile?: string): NonLibraryImportHint[];
/**
 * Per-component non-library hints, indexed by consumer component name.
 * Mirror shape to `ImportsByComponent` so emission paths can iterate
 * symmetrically. Hints from multiple files of the same consumer are
 * merged: same `from:` + same `pattern:` collapse to one hint with the
 * unioned `select:` + `config.queues:` lists.
 */
export type NonLibraryImportsByComponent = Record<string, NonLibraryImportHint[]>;
/**
 * Build the per-component non-library imports index. Walks every
 * consumer component's source files, runs the four detection passes,
 * deduplicates by (from, pattern) within a component, and unions the
 * select / queues fields. File walking reuses the same file-discovery
 * logic as `buildImportsByComponent` so detections are scoped to the
 * same surface as in-tree imports.
 */
export declare function buildNonLibraryImportsByComponent(opts: BuildImportsByComponentOpts): Promise<NonLibraryImportsByComponent>;
/**
 * Convenience: run the V2 Phase 2 non-library walker against a
 * StructuralPrepass backend (analogous to
 * `buildImportsByComponentFromBackend`).
 */
export declare function buildNonLibraryImportsByComponentFromBackend(facts: SpecVerseFacts, backend: StructuralPrepass): Promise<NonLibraryImportsByComponent>;
//# sourceMappingURL=imports-graph.d.ts.map