@eagleoutice/flowr-dev
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
130 lines • 5.74 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Package = void 0;
const semver_1 = require("semver");
const assert_1 = require("../../../util/assert");
const flowr_namespace_file_1 = require("../file-plugins/files/flowr-namespace-file");
const flowr_file_1 = require("../../context/flowr-file");
const r_version_1 = require("../../../util/r-version");
const node_id_1 = require("../../../r-bridge/lang-4.x/ast/model/processing/node-id");
/**
* A package as the sources describe it, accumulated with {@link addInfo}/{@link mergeInPlace}: only those may
* change it, everything else reads. Its three version views run from the rawest to the most concrete:
* - {@link versionConstraints}: what each source declared, unmerged.
* - {@link derivedRange}: their intersection, whether or not a version can satisfy it (see
* {@link hasSatisfiableVersion}, and `inferredRange` on the dependencies context for the range that is only
* handed out once it is).
* - {@link resolvedVersion}: the one concrete version the exports were read from.
*/
class Package {
name;
_type;
_dependencies;
_namespaceInfo;
_resolvedVersion;
_versionConstraints = [];
/** the intersection of {@link versionConstraints}, computed on demand and dropped whenever one is added */
_derivedRange;
get type() {
return this._type;
}
get dependencies() {
return this._dependencies;
}
get namespaceInfo() {
return this._namespaceInfo;
}
get resolvedVersion() {
return this._resolvedVersion;
}
get versionConstraints() {
return this._versionConstraints;
}
get derivedRange() {
this._derivedRange ??= this.deriveRange();
return this._derivedRange;
}
/** {@link derivedRange} if a source declared one, else the {@link resolvedVersion} the exports were read from. */
get effectiveRange() {
return this.derivedRange ?? (this._resolvedVersion !== undefined ? r_version_1.RRange.parse('=' + this._resolvedVersion) : undefined);
}
constructor(info) {
this.name = info.name;
this.addInfo(info);
}
/** Builds a package from a raw `NAMESPACE` body and its list of callable exports. */
static fromConstants(name, namespace, callable) {
return new Package({
name,
namespaceInfo: (0, flowr_namespace_file_1.setCallable)(flowr_namespace_file_1.FlowrNamespaceFile.from(new flowr_file_1.FlowrInlineTextFile('NAMESPACE', namespace)).content().current, callable)
});
}
has(name, className) {
if (!this.namespaceInfo) {
return false;
}
// an explicit `generic`/`className` pair -> S3 method lookup
if (className) {
const classes = this.namespaceInfo.exportS3Generics.get(name);
return classes ? classes.includes(className) : false;
}
// a directly exported symbol/function - this also covers dotted plain exports such as
// `solve.QP`, `as.Date` or `read.csv` that are not S3 methods
if (this.namespaceInfo.exportedFunctions.includes(name) || this.namespaceInfo.exportedSymbols.includes(name)) {
return true;
}
// otherwise it may be an S3 method `generic.class` whose exported generic reconstructs it
if (name.includes('.')) {
const dot = name.indexOf('.');
const classes = this.namespaceInfo.exportS3Generics.get(name.slice(0, dot));
return classes ? classes.includes(name.slice(dot + 1)) : false;
}
return false;
}
s3For(generic) {
return this.namespaceInfo?.exportS3Generics.get(generic) ?? [];
}
mergeInPlace(other) {
(0, assert_1.guard)(this.name === other.name, 'Can only merge packages with the same name');
this.addInfo({
type: other.type,
dependencies: other._dependencies,
namespaceInfo: other.namespaceInfo,
versionConstraints: other._versionConstraints,
resolvedVersion: other.resolvedVersion
});
}
addInfo({ type, dependencies, namespaceInfo, versionConstraints, resolvedVersion }) {
this._resolvedVersion = resolvedVersion ?? this._resolvedVersion;
this._type = type ?? this._type;
this._dependencies = dependencies ?? this._dependencies;
this._namespaceInfo = namespaceInfo ?? this._namespaceInfo;
if (versionConstraints !== undefined && versionConstraints.length > 0) {
this._versionConstraints.push(...versionConstraints);
this._derivedRange = undefined; // re-derived on the next read, once every source has had its say
}
}
/** The combined (intersected) range of all recorded constraints, or `undefined` if none were given. */
deriveRange() {
// sources may disagree, which `hasSatisfiableVersion` reports rather than this failing
return r_version_1.RRange.intersect(this._versionConstraints);
}
/** Whether some concrete version can satisfy every recorded constraint at once. */
hasSatisfiableVersion() {
const range = this.derivedRange;
return range !== undefined && (0, semver_1.minVersion)(range) !== null;
}
static parsePkgVersionRange(constraint, version) {
if (version) {
return constraint ? r_version_1.RRange.parse(constraint + version) : r_version_1.RRange.parse(version);
}
else {
return undefined;
}
}
static functionIdentifier(dependency, func) {
return node_id_1.NodeId.pkgFnName(dependency, func);
}
}
exports.Package = Package;
//# sourceMappingURL=package.js.map