UNPKG

@eagleoutice/flowr-dev

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

196 lines (195 loc) 13.2 kB
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 {};