UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

107 lines 5.3 kB
"use strict"; 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