UNPKG

@eagleoutice/flowr-dev

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

144 lines 8.27 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.dataflowSimpleStarCommand = exports.dataflowSimplifiedCommand = exports.dataflowSilentCommand = exports.dataflowAsciiCommand = exports.dataflowStarCommand = exports.dataflowCommand = void 0; const ansi_1 = require("../../../util/text/ansi"); const core_1 = require("../core"); const repl_clipboard_1 = require("./repl-clipboard"); const vertex_1 = require("../../../dataflow/graph/vertex"); const dfg_ascii_1 = require("../../../util/simple-df/dfg-ascii"); const df_helper_1 = require("../../../dataflow/graph/df-helper"); const config_1 = require("../../../config"); const identifier_1 = require("../../../dataflow/environments/identifier"); const range_1 = require("../../../util/range"); function formatInfo(out, type, meta) { return out.formatter.format(`Copied ${type} to clipboard (dataflow: ${meta['.meta'].timing + 'ms'}).`, { color: 7 /* Colors.White */, effect: ansi_1.ColorEffect.Foreground, style: 3 /* FontStyles.Italic */ }); } function formatReference(output, ref, idMap) { const id = output.formatter.format(`$${ref.nodeId}`, { color: 6 /* Colors.Cyan */, effect: ansi_1.ColorEffect.Foreground }); const name = ref.name === undefined ? '<anonymous>' : identifier_1.Identifier.toString(ref.name); const node = idMap.get(ref.nodeId); const sl = range_1.SourceLocation.fromNode(node); const loc = sl ? ` [${range_1.SourceLocation.format(sl)}]` : ''; const detail = node ? ` "${node.lexeme ?? name}"${loc}` : ''; return `${id} ${name} (${identifier_1.ReferenceType[ref.type]})${detail}`; } /** Formats a single {@link KillReference}, which unlike a plain reference may kill the whole (or an unknown part of the) scope */ function formatKill(output, kill, idMap) { switch (kill.kind) { case 'named': return formatReference(output, kill.reference, idMap); case 'all': return 'kills entire scope'; case 'unknown': return 'kills unknown, not statically resolvable references'; } } /** * Prints the reference sets, listing each non-empty one and collapsing all empty ones into a single trailing * line, as a screen full of `(0):` headers says nothing. */ function printReferenceSections(output, sections) { const count = (n) => output.formatter.format(String(n), { color: 6 /* Colors.Cyan */, effect: ansi_1.ColorEffect.Foreground }); for (const { title, lines } of sections.filter(s => s.lines.length > 0)) { output.stdout(`${title} (${count(lines.length)}):`); for (const line of lines) { output.stdout(' - ' + line); } } const empty = sections.filter(s => s.lines.length === 0); if (empty.length > 0) { output.stdout(output.formatter.format('Empty: ', { style: 3 /* FontStyles.Italic */ }) + `${empty.map(s => `${s.title} (${count(0)})`).join(', ')}`); } } exports.dataflowCommand = { description: 'Get mermaid code for the dataflow graph', isCodeCommand: true, usageExample: ':dataflow', aliases: ['d', 'df'], script: false, argsParser: (args) => (0, core_1.handleString)(args), fn: async ({ output, analyzer }) => { const result = await analyzer.dataflow(); const mermaid = df_helper_1.Dataflow.visualize.mermaid.convert({ graph: result.graph, includeEnvironments: false, qualifyBaseR: (0, config_1.isSigDbEnabled)(analyzer.flowrConfig) }).string; await repl_clipboard_1.ReplClipboard.print(output, mermaid, formatInfo(output, 'mermaid code', result)); } }; exports.dataflowStarCommand = { description: 'Returns the URL to mermaid.live', isCodeCommand: true, usageExample: ':dataflow*', aliases: ['d*', 'df*'], script: false, argsParser: (args) => (0, core_1.handleString)(args), fn: async ({ output, analyzer }) => { const result = await analyzer.dataflow(); const mermaid = df_helper_1.Dataflow.visualize.mermaid.url(result.graph, false, undefined, false, (0, config_1.isSigDbEnabled)(analyzer.flowrConfig)); await repl_clipboard_1.ReplClipboard.print(output, mermaid, formatInfo(output, 'mermaid url', result)); } }; exports.dataflowAsciiCommand = { description: 'Returns an ASCII representation of the dataflow graph', isCodeCommand: true, usageExample: ':dataflowascii', aliases: ['df!'], script: false, argsParser: (args) => (0, core_1.handleString)(args), fn: async ({ output, analyzer }) => { const result = await analyzer.dataflow(); output.stdout((0, dfg_ascii_1.dfgToAscii)(result.graph)); } }; exports.dataflowSilentCommand = { description: 'Just calculates the DFG, but only prints summary info', isCodeCommand: true, usageExample: ':dataflowsilent', aliases: ['d#', 'df#'], script: false, argsParser: (args) => (0, core_1.handleString)(args), fn: async ({ output, analyzer }) => { const result = await analyzer.dataflow(); const numOfEdges = Array.from(result.graph.edges().flatMap(e => e[1].entries())).length; const numOfVertices = Array.from(result.graph.vertices(true)).length; output.stdout(output.formatter.format(`Dataflow calculated in ${result['.meta'].timing}ms.`, { color: 7 /* Colors.White */, effect: ansi_1.ColorEffect.Foreground, style: 3 /* FontStyles.Italic */ }) + '\n' + 'Edges: ' + output.formatter.format(`${String(numOfEdges).padStart(12)}`, { color: 6 /* Colors.Cyan */, effect: ansi_1.ColorEffect.Foreground }) + '\n' + // number of vertices and edges 'Vertices: ' + output.formatter.format(`${String(numOfVertices).padStart(12)}`, { color: 6 /* Colors.Cyan */, effect: ansi_1.ColorEffect.Foreground })); const longestVertexType = Math.max(...Object.keys(vertex_1.VertexType).map(vt => vt.length)); for (const vertType of Object.values(vertex_1.VertexType)) { const vertsOfType = Array.from(result.graph.verticesOfType(vertType)); const longVertexName = Object.entries(vertex_1.VertexType).find(([, v]) => v === vertType)?.[0] ?? vertType; output.stdout(` - ${(longVertexName + ':').padEnd(longestVertexType + 1)} ` + output.formatter.format(`${String(vertsOfType.length).padStart(8)}`, { color: 6 /* Colors.Cyan */, effect: ansi_1.ColorEffect.Foreground }).padStart(9, ' ')); } const { idMap } = await analyzer.normalize(); printReferenceSections(output, [ { title: 'In', lines: result.in.map(r => formatReference(output, r, idMap)) }, { title: 'Out', lines: result.out.map(r => formatReference(output, r, idMap)) }, { title: 'Unknown References', lines: result.unknownReferences.map(r => formatReference(output, r, idMap)) }, { title: 'Kill', lines: (result.kill ?? []).map(k => formatKill(output, k, idMap)) } ]); } }; exports.dataflowSimplifiedCommand = { description: 'Get mermaid code for the simplified dataflow graph', isCodeCommand: true, usageExample: ':dataflowsimple', aliases: ['ds', 'dfs'], script: false, argsParser: (args) => (0, core_1.handleString)(args), fn: async ({ output, analyzer }) => { const result = await analyzer.dataflow(); const mermaid = df_helper_1.Dataflow.visualize.mermaid.convert({ graph: result.graph, includeEnvironments: false, simplified: true, qualifyBaseR: (0, config_1.isSigDbEnabled)(analyzer.flowrConfig) }).string; await repl_clipboard_1.ReplClipboard.print(output, mermaid, formatInfo(output, 'mermaid code', result)); } }; exports.dataflowSimpleStarCommand = { description: 'Returns the URL to mermaid.live', isCodeCommand: true, usageExample: ':dataflowsimple*', aliases: ['ds*', 'dfs*'], script: false, argsParser: (args) => (0, core_1.handleString)(args), fn: async ({ output, analyzer }) => { const result = await analyzer.dataflow(); const mermaid = df_helper_1.Dataflow.visualize.mermaid.url(result.graph, false, undefined, true, (0, config_1.isSigDbEnabled)(analyzer.flowrConfig)); await repl_clipboard_1.ReplClipboard.print(output, mermaid, formatInfo(output, 'mermaid url', result)); } }; //# sourceMappingURL=repl-dataflow.js.map