@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
119 lines • 5.41 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.asciiCallContext = asciiCallContext;
exports.summarizeIdsIfTooLong = summarizeIdsIfTooLong;
exports.asciiSummaryOfQueryResult = asciiSummaryOfQueryResult;
const ansi_1 = require("../util/text/ansi");
const query_1 = require("./query");
const node_id_1 = require("../r-bridge/lang-4.x/ast/model/processing/node-id");
const html_hover_over_1 = require("../util/html-hover-over");
const time_1 = require("../util/text/time");
const model_1 = require("../r-bridge/lang-4.x/ast/model/model");
function nodeString(nodeId, formatter, idMap) {
const isObj = typeof nodeId === 'object' && nodeId !== null && 'id' in nodeId;
const id = isObj ? nodeId?.id : nodeId;
const info = isObj ? nodeId?.info : undefined;
if (node_id_1.NodeId.isBuiltIn(id)) {
return (0, ansi_1.italic)(id, formatter) + (info ? ` (${JSON.stringify(info)})` : '');
}
const node = idMap.get(id);
if (node === undefined) {
return `UNKNOWN: ${id} (info: ${JSON.stringify(info)})`;
}
return `${(0, ansi_1.italic)('`' + (model_1.RNode.lexeme(node) ?? 'UNKNOWN') + '`', formatter)} (L.${node.location?.[0]}${info ? ', ' + JSON.stringify(info) : ''})`;
}
function asciiCallContextSubHit(formatter, results, idMap) {
const result = [];
for (const { id, calls = [], linkedIds = [], aliasRoots = [] } of results.slice(0, 20)) {
const node = idMap.get(id);
if (node === undefined) {
result.push(` ${(0, ansi_1.bold)('UNKNOWN: ' + JSON.stringify({ calls, linkedIds }))}`);
continue;
}
let line = nodeString(id, formatter, idMap);
if (calls.length > 0) {
line += ` with ${calls.length} call${calls.length > 1 ? 's' : ''} (${calls.map(c => nodeString(c, formatter, idMap)).join(', ')})`;
}
if (linkedIds.length > 0) {
line += ` with ${linkedIds.length} link${linkedIds.length > 1 ? 's' : ''} (${linkedIds.map(c => nodeString(c, formatter, idMap)).join(', ')})`;
}
if (aliasRoots.length > 0) {
line += ` with ${aliasRoots.length} alias root${aliasRoots.length > 1 ? 's' : ''} (${aliasRoots.map(c => nodeString(c, formatter, idMap)).join(', ')})`;
}
result.push(line);
}
if (results.length > 20) {
result.push(` ... and ${results.length - 20} more hits`);
}
return result.join(', ');
}
/**
* Converts call context query results to an ASCII representation
*/
function asciiCallContext(formatter, results, idMap) {
/* traverse over 'kinds' and within them 'subkinds' */
const result = [];
for (const [kind, { subkinds }] of Object.entries(results['kinds'])) {
const amountOfHits = Object.values(subkinds).reduce((acc, cur) => acc + cur.length, 0);
result.push(` ╰ ${(0, ansi_1.bold)(kind, formatter)} (${amountOfHits} hit${amountOfHits === 1 ? '' : 's'}):`);
for (const [subkind, values] of Object.entries(subkinds)) {
const amountOfSubHits = values.length;
result.push(` ╰ ${(0, ansi_1.bold)(subkind, formatter)} (${amountOfSubHits} hit${amountOfSubHits === 1 ? '' : 's'}): ${asciiCallContextSubHit(formatter, values, idMap)}`);
}
}
return result.join('\n');
}
/**
* Summarizes a list of node IDs, shortening the output if it is too long
* @example
* ```ts
* summarizeIdsIfTooLong(markdownFormatter, ['id1', 'id2', 'id3']);
* // returns 'id1, id2, id3'
* summarizeIdsIfTooLong(markdownFormatter, [<array of many ids>]);
* // returns 'id1, id2, id3, ... (see JSON)' with a tooltip containing the full JSON array
* ```
*/
function summarizeIdsIfTooLong(formatter, ids) {
const naive = ids.join(', ');
if (naive.length <= 20) {
return naive;
}
let acc = '';
let i = 0;
while (acc.length <= 20) {
acc += ids[i++] + ', ';
}
if (i < ids.length) {
acc += '... (see JSON)';
}
return formatter === ansi_1.markdownFormatter ? (0, html_hover_over_1.textWithTooltip)(acc, JSON.stringify(ids)) : acc;
}
/**
* Generates an ASCII summary of the given query results
*/
async function asciiSummaryOfQueryResult(formatter, totalInMs, results, analyzer, queries) {
const result = [];
for (const [query, queryResults] of Object.entries(results)) {
if (query === '.meta') {
continue;
}
const queryType = query_1.SupportedQueries[query];
const relevantQueries = queries.filter(q => q.type === query);
if (await queryType.asciiSummarizer(formatter, analyzer, queryResults, result, relevantQueries)) {
continue;
}
result.push(`Query: ${(0, ansi_1.bold)(query, formatter)}`);
let timing = -1;
for (const [key, value] of Object.entries(queryResults)) {
if (key === '.meta') {
timing = value.timing;
continue;
}
result.push(` ╰ ${key}: ${JSON.stringify(value)}`);
}
result.push(` - Took ${(0, time_1.printAsMs)(timing, 0)}`);
}
result.push((0, ansi_1.italic)(`All queries together required ≈${(0, time_1.printAsMs)(results['.meta'].timing, 0)} (1ms accuracy, total ${(0, time_1.printAsMs)(totalInMs, 0)})`, formatter));
return formatter.format(result.join('\n'));
}
//# sourceMappingURL=query-print.js.map