/**
 * The dependency version space: for each dependency, the set of signature-database versions that survive the
 * project's constraints (declared ranges, transitive requirements, the base-R/assumed-R bound, a date cutoff, and
 * how the code actually calls the package), and the explosion of that space into concrete per-dependency version
 * assignments. This is a source-agnostic resolver over {@link PackageSignatureSource} and the dependencies context;
 * the `guess-dep-versions` query presents it, but it is usable on its own (e.g. for compatibility-matrix tooling).
 */
import { type Range } from 'semver';
import { type VersionString } from '../util/r-version';
import { type PackageSignatureSource } from './sigdb/reader';
import type { DecodedFunction, ResolvedDependency } from './sigdb/decode';
import { FunctionArgument, type DataflowGraph } from '../dataflow/graph/graph';
import type { ReadOnlyFlowrAnalyzerDependenciesContext } from './context/flowr-analyzer-dependencies-context';
import type { ReadonlyFlowrAnalysisProvider } from './flowr-analyzer';
import type { NodeId } from '../r-bridge/lang-4.x/ast/model/processing/node-id';
/** the pseudo-package standing for the analyzed project itself, never one of its own dependencies */
export declare const ProjectPackage = "current";
/** where a single bound on a dependency's version came from */
export type ConstraintSource = 'declared' | 'transitive' | 'signature' | 'date' | 'base-r' | 'available' | 'indirect';
/**
 * One provenance-carrying constraint on a dependency's version: *where* it comes from ({@link source}/{@link origin})
 * and *what* it requires ({@link bound}). The set of these is exactly why a range is what it is, so it can answer
 * "it must be `>= 4.2.0` because ...".
 */
export interface DerivedConstraint {
    readonly source: ConstraintSource;
    /** the concrete origin of the constraint, e.g. `project metadata`, `dplyr 1.1.0`, `dplyr::filter` */
    readonly origin: string;
    /** a human-readable explanation, e.g. `dplyr::filter has parameter '.by' only from 1.1.0` */
    readonly detail: string;
    /** the qualified function that carried the evidence (for {@link ConstraintSource|signature} constraints) */
    readonly function?: string;
    /** the argument/parameter that carried the evidence (for signature constraints) */
    readonly parameter?: string;
    /** the call site that carried the evidence, so a bound can point at the line forcing it */
    readonly at?: NodeId;
    /** the version bound this constraint establishes, if any (e.g. `>=1.1.0`, `<=2021-05-31`) */
    readonly bound?: string;
    /**
     * Set when the bound only holds for *some* of the origin's own candidate versions (e.g. only the newer releases
     * of `dplyr` require `R >= 4.1`). Such a constraint is reported but never filters, as picking another version of
     * the origin avoids it.
     */
    readonly partial?: boolean;
}
/** notified of each constraint as it is applied, so a caller can collect provenance (e.g. into the query's evidence) */
export type ConstraintObserver = (constraint: DerivedConstraint) => void;
/** resolves (and memoizes) one function's decoded signature at a given version of the current package */
export type FnResolver = (fn: string, version: VersionString) => DecodedFunction | undefined;
/** how a single function of a package is used in the code */
interface FunctionUsage {
    /** per named argument used anywhere, the first call supplying it (drives the lower-bound evidence) */
    readonly named: Map<string, NodeId>;
    /** one representative argument list per distinct call *shape* (drives signature compatibility) */
    readonly calls: Map<string, readonly FunctionArgument[]>;
    /** the first call of the function, absent when only a class use implies it */
    at?: NodeId;
}
/** per-package function usage, keyed by the function's (unqualified) name */
export type PackageUsage = Map<string, FunctionUsage>;
/** one dated release in a package's version timeline */
export interface TimelineEntry {
    readonly ver: VersionString;
    readonly date?: Date;
}
/**
 * The version qualifier a package imposes on one of its own dependencies (a transitive constraint). Because the
 * declaring package's own version is usually a guess too, the requirement is read from *every* version of it that is
 * still in play: {@link ranges} holds one alternative per distinct requirement found, and only a
 * {@link universal} constraint (one that every one of those versions declares) may filter.
 */
export interface TransitiveConstraint {
    /** the alternative requirements; a version satisfying any one of them is acceptable */
    readonly ranges: readonly Range[];
    /** the declaring package + version, e.g. `dplyr 1.1.0`, or just `dplyr` when read from several of its versions */
    readonly from: string;
    /** whether every considered version of the declaring package requires *something*, so the constraint can filter */
    readonly universal: boolean;
}
/** the versions of a package before and after the signature-usage filter, plus the declared inputs used to build them */
export interface SurvivingEntries {
    /** versions after all constraints including signature-usage compatibility */
    readonly survivors: TimelineEntry[];
    /** versions after the declared/transitive/base/date constraints but *before* the signature filter */
    readonly preSignature: TimelineEntry[];
    /** the memoized function resolver used for the signature pass (shared so evidence reuses the decodes) */
    readonly getFn: FnResolver;
    /** the combined, satisfiable declared range (`inferredRange`), or `undefined` if none/contradictory */
    readonly declaredRange: Range | undefined;
    /** the raw declared version constraints */
    readonly declaredConstraints: readonly string[];
    /** whether the package is an R-core / base package */
    readonly base: boolean;
    /** whether the declared + transitive constraints contradict each other (no version can satisfy them all) */
    readonly unsatisfiable: boolean;
    /** the total number of versions the database carries for the package (the full history the candidates are drawn from) */
    readonly total: number;
    /** whether the database carries the package at all: `false` means "no record", not "no constraint" */
    readonly known: boolean;
    /** how many of those versions the *declared* constraints alone allow, the baseline the guess narrows down from */
    readonly declared: number;
}
/** one package's surviving versions, ordered by preference for the constraint-space explosion */
export interface OrderedCandidates {
    readonly pkg: string;
    readonly versions: readonly VersionString[];
}
/** options for {@link explodeDependencyVersions} */
export interface VersionExplodeOptions {
    /** iterate each package's versions newest-first (default) or oldest-first */
    readonly order?: 'newest' | 'oldest';
    /** a version to prefer per package, used first when it survives the constraints (package name to version) */
    readonly prefer?: Readonly<Record<string, VersionString>>;
    /** restrict to these packages (default: every declared and used dependency) */
    readonly packages?: readonly string[];
    /** only consider releases on or before this day, `YYYY.MM.DD` (also `YYYY` or `YYYY.MM`) */
    readonly date?: string;
    /** cap the number of assignments produced (default {@link DefaultExplodeLimit}) */
    readonly limit?: number;
}
/** a concrete, sigdb-available version choice for every resolvable dependency */
export interface VersionAssignment {
    readonly versions: ReadonlyMap<string, VersionString>;
    /**
     * The requirements of the chosen versions that nothing here could settle, because they bear on a package the
     * assignment does not choose (`dplyr 1.1.0 requires rlang >= 1.0.0`). Such an assignment holds for what it
     * states and may still fail at `library()` time, so it is proposed but not verified.
     */
    readonly unverified?: readonly string[];
}
export declare const DefaultExplodeLimit = 256;
/** the date cutoff (end of the named day/month/year) for a `YYYY.MM.DD` spec, or `undefined` if malformed */
export declare function dateCutoff(spec: string): Date | undefined;
/** an ISO `YYYY-MM-DD` day */
export declare function isoDay(date: Date): string;
/** scan the dataflow graph for every call that resolves (via {@link Dataflow.qualify}) to a package export */
export declare function collectUsage(graph: DataflowGraph, deps?: ReadOnlyFlowrAnalyzerDependenciesContext): Map<string, PackageUsage>;
/** why one orphan call was attributed to its package, given that several may export the name */
export type OrphanReason = 'builtin' | 'sole exporter' | 'most downloaded';
/** one orphan call: the undefined name, where it is called, and why it was pinned on the package */
export interface OrphanCall {
    readonly at: NodeId;
    readonly reason: OrphanReason;
    /** how many packages export the name, the field the {@link OrphanReason} picked from */
    readonly exporters: number;
}
/**
 * What the orphan calls of one analyzed program implicated, as {@link collectOrphanUsage} reports it.
 */
export interface OrphanUsage {
    /** per package the project does not already know: the orphan calls that pointed at it, by function name */
    readonly attributed: Map<string, Map<string, OrphanCall>>;
    /** per such package: the other exporters of those names that lost the pick, most downloaded first */
    readonly alternatives: Map<string, string[]>;
    /** the same calls recorded against every alternative, so a caller can ask which of its versions would fit */
    readonly alternativeUsage: Map<string, PackageUsage>;
}
/** options for {@link collectOrphanUsage} */
export interface OrphanUsageOptions {
    /** the analyzed project's own namespace, never inferred as one of its own orphan dependencies */
    readonly self?: string;
    /** flowR's curated map of a builtin-modeled library function to its package (e.g. `ggplot` to `ggplot2`), the authoritative disambiguator when several packages export the name */
    readonly builtinLibraryOf?: (name: string) => string | undefined;
}
/**
 * Fold the analyzed code's *orphan* calls into `usage` and report which functions implicated each **unknown**
 * package. An orphan is a bare call (`ggplot()`) whose name is not bound to a local/parameter/closure/import
 * definition and is not a default-attached base export, but is exported by exactly one signature-database package.
 * Such a call never qualifies to `pkg::fn`, so {@link collectUsage} is blind to it (even when flowR models the
 * function as a builtin, as it does for `ggplot`), yet it pins the package's version just as a qualified call
 * would; folding it into `usage` makes the package a guess target. The returned map lists, per package the project
 * does not already declare or load (`isKnown` is `false`), the orphan function names that pointed at it (e.g.
 * `ggplot2` from `ggplot()`) -- a note for a downstream handler to attach the library, since the symbol would be
 * undefined were the package not loaded. Disambiguation is `options.builtinLibraryOf` (flowR's curated map, e.g.
 * `ggplot` to `ggplot2`, authoritative even when several packages re-export the name), then a package the project
 * already declares or loads, and finally the most downloaded of at most {@link MaxOrphanProviders} exporters; a
 * name beyond that many packages export says nothing about which one is meant and is skipped, as are quoted (NSE)
 * uses and forward-referenced closures. The exporters that lost the pick are kept as
 * {@link OrphanUsage.alternatives}, since the guess is exactly that -- a guess.
 */
export declare function collectOrphanUsage(graph: DataflowGraph, deps: ReadOnlyFlowrAnalyzerDependenciesContext, usage: Map<string, PackageUsage>, isKnown: (pkg: string) => boolean, options?: OrphanUsageOptions): OrphanUsage;
/** intersection of multiple survivor sets: versions that survive in every set */
export declare function intersectSurvivors(survivorSets: readonly (readonly TimelineEntry[])[]): TimelineEntry[];
/**
 * The transitive constraints declared packages place on their own dependencies (one level deep). `versionsOf` gives
 * the versions of each declaring package that are still in play. The requirements are read from all of them, so a
 * constraint only ever filters when *every* one of them declares it (see {@link TransitiveConstraint}). Without it,
 * the single {@link Package.resolvedVersion|resolved version} is used, which is by definition universal.
 */
export declare function collectTransitiveConstraints(deps: ReadOnlyFlowrAnalyzerDependenciesContext, sources: readonly PackageSignatureSource[], versionsOf?: (pkg: string) => readonly VersionString[] | undefined): Map<string, TransitiveConstraint[]>;
/** the default bound for the fixpoint loops, overridable per query with {@link GuessDepVersionsQuery.maxIterations} */
export declare const DefaultFixpointIterations = 8;
/** repeatedly run `step` until it reports no further change (returns `false`) or `maxIterations` is reached */
export declare function iterateToFixpoint(maxIterations: number, step: () => boolean): void;
/** the per-analysis inputs every constraint pass shares, see {@link VersionSpace} */
export interface VersionSpaceOptions {
    readonly deps: ReadOnlyFlowrAnalyzerDependenciesContext;
    /** how the analyzed code calls each package, from {@link collectUsage} */
    readonly usage: ReadonlyMap<string, PackageUsage>;
    /** only consider releases up to this instant */
    readonly cutoff?: Date;
    /** the assumed R version bounding base packages, when genuinely known */
    readonly rVersion?: string;
    /** constraint sources to skip entirely: neither filtered on nor reported */
    readonly disabled?: ReadonlySet<ConstraintSource>;
}
/** a target's sigdb package key, merged source and memoized signature resolver */
interface PackageResolution {
    readonly key: string;
    readonly src: PackageSignatureSource | undefined;
    readonly getFn: FnResolver;
    /** the package's release timeline, ascending */
    readonly timeline: readonly TimelineEntry[];
    /** the usage the signature pass judges by (base primitives dropped for a base package), `undefined` if unused */
    readonly usage: PackageUsage | undefined;
    /** whether a version's signatures accept how the code calls it, see {@link makeSignatureFilter} */
    readonly signatureOk: (version: VersionString) => boolean;
}
/**
 * The version space of one analysis: the surviving versions of each dependency and the transitive constraints
 * refined to a fixpoint. Holding the shared inputs here keeps the passes to a handful of arguments and lets each
 * package's sigdb key, source and decoded signatures be resolved once. The passes revisit the same versions
 * repeatedly, so that memoization is what makes the fixpoint affordable.
 */
export declare class VersionSpace {
    readonly deps: ReadOnlyFlowrAnalyzerDependenciesContext;
    readonly sources: readonly PackageSignatureSource[];
    readonly usage: ReadonlyMap<string, PackageUsage>;
    readonly cutoff: Date | undefined;
    readonly rVersion: string | undefined;
    readonly disabled: ReadonlySet<ConstraintSource>;
    private readonly resolved;
    constructor({ deps, usage, cutoff, rVersion, disabled }: VersionSpaceOptions);
    /** the sigdb package, source and signature resolver of a target, resolved once */
    resolve(name: string): PackageResolution;
    /** the versions of `name` surviving every constraint, see {@link survivingEntries} */
    survivors(name: string, transitive: readonly TransitiveConstraint[], observe?: ConstraintObserver): SurvivingEntries;
    /**
     * The transitive constraints, refined to a fixpoint: each pass re-reads every declaring package's requirements
     * from the versions of it that survived the previous pass, so two packages can tighten each other. Feeding back
     * the whole surviving set (not one representative version) is what keeps a requirement that only *some* of those
     * versions declare from filtering (see {@link TransitiveConstraint}).
     *
     * The first pass runs with *no* transitive constraint at all, so every later pass can only shrink the surviving
     * sets and thus only tighten the constraints: the refinement is monotone and cannot oscillate, and stopping early
     * at `maxIterations` leaves it on the permissive side rather than at an arbitrary point. A declaring package that
     * is not among the `targets` is not being guessed, so its {@link Package.resolvedVersion} stands in.
     */
    refineTransitive(targets: readonly string[], maxIterations?: number): Map<string, TransitiveConstraint[]>;
}
/** the outcome of {@link enforceArcConsistency}: the pruned version sets, and which partner blocked each package */
export interface ArcConsistency {
    readonly survivors: Map<string, TimelineEntry[]>;
    /** per package, the partner that rejected a version and the requirement it could not meet */
    readonly blockers: Map<string, Map<string, string>>;
}
/** drop, to a fixpoint, the versions of each package that no co-guessed dependency can satisfy */
export declare function enforceArcConsistency(space: VersionSpace, initial: ReadonlyMap<string, TimelineEntry[]>, maxIterations?: number): ArcConsistency;
/** a package (or a linked group sharing one version) and its surviving versions, one factor of the combination count */
export interface CountFactor {
    readonly name: string;
    readonly survivors: readonly string[];
}
/** two packages whose version choices are not independent, and whether that holds for all of their versions */
export interface VersionCoupling {
    readonly a: string;
    readonly b: string;
    /** `false` when only *some* versions of the two require each other, so the coupling does not always apply */
    readonly always: boolean;
    /** whether the coupling was counted; a coupling closing a cycle in the graph is dropped from the count */
    readonly counted: boolean;
}
/** the result of {@link countRunnableCombinations} */
export interface CountedCombinations {
    /** the number of runnable version tuples; an upper bound when {@link couplings} contains uncounted entries */
    readonly total: number;
    /** every coupling found between the counted factors */
    readonly couplings: readonly VersionCoupling[];
}
/**
 * The runnable-combination count: how many version tuples satisfy the requirements the factors place on each other.
 * A requirement need not hold for every version of the declaring package (`A 0.2.5` may pin `B` to `0.2.1` while
 * `A 0.3.0` pins it to `0.3.2`), so the two are counted as *coupled* rather than as independent factors: a version
 * of `A` only ever multiplies in the versions of `B` it actually admits.
 *
 * Counting all couplings exactly is #CSP-hard, so they are counted over a spanning forest of the coupling graph,
 * preferring the couplings that always apply. That is exact whenever the graph has no cycle, which covers the common
 * shared-hub shape. A coupling that would close a cycle is dropped and reported as uncounted, leaving the result an
 * upper bound. Only the forest's couplings need their compatibility matrix, so the work stays linear in the factors.
 */
export declare function countRunnableCombinations(space: VersionSpace, factors: readonly CountFactor[]): CountedCombinations;
/** an empty set, shared so callers that do not disable anything need not allocate one */
export declare const NoDisabledSources: ReadonlySet<ConstraintSource>;
/**
 * Apply every constraint (declared, transitive, base-R, date, then signature usage) to a package's timeline. When an
 * `observe` callback is given, emits the provenance of each constraint (including the signature lower bounds).
 * Prefer {@link VersionSpace.survivors}, which is the same call with the shared inputs already bound.
 */
export declare function survivingEntries(space: VersionSpace, name: string, transitive: readonly TransitiveConstraint[], observe?: ConstraintObserver): SurvivingEntries;
/** the sigdb package a target's version history is drawn from: `R` reuses `base` (their releases coincide), everything else is itself */
export declare function timelinePackageKey(name: string, sources: readonly PackageSignatureSource[]): string;
/** the ordered candidate list for one package, or `undefined` when nothing survives (shared by the query and the iterator) */
export declare function orderedCandidatesOf(src: PackageSignatureSource | undefined, name: string, surviving: SurvivingEntries, prefer: string | undefined, order: 'newest' | 'oldest'): OrderedCandidates | undefined;
/** the default explosion targets: every declared and used dependency (excluding `current`, the analyzed package's own namespace) */
export declare function defaultTargets(deps: ReadOnlyFlowrAnalyzerDependenciesContext, usage: ReadonlyMap<string, PackageUsage>): string[];
/** the requirements one concrete version declares, as {@link coInstallability} reads them */
export type DependencyResolver = (pkg: string, version: VersionString) => readonly ResolvedDependency[] | undefined;
/**
 * Whether the chosen versions can be loaded together, checking every requirement the chosen versions declare
 * against the version chosen for the required package (R itself against the chosen base-R version). A requirement
 * on a package the assignment does not choose cannot be settled here and is reported as
 * {@link VersionAssignment.unverified} instead of silently passing, as `library()` still enforces it.
 */
export declare function coInstallability(versions: ReadonlyMap<string, VersionString>, declares: DependencyResolver): {
    ok: boolean;
    unverified?: readonly string[];
};
/**
 * Lazily yield concrete version assignments (one version per package) in odometer order over the per-package lists.
 * With `declares`, a combination whose versions cannot be loaded together is skipped rather than proposed; `limit`
 * bounds the combinations *considered* either way, so fewer than `limit` assignments may come out.
 */
export declare function assignmentsOf(perPackage: readonly OrderedCandidates[], limit: number, declares?: DependencyResolver): Generator<VersionAssignment>;
/** the {@link DependencyResolver} backed by the signature database a version space resolves each package in */
export declare function declaredDependenciesOf(space: VersionSpace): DependencyResolver;
/**
 * Explode the guessed constraint space into concrete, signature-database-available version assignments: a lazy
 * iterator over one chosen version per resolvable dependency. Each package's versions are ordered by preference
 * (an explicitly {@link VersionExplodeOptions.prefer|preferred} version, then non-archived releases, then newest or
 * oldest first), so the first assignments are the most preferred. The iterator is bounded by
 * {@link VersionExplodeOptions.limit} so an enormous product cannot run away.
 */
export declare function explodeDependencyVersions(analyzer: ReadonlyFlowrAnalysisProvider, options?: VersionExplodeOptions): AsyncGenerator<VersionAssignment>;
export {};
