@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
107 lines • 5.3 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.staticRequests = staticRequests;
exports.extractUsageStatistics = extractUsageStatistics;
const xmldom_1 = require("@xmldom/xmldom");
const fs_1 = __importDefault(require("fs"));
const meta_statistics_1 = require("./meta-statistics");
const log_1 = require("../util/log");
const json_1 = require("../util/json");
const pipeline_executor_1 = require("../core/pipeline-executor");
const default_pipelines_1 = require("../core/steps/pipeline/default-pipelines");
const feature_1 = require("./features/feature");
const convert_values_1 = require("../r-bridge/lang-4.x/convert-values");
/**
* By default, {@link extractUsageStatistics} requires a generator, but sometimes you already know all the files
* that you want to process. This function simply reps your requests as a generator.
*/
function staticRequests(...requests) {
// eslint-disable-next-line @typescript-eslint/require-await
return async function* () {
for (const request of requests) {
yield request;
}
}();
}
/**
* Extract all wanted statistic information from a set of requests using the presented R session.
*
* @param shell - The R session to use
* @param onRequest - A callback that is called at the beginning of each request, this may be used to debug the requests.
* @param features - The features to extract (see {@link allFeatureNames}).
* @param requests - The requests to extract the features from. May generate them on demand (e.g., by traversing a folder).
* If your request is statically known, you can use {@link staticRequests} to create this generator.
* @param rootPath - The root path to the project, this is used to relativize the file paths in the statistics.
*/
async function extractUsageStatistics(shell, onRequest, features, requests, rootPath) {
let result = initializeFeatureStatistics();
const meta = (0, meta_statistics_1.initialMetaStatistics)();
const outputs = new Map();
for await (const request of requests) {
onRequest(request);
const start = performance.now();
const suffix = request.request === 'file' ? request.content.replace(new RegExp('^' + (rootPath ?? '')), '') : undefined;
try {
let output;
({ stats: result, output } = await extractSingle(result, shell, request, features, suffix));
outputs.set(request, output);
processMetaOnSuccessful(meta, request);
meta.numberOfNormalizedNodes.push(output.normalize.idMap.size);
}
catch (e) {
log_1.log.error('for request: ', request, e);
processMetaOnUnsuccessful(meta, request);
}
meta.processingTimeMs.push(performance.now() - start);
}
return { features: result, meta, outputs };
}
function initializeFeatureStatistics() {
const result = {};
for (const key of feature_1.allFeatureNames) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
result[key] = JSON.parse(JSON.stringify(feature_1.ALL_FEATURES[key].initialValue, json_1.jsonReplacer), json_1.jsonBigIntRetriever);
}
return result;
}
function processMetaOnUnsuccessful(meta, request) {
meta.failedRequests.push(request);
}
function processMetaOnSuccessful(meta, request) {
meta.successfulParsed++;
if (request.request === 'text') {
meta.lines.push(request.content.split('\n').map(l => l.length));
}
else {
meta.lines.push(fs_1.default.readFileSync(request.content, 'utf-8').split('\n').map(l => l.length));
}
}
const parser = new xmldom_1.DOMParser();
async function extractSingle(result, shell, request, features, suffixFilePath) {
const slicerOutput = await new pipeline_executor_1.PipelineExecutor(default_pipelines_1.DEFAULT_DATAFLOW_PIPELINE, {
request, parser: shell
}).allRemainingSteps();
// retrieve parsed xml through (legacy) xmlparsedata
const suffix = request.request === 'file' ? ', encoding="utf-8"' : '';
shell.sendCommands(`try(flowr_parsed<-parse(${request.request}=${JSON.stringify(request.content)},keep.source=TRUE${suffix}),silent=FALSE)`, 'try(flowr_output<-xmlparsedata::xml_parse_data(flowr_parsed,includeText=TRUE,pretty=FALSE),silent=FALSE)');
const parsed = (await shell.sendCommandWithOutput(`cat(flowr_output,${(0, convert_values_1.ts2r)(shell.options.eol)})`)).join(shell.options.eol);
const doc = parser.parseFromString(parsed, 'text/xml');
// eslint-disable-next-line @typescript-eslint/no-explicit-any
for (const [key, feature] of Object.entries(feature_1.ALL_FEATURES)) {
if (features !== 'all' && !features.has(key)) {
continue;
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
result[key] = feature.process(result[key], {
parsedRAst: doc,
dataflow: slicerOutput.dataflow,
normalizedRAst: slicerOutput.normalize,
filepath: suffixFilePath
});
}
return { stats: result, output: slicerOutput };
}
//# sourceMappingURL=statistics.js.map