@eagleoutice/flowr-dev
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
62 lines • 3.48 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.FlowrAnalyzerPackageVersionsSessionInfoPlugin = exports.sessionInfoLog = void 0;
const flowr_analyzer_package_versions_plugin_1 = require("./flowr-analyzer-package-versions-plugin");
const semver_1 = require("semver");
const package_1 = require("./package");
const flowr_file_1 = require("../../context/flowr-file");
const log_1 = require("../../../util/log");
exports.sessionInfoLog = log_1.log.getSubLogger({ name: 'flowr-analyzer-package-versions-session-info-plugin' });
/** matches the `R version 4.3.1 (2023-06-16)` line of `sessionInfo()`/`sessionInfo` output */
const rVersionRe = /\bR version\s+(\d+\.\d+\.\d+)/;
/** the section headers `sessionInfo()` prints right before a `[n] pkg_version ...` package listing */
const packageHeaderRe = /\b(?:other attached packages|loaded via a namespace \(and not attached\))\s*:/;
/** an `[n] ...` listing line as printed by R for a vector of packages (the `[n]` may itself be commented out) */
const packageListingLineRe = /\[\d+\]\s*(.+)$/gm;
/** a single `name_version` token within a listing line, e.g. `dplyr_1.1.2` or `data.table_1.14.8` */
const packageTokenRe = /([A-Za-z][A-Za-z0-9.]*)_(\d+(?:[.-]\d+)+)/g;
function pin(ctx, name, version) {
const range = package_1.Package.parsePkgVersionRange(undefined, version);
ctx.deps.addDeclaredDependency(new package_1.Package({ name, versionConstraints: range ? [range] : undefined }));
}
/**
* Reads package (and R) versions from a pasted `sessionInfo()` output block within a source file (typically inside
* a comment). This is how R users record a reproducible environment, so when present it pins exact versions, just
* like a lockfile. Detection is conservative: we only act once we see the `R version` line and/or one of
* `sessionInfo()`'s package-listing headers, and additionally require at least one `pkg_version` token so unrelated
* text is not misread.
*/
class FlowrAnalyzerPackageVersionsSessionInfoPlugin extends flowr_analyzer_package_versions_plugin_1.FlowrAnalyzerPackageVersionsPlugin {
name = 'flowr-analyzer-package-versions-session-info-plugin';
description = 'Extracts package and R versions from a pasted sessionInfo() output block.';
version = new semver_1.SemVer('0.1.0');
process(ctx) {
for (const file of ctx.files.getFilesByRole(flowr_file_1.FileRole.Source)) {
this.processContent(ctx, file.content().toString());
}
}
processContent(ctx, content) {
const rVersionMatch = rVersionRe.exec(content);
if (!rVersionMatch && !packageHeaderRe.test(content)) {
return;
}
const packages = new Map();
for (const line of content.matchAll(packageListingLineRe)) {
for (const token of line[1].matchAll(packageTokenRe)) {
packages.set(token[1], token[2]);
}
}
if (packages.size === 0) {
exports.sessionInfoLog.debug('Found sessionInfo() markers but no package version tokens, skipping.');
return;
}
if (rVersionMatch) {
pin(ctx, 'R', rVersionMatch[1]);
}
for (const [name, version] of packages) {
pin(ctx, name, version);
}
}
}
exports.FlowrAnalyzerPackageVersionsSessionInfoPlugin = FlowrAnalyzerPackageVersionsSessionInfoPlugin;
//# sourceMappingURL=flowr-analyzer-package-versions-session-info-plugin.js.map