@eagleoutice/flowr-dev
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
196 lines (195 loc) • 13.2 kB
TypeScript
import type { BaseQueryFormat, BaseQueryResult } from '../../base-query-format';
import Joi from 'joi';
import type { NodeId } from '../../../r-bridge/lang-4.x/ast/model/processing/node-id';
import type { ParsedQueryLine } from '../../query';
import { type OutputFormatter } from '../../../util/text/ansi';
import { type VersionString } from '../../../util/r-version';
import type { ReplOutput } from '../../../cli/repl/commands/repl-main';
import { VersionSelection, type FlowrConfig } from '../../../config';
import { executeGuessDepVersionsQuery } from './guess-dep-versions-query-executor';
import type { ConstraintSource, DerivedConstraint, OrphanReason } from '../../../project/dependency-version-space';
import type { RVersionOrigin } from '../../../project/context/flowr-analyzer-context';
/**
* Guesses the possible version range of every dependency of a project by combining what the project *declares*
* (a `DESCRIPTION` range, an `rproject.toml` entry, a lockfile pin, and their transitive constraints) with what
* the code actually *does* (which package functions it calls and with which arguments, matched against the
* {@link https://github.com/flowr-analysis/flowr/wiki/Signature-Database|signature database}). A named argument
* a function only gained in some version raises the lower bound ("this parameter only existed from version X.Y,
* so it must be at least X.Y"); an optional `date` caps every guess to releases available at that point in time,
* and base-R packages are additionally bounded by the assumed/declared R version.
*/
export interface GuessDepVersionsQuery extends BaseQueryFormat {
readonly type: 'guess-dep-versions';
/** restrict the guess to these packages; omit to guess for every declared and used dependency */
readonly packages?: readonly string[];
/** only consider versions released on or before this day, written `YYYY.MM.DD` (also `YYYY` or `YYYY.MM`) */
readonly date?: string;
/** cap the number of candidate versions listed per dependency in the result (default {@link DefaultCandidateCap}) */
readonly maxCandidates?: number;
/** bound both fixpoint loops (mutual transitive refinement and arc consistency), default {@link DefaultFixpointIterations} */
readonly maxIterations?: number;
/** ignore the project's declared constraints (`DESCRIPTION` ranges, lockfile pins, transitive requirements); guess purely from code usage and the date/R bounds */
readonly clean?: boolean;
/** exclude these evidence sources from consideration entirely (repl: `--disabled` followed by their one-letter codes, e.g. `--disabled ds` for declared+signature) */
readonly disabled?: readonly ConstraintSource[];
/** also explode the guessed space into concrete per-dependency version assignments (see {@link GuessExplodeOptions}) */
readonly explode?: GuessExplodeOptions;
}
/** how to explode the guessed constraint space into concrete version assignments */
export interface GuessExplodeOptions {
/** iterate each dependency's versions newest-first (default) or oldest-first */
readonly order?: 'newest' | 'oldest';
/** a version to prefer per dependency when it survives the constraints (package name to version) */
readonly prefer?: Readonly<Record<string, VersionString>>;
/** cap the number of combinations considered; the ones that cannot be loaded together are skipped, not returned */
readonly limit?: number;
}
/** one concrete version choice per resolvable dependency (`package -> version`) */
export interface VersionAssignmentView {
readonly versions: Readonly<Record<string, VersionString>>;
/** see {@link VersionAssignment.unverified}: requirements on packages this assignment does not choose */
readonly unverified?: readonly string[];
}
/** the default cap on how many surviving candidate versions are listed per dependency */
export declare const DefaultCandidateCap = 16;
/** where a single bound on a dependency's version came from (the {@link DerivedConstraint} source, from the resolver) */
export type GuessEvidenceSource = ConstraintSource;
/**
* The resolver's {@link DerivedConstraint} with its {@link DerivedConstraint.at|call site} resolved to a readable
* location, so the evidence answers not only "it must be `>= 4.2.0` because it calls `filter(.by=)`" but also where.
*/
export interface GuessVersionEvidence extends DerivedConstraint {
/** the location of the call that carried the evidence, e.g. `12:3` or `helper.R:12:3` */
readonly location?: string;
}
/** why a package is reported as an orphan: the call that would be undefined without it, and how it was picked */
export interface OrphanEvidenceView {
/** the undefined function that is called, e.g. `ggplot` */
readonly function: string;
/** where it is called, e.g. `12:3` */
readonly location?: string;
/** why this package and not another exporter of the name */
readonly reason: OrphanReason;
/** how many packages export the name */
readonly exporters: number;
}
/** one package an orphan call could have meant instead, with the versions of it that fit those calls */
export interface OrphanAlternativeView {
readonly package: string;
/** the version range of this package that would accept the orphan calls, in the notation {@link GuessedDependency.range} uses */
readonly range: string;
readonly minVersion?: string;
readonly maxVersion?: string;
readonly candidateCount: number;
readonly totalVersions: number;
}
/** the guessed version range of one dependency */
export interface GuessedDependency {
readonly package: string;
/** whether this is an R-core / base package (then its version *is* the R version) */
readonly base: boolean;
/** the raw version constraints declared for the package (`>= 1.0.0`, a lockfile pin, ...) */
readonly declaredConstraints: readonly string[];
/** the resulting range, e.g. `>=1.0.0 <=1.1.4`, an exact `1.1.4`, or `*` when nothing constrains it */
readonly range: string;
readonly minVersion?: VersionString;
readonly maxVersion?: VersionString;
/** how many candidate versions survived every constraint */
readonly candidateCount: number;
/** how many versions the database carries in total for the package (the history the candidates are drawn from) */
readonly totalVersions?: number;
/** the surviving candidate versions, ascending (capped, see {@link GuessDepVersionsQuery.maxCandidates}) */
readonly candidates?: readonly VersionString[];
/** whether the listed {@link candidates} were capped */
readonly truncated?: boolean;
readonly evidence: readonly GuessVersionEvidence[];
/** set when the constraints contradict each other so that no version can satisfy them all */
readonly unsatisfiable?: boolean;
/** the other packages this one shares a version with, so its range is not independent of theirs */
readonly linkedWith?: readonly string[];
/**
* The other packages whose version requirements this one's version choice interacts with, so the two cannot be
* picked independently (`A 0.2.5` requiring `B == 0.2.1` while `A 0.3.0` requires `B == 0.3.2`). A partner marked
* `(partial)` only requires (or is required by) this package in some of their versions.
*/
readonly coupledWith?: readonly string[];
/**
* Whether the analyzed code actually uses this package (a declared-but-never-used dependency is unconstrained):
* either a direct call, or the project's own NAMESPACE registering an S3 method for a class this package OWNS
* (see `PackageSignatureSource.classOwner`), e.g. tseries's `S3method("as.irts","zoo")` marks `zoo` used with
* no direct `zoo::`/`library(zoo)` call.
*/
readonly used?: boolean;
/**
* Set to `false` when the signature database has no record of the package at all (e.g. a Bioconductor package),
* distinguishing it from one the database carries but cannot constrain. Such a package has no `minVersion`/`maxVersion`
* and never appears in {@link GuessDepVersionsQueryResult.assignments}, so a consumer should resolve it by other means.
*/
readonly known?: boolean;
/**
* Set to `false` when nothing narrowed the package: every version the database holds survives, so the range
* merely restates what is available. Its {@link minVersion}/{@link maxVersion} then say nothing about the code
* (an era read off the minimum would be the database's oldest release, not the script's), which a range that
* happens to end at the newest version does not reveal on its own.
*/
readonly constrained?: boolean;
/**
* Set when this package was inferred purely from *orphan* calls: bare calls (`ggplot()`) that flowR could not
* resolve and that no loaded package defines, but whose name is exported by exactly this one package in the
* signature database. The symbol would be undefined were the package not loaded, so a downstream handler may
* attach `library(package)`. See {@link orphanFunctions} for the calls that implicated it.
*/
readonly orphan?: boolean;
/** the undefined orphan function names that inferred this package (only set when {@link orphan}), e.g. `['ggplot']` */
readonly orphanFunctions?: readonly string[];
/** per {@link orphanFunctions} entry, where the undefined call is and why it was pinned on this package */
readonly orphanEvidence?: readonly OrphanEvidenceView[];
/**
* The other packages that export the {@link orphanFunctions}, each with the versions of it that would fit the
* calls. Attributing an orphan is a guess: the most downloaded exporter wins, and these are the ones it beat,
* so whoever reads the result can pick another. Ordered as the guess ranked them, best first.
*/
readonly orphanAlternatives?: readonly OrphanAlternativeView[];
}
export interface GuessDepVersionsQueryResult extends BaseQueryResult {
readonly dependencies: readonly GuessedDependency[];
/** the effective date cutoff that was applied (ISO `YYYY-MM-DD`), if any */
readonly dateCutoff?: string;
/** the R version the guess assumed when bounding base-R packages, if known */
readonly rVersion?: string;
/**
* Where {@link rVersion} comes from. An `engine` version is the R installation running the analysis, which
* bounds the guess without saying anything about the analyzed code, unlike a `config` pin or project `metadata`.
*/
readonly rVersionOrigin?: RVersionOrigin;
/** the configured version-selection policy the sample illustrates (newest by default; see `solver.sigdb.versionSelection`) */
readonly versionSelection?: VersionSelection;
/** version tuples that satisfy every interdependency (the base/R hub counted against each dependency) */
readonly runnableCombinations?: number;
/** the whole version space those tuples are drawn from (product of each counted factor's total versions) */
readonly possibleCombinations?: number;
/**
* The tuples the *declared* constraints alone leave, i.e. what the project already pins down before code usage and
* interdependencies are taken into account. Set only when something is declared and the `declared` source is active,
* so `runnableCombinations` relative to it says how much the guess added.
*/
readonly declaredCombinations?: number;
/** groups of packages interlinked to one shared version (the base/R group plus any configured groups), so their versions are not independent */
readonly linkedGroups?: readonly (readonly string[])[];
/** concrete version assignments, present when {@link GuessDepVersionsQuery.explode} was requested (most-preferred first) */
readonly assignments?: readonly VersionAssignmentView[];
/** a note, e.g. when the signature database is unavailable */
readonly message?: string;
}
/** parse a repl line: `[(clean[:<=YYYY])] [pkg ...] [--date YYYY.MM.DD] [--max N] [--iterations N] [--disabled <letters>] [--explode [--oldest] [--limit N] [--prefer pkg=ver ...]]` */
declare function guessDepVersionsLineParser(_output: ReplOutput, line: readonly string[], _config: FlowrConfig): ParsedQueryLine<'guess-dep-versions'>;
export declare const GuessDepVersionsQueryDefinition: {
readonly title: "Guess Dependency Versions Query";
readonly executor: typeof executeGuessDepVersionsQuery;
readonly asciiSummarizer: (formatter: OutputFormatter, _analyzer: import("../../../project/flowr-analyzer").ReadonlyFlowrAnalysisProvider<import("../../../r-bridge/parser").KnownParser>, queryResults: BaseQueryResult, result: string[], _query: readonly import("../../query").Query[]) => true;
readonly fromLine: typeof guessDepVersionsLineParser;
readonly syntax: "@guess-dep-versions [<pkg> ...] [(clean | <=YYYY.MM.DD)] [--date YYYY.MM.DD] [--max <n>] [--iterations <n>] [--disabled <letters>] [--explode [--oldest] [--limit <n>] [--prefer <pkg>=<ver>]] <code | file://path>";
readonly schema: Joi.ObjectSchema<any>;
readonly flattenInvolvedNodes: () => NodeId[];
};
export {};