@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
100 lines (94 loc) • 4.72 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.printDfGraph = printDfGraph;
exports.formatSideEffect = formatSideEffect;
exports.printDfGraphForCode = printDfGraphForCode;
exports.verifyExpectedSubgraph = verifyExpectedSubgraph;
const default_pipelines_1 = require("../../core/steps/pipeline/default-pipelines");
const decorate_1 = require("../../r-bridge/lang-4.x/ast/model/processing/decorate");
const assert_1 = require("../../util/assert");
const time_1 = require("../../util/text/time");
const doc_files_1 = require("./doc-files");
const doc_code_1 = require("./doc-code");
const flowr_analyzer_context_1 = require("../../project/context/flowr-analyzer-context");
const df_helper_1 = require("../../dataflow/graph/df-helper");
const call_graph_1 = require("../../dataflow/graph/call-graph");
/**
* Visualizes the dataflow graph as a mermaid graph inside a markdown code block.
* Please use this only for documentation purposes, for programmatic usage use {@link graphToMermaid} directly.
*/
function printDfGraph(graph, mark, simplified = false) {
return `
${(0, doc_code_1.codeBlock)('mermaid', df_helper_1.Dataflow.visualize.mermaid.convert({
graph,
prefix: 'flowchart LR',
mark,
simplified
}).string)}
`;
}
/**
* Visualizes a side effect for documentation purposes.
*/
function formatSideEffect(ef) {
if (typeof ef === 'object') {
return `${ef.id} (linked)`;
}
else {
return `${ef}`;
}
}
/**
* Visualizes the dataflow graph of the given R code using the given parser.
* This function returns a markdown string containing the dataflow graph as a mermaid code block,
* along with the R code itself in a collapsible section.
*/
async function printDfGraphForCode(parser, code, { callGraph = false, simplified = false, mark, showCode = true, codeOpen = false, exposeResult, switchCodeAndGraph = false } = {}) {
const now = performance.now();
const result = await (0, default_pipelines_1.createDataflowPipeline)(parser, {
context: (0, flowr_analyzer_context_1.contextFromInput)(code)
}).allRemainingSteps();
const duration = performance.now() - now;
if (switchCodeAndGraph) {
(0, assert_1.guard)(showCode, 'can not switch code and graph if code is not shown');
}
const metaInfo = `The analysis required _${(0, time_1.printAsMs)(duration)}_ (including parse and normalize, using the [${parser.name}](${doc_files_1.FlowrWikiBaseRef}/Engines) engine) within the generation environment.`;
const graph = callGraph ? call_graph_1.CallGraph.compute(result.dataflow.graph) : result.dataflow.graph;
const dfGraph = printDfGraph(graph, mark, simplified);
const simplyText = simplified ? '(simplified) ' : '';
const graphName = callGraph ? 'Call Graph' : 'Dataflow Graph';
let resultText = '\n\n';
if (showCode) {
const codeText = (0, doc_code_1.codeBlock)('r', code);
resultText += switchCodeAndGraph ? codeText : dfGraph;
resultText += `
<details${codeOpen ? ' open' : ''}>
<summary style="color:gray">${switchCodeAndGraph ? `${simplyText}${graphName} of the R Code` : `R Code of the ${simplyText}${graphName}`}</summary>
${metaInfo} ${mark ? `The following marks are used in the graph to highlight sub-parts (uses ids): {${[...mark].join(', ')}}.` : ''}
We encountered ${graph.unknownSideEffects.size > 0 ? 'unknown side effects (with ids: ' + [...graph.unknownSideEffects].map(formatSideEffect).join(', ') + ')' : 'no unknown side effects'} during the analysis.
${switchCodeAndGraph ? dfGraph : codeText}
</details>
`;
}
else {
resultText += dfGraph + '\n(' + metaInfo + ')\n\n';
}
return exposeResult ? [resultText, result] : resultText;
}
/** returns resolved expected df graph */
async function verifyExpectedSubgraph(parser, code, expectedSubgraph) {
const context = (0, flowr_analyzer_context_1.contextFromInput)(code);
/* we verify that we get what we want first! */
const info = await (0, default_pipelines_1.createDataflowPipeline)(parser, {
context: context,
getId: (0, decorate_1.deterministicCountingIdGenerator)(0)
}).allRemainingSteps();
expectedSubgraph.setIdMap(info.normalize.idMap);
expectedSubgraph = df_helper_1.Dataflow.resolveGraphCriteria(expectedSubgraph, context);
const report = df_helper_1.Dataflow.diffGraphs({ name: 'expected', graph: expectedSubgraph }, { name: 'got', graph: info.dataflow.graph }, {
leftIsSubgraph: true
});
(0, assert_1.guard)(report.isEqual(), () => `report:\n * ${report.comments()?.join('\n * ') ?? ''}`);
return expectedSubgraph;
}
//# sourceMappingURL=doc-dfg.js.map