UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

100 lines (94 loc) 4.72 kB
"use strict"; 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