@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
132 lines • 6.22 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.queryStarCommand = exports.queryCommand = void 0;
const ansi_1 = require("../../../util/text/ansi");
const query_1 = require("../../../queries/query");
const retriever_1 = require("../../../r-bridge/retriever");
const query_print_1 = require("../../../queries/query-print");
const json_1 = require("../../../util/json");
const args_1 = require("../../../util/text/args");
function printHelp(output) {
output.stderr(`Format: ${(0, ansi_1.italic)(':query <query> <code>', output.formatter)}`);
output.stdout('Queries starting with \'@<type>\' are interpreted as a query of the given type.');
output.stdout(`With this, ${(0, ansi_1.bold)(':query @config', output.formatter)} prints the result of the config query.`);
output.stdout(`If you want to run the linter on a project use:\n ${(0, ansi_1.bold)(':query @linter file://<path>', output.formatter)}.`);
output.stdout((0, ansi_1.ansiInfo)('Otherwise, you can also directly pass the query json. Then, the query is an array of query objects to represent multiple queries.'));
output.stdout((0, ansi_1.ansiInfo)('The example') + (0, ansi_1.italic)(String.raw `:query "[{\"type\": \"call-context\", \"callName\": \"mean\" }]" mean(1:10)`, output.formatter, { color: 7 /* Colors.White */, effect: ansi_1.ColorEffect.Foreground }) + (0, ansi_1.ansiInfo)('would return the call context of the mean function.'));
output.stdout('Please have a look at the wiki for more info: https://github.com/flowr-analysis/flowr/wiki/Query-API');
}
async function processQueryArgs(output, analyzer, remainingArgs) {
const query = remainingArgs.shift();
if (!query) {
output.stderr('No query provided, use \':query help\' to get more information.');
return;
}
if (query === 'help') {
printHelp(output);
return;
}
let parsedQuery;
let input;
if (query.startsWith('@')) {
const queryName = query.slice(1);
const queryObj = query_1.SupportedQueries[queryName];
if (queryObj?.fromLine) {
const parseResult = queryObj.fromLine(output, remainingArgs, analyzer.flowrConfig);
const q = parseResult.query;
parsedQuery = q ? (Array.isArray(q) ? q : [q]) : [];
input = parseResult.rCode;
}
else {
parsedQuery = [{ type: query.slice(1) }];
input = remainingArgs.join(' ').trim();
}
const validationResult = (0, query_1.QueriesSchema)().validate(parsedQuery);
if (validationResult.error) {
output.stderr(`Invalid query: "${output.formatter.format(JSON.stringify(parsedQuery), { style: 3 /* FontStyles.Italic */, color: 3 /* Colors.Yellow */, effect: ansi_1.ColorEffect.Foreground })}"`);
for (const line of validationResult.error.details) {
const value = line.context?.value ? JSON.stringify(line.context.value) : undefined;
output.stderr(` - ${line.message} ${value ? '(' + (0, ansi_1.italic)(value, output.formatter) + ')' : ''}`);
const ctx = line.context;
for (const detail of ctx?.details?.slice(0, ctx.details.length - 1) ?? []) {
if ('context' in detail && 'message' in detail.context) {
const lines = detail.context.message.split('. ');
for (const l of lines) {
output.stderr(` - ${l.trim()}`);
}
}
}
}
return;
}
}
else if (query.startsWith('[')) {
parsedQuery = JSON.parse(query);
const validationResult = (0, query_1.QueriesSchema)().validate(parsedQuery);
if (validationResult.error) {
output.stderr(`Invalid query: ${validationResult.error.message}`);
printHelp(output);
return;
}
input = remainingArgs.join(' ').trim();
}
else {
parsedQuery = [{ type: 'call-context', callName: query }];
}
if (input) {
analyzer.reset();
analyzer.addRequest(input);
}
return {
query: await (0, query_1.executeQueries)({
analyzer,
}, parsedQuery),
parsedQuery,
analyzer
};
}
/**
* Function for splitting the input line.
* All input is treated as arguments, no R code is separated so that the individual queries can handle it.
* @param line - The input line
*/
function parseArgs(line) {
const args = (0, args_1.splitAtEscapeSensitive)(line);
return {
rCode: undefined,
remaining: args
};
}
exports.queryCommand = {
description: `Query the given R code, start with '${retriever_1.fileProtocol}' to indicate a file. The query is to be a valid query in json format (use 'help' to get more information).`,
isCodeCommand: true,
usageExample: ':query "<query>" <code>',
aliases: [],
script: false,
argsParser: parseArgs,
fn: async ({ output, analyzer, remainingArgs }) => {
const totalStart = Date.now();
const results = await processQueryArgs(output, analyzer, remainingArgs);
const totalEnd = Date.now();
if (results) {
output.stdout(await (0, query_print_1.asciiSummaryOfQueryResult)(ansi_1.ansiFormatter, totalEnd - totalStart, results.query, results.analyzer, results.parsedQuery));
}
}
};
exports.queryStarCommand = {
description: 'Similar to query, but returns the output in json format.',
isCodeCommand: true,
usageExample: ':query* <query> <code>',
aliases: [],
script: false,
argsParser: parseArgs,
fn: async ({ output, analyzer, remainingArgs }) => {
const results = await processQueryArgs(output, analyzer, remainingArgs);
if (results) {
const json = Object.fromEntries(Object.entries(results.query)
.map(([query, queryResults]) => [query, query_1.SupportedQueries[query]?.jsonFormatter?.(queryResults) ?? queryResults]));
output.stdout(JSON.stringify(json, json_1.jsonReplacer));
}
}
};
//# sourceMappingURL=repl-query.js.map