@eagleoutice/flowr-dev
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
133 lines • 5.34 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MemorySignatureSource = void 0;
exports.memorySourceOfPackages = memorySourceOfPackages;
const r_version_1 = require("../../util/r-version");
const reader_1 = require("./reader");
const r_base_packages_1 = require("../../util/r-base-packages");
/** what {@link LibraryExports.version} says when the source was given no version to claim */
const UnknownVersion = '';
/**
* A signature source held entirely in memory, for the places that cannot open a database file: a browser
* (the playground bundles its packages rather than reading them) and a test that wants to state a package's
* exports outright. It answers what a package brings into scope; the per-function view a real database
* decodes from its blobs is not part of what it can say, so those answers stay empty.
* @see {@link SigDatabase} - the file-backed source
*/
class MemorySignatureSource {
packages;
/** reverse index `class -> owning package`, built on first use (see {@link classOwner}) */
classIndex;
constructor(packages) {
this.packages = packages instanceof Map ? packages : new Map(Object.entries(packages));
}
has(pkg) {
return this.packages.has(pkg);
}
hasVersion(pkg, version) {
const known = this.versionOf(pkg);
return known !== UnknownVersion && known === version;
}
isCranVersion(pkg, version) {
return this.hasVersion(pkg, version);
}
lookup(pkg, version) {
const found = this.packages.get(pkg);
/* a source given no version has one answer and gives it whatever is asked for: it cannot say no */
if (found === undefined || !this.answersFor(pkg, version)) {
return undefined;
}
return {
version: this.versionOf(pkg),
exported: found.exported,
internal: [],
deprecated: found.deprecated ?? [],
s3Classes: found.s3Classes ?? [],
s4Classes: found.s4Classes ?? [],
cran: true
};
}
packagesExporting(name) {
return [...this.packages]
.filter(([, p]) => p.exported.includes(name))
.sort(([an, a], [bn, b]) => (b.downloads ?? 0) - (a.downloads ?? 0) || an.localeCompare(bn))
.map(([pkg]) => pkg);
}
classOwner(className, version) {
if (version !== undefined) {
return this.packageNames().find(pkg => {
const lib = this.lookup(pkg, version);
return (lib?.s3Classes.includes(className) ?? false) || (lib?.s4Classes.includes(className) ?? false);
});
}
this.classIndex ??= (0, reader_1.classOwnerIndexFor)(this, this.packageNames());
return this.classIndex.get(className);
}
/** no blobs to decode, so the rich per-function view has nothing to give */
functions() {
return undefined;
}
functionByName() {
return undefined;
}
transitiveCallees() {
return undefined;
}
dependencies(pkg, version) {
const found = this.packages.get(pkg);
if (found === undefined || !this.answersFor(pkg, version)) {
return undefined;
}
return [...found.deps ?? []];
}
packageNames() {
return [...this.packages.keys()];
}
isBaseR(pkg) {
return (0, r_base_packages_1.baseRPackages)().includes(pkg);
}
downloads(pkg) {
return this.packages.get(pkg)?.downloads ?? 0;
}
/** the R releases a base package shipped with are a property of the database, which this source has none of */
coreVersions() {
return undefined;
}
releaseDate(pkg) {
return this.packages.get(pkg)?.released;
}
releaseDates(pkg) {
const version = this.latestVersion(pkg);
const date = this.releaseDate(pkg);
return version === undefined || date === undefined ? [] : [{ version, date }];
}
latestVersion(pkg) {
const known = this.versionOf(pkg);
return known === UnknownVersion ? undefined : r_version_1.RVersion.parse(known);
}
/** nothing is held open */
close() {
/* nothing to release */
}
/** whether the package answers a lookup for `version`, which an unversioned one always does */
answersFor(pkg, version) {
return version === undefined || this.versionOf(pkg) === UnknownVersion || this.versionOf(pkg) === version;
}
versionOf(pkg) {
return this.packages.get(pkg)?.version ?? UnknownVersion;
}
}
exports.MemorySignatureSource = MemorySignatureSource;
/**
* A {@link MemorySignatureSource} from what a page can carry: `package -> [version, release date, ...exports]`.
* The version is what the exports were read from, so recording it is what keeps a consumer from being told
* the package is unknown when only its history is.
*/
function memorySourceOfPackages(packages) {
return new MemorySignatureSource(Object.fromEntries(Object.entries(packages).map(([pkg, [version = '', released = '', ...exported]]) => [pkg, {
exported,
version: version.length > 0 ? version : undefined,
released: released.length > 0 ? new Date(released) : undefined
}])));
}
//# sourceMappingURL=memory-source.js.map