@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
145 lines • 7.76 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LinterQueryDefinition = void 0;
const joi_1 = __importDefault(require("joi"));
const linter_query_executor_1 = require("./linter-query-executor");
const linter_rules_1 = require("../../../linter/linter-rules");
const linter_format_1 = require("../../../linter/linter-format");
const ansi_1 = require("../../../util/text/ansi");
const time_1 = require("../../../util/text/time");
const doc_code_1 = require("../../../documentation/doc-util/doc-code");
const retriever_1 = require("../../../r-bridge/retriever");
const assert_1 = require("../../../util/assert");
function rulesFromInput(output, rulesPart) {
return rulesPart
.reduce((acc, ruleName) => {
ruleName = ruleName.trim();
if (ruleName in linter_rules_1.LintingRules) {
acc.valid.push(ruleName);
}
else {
acc.invalid.push(ruleName);
}
return acc;
}, { valid: [], invalid: [] });
}
const rulesPrefix = 'rules:';
function linterQueryLineParser(output, line, _config) {
let rules = undefined;
let input = undefined;
if (line.length > 0 && line[0].startsWith(rulesPrefix)) {
const rulesPart = line[0].slice(rulesPrefix.length).split(',');
const parseResult = rulesFromInput(output, rulesPart);
if (parseResult.invalid.length > 0) {
output.stderr(`Invalid linting rule name(s): ${parseResult.invalid.map(r => (0, ansi_1.bold)(r, output.formatter)).join(', ')}`
+ `\nValid rule names are: ${Object.keys(linter_rules_1.LintingRules).map(r => (0, ansi_1.bold)(r, output.formatter)).join(', ')}`);
}
rules = parseResult.valid;
input = line[1];
}
else if (line.length > 0) {
input = line[0];
}
return { query: [{ type: 'linter', rules: rules }], rCode: input };
}
function linterQueryCompleter(line, startingNewArg, _config) {
const rulesPrefixNotPresent = line.length == 0 || (line.length == 1 && line[0].length < rulesPrefix.length);
const rulesNotFinished = line.length == 1 && line[0].startsWith(rulesPrefix) && !startingNewArg;
const endOfRules = line.length == 1 && startingNewArg || line.length == 2;
if (rulesPrefixNotPresent) {
return { completions: [`${rulesPrefix}`] };
}
else if (endOfRules) {
return { completions: [retriever_1.fileProtocol] };
}
else if (rulesNotFinished) {
const rulesWithoutPrefix = line[0].slice(rulesPrefix.length);
const usedRules = rulesWithoutPrefix.split(',').map(r => r.trim());
const allRules = Object.keys(linter_rules_1.LintingRules);
const unusedRules = allRules.filter(r => !usedRules.includes(r));
const lastRule = usedRules[usedRules.length - 1];
const lastRuleIsUnfinished = !allRules.includes(lastRule);
if (lastRuleIsUnfinished) {
// Return all rules that have not been added yet
return { completions: unusedRules, argumentPart: lastRule };
}
else if (unusedRules.length > 0) {
// Add a comma, if the current last rule is complete
return { completions: [','], argumentPart: '' };
}
else {
// All rules are used, complete with a space
return { completions: [' '], argumentPart: '' };
}
}
return { completions: [] };
}
exports.LinterQueryDefinition = {
executor: linter_query_executor_1.executeLinterQuery,
asciiSummarizer: (formatter, analyzer, queryResults, result) => {
const out = queryResults;
result.push(`Query: ${(0, ansi_1.bold)('linter', formatter)} (${(0, time_1.printAsMs)(out['.meta'].timing, 0)})`);
const allDidFail = Object.values(out.results).every(linter_format_1.LintingResults.isError);
if (allDidFail) {
result.push('All linting rules failed to execute.');
if (analyzer.inspectContext().files.loadingOrder.getUnorderedRequests().length === 0) {
result.push(formatter.format('No requests to lint for were found in the analysis.', { color: 1 /* Colors.Red */, effect: ansi_1.ColorEffect.Foreground, style: 1 /* FontStyles.Bold */ }));
result.push('If you consider this an error, please report a bug: ' + (0, assert_1.getGuardIssueUrl)('analyzer found no requests to lint for'));
}
else if (Object.values(out.results).length === 1) {
const fst = Object.values(out.results)[0];
result.push('Error: ' + linter_format_1.LintingResults.stringifyError(fst));
if (fst.error instanceof Error) {
// print stack
result.push('Stack Trace:\n' + fst.error.stack);
}
}
result.push('If you consider this an error that should be fixed, please report a bug: ' + (0, assert_1.getGuardIssueUrl)('linting rule threw an error'));
return true;
}
for (const [ruleName, results] of Object.entries(out.results)) {
addLintingRuleResult(ruleName, results, result);
}
return true;
},
completer: linterQueryCompleter,
fromLine: linterQueryLineParser,
schema: joi_1.default.object({
type: joi_1.default.string().valid('linter').required().description('The type of the query.'),
rules: joi_1.default.array().items(joi_1.default.string().valid(...Object.keys(linter_rules_1.LintingRules)), joi_1.default.object({
name: joi_1.default.string().valid(...Object.keys(linter_rules_1.LintingRules)).required(),
config: joi_1.default.object()
})).description('The rules to lint for. If unset, all rules will be included.')
}).description('The linter query lints for the given set of rules and returns the result.'),
flattenInvolvedNodes: (queryResults) => {
const out = queryResults;
return Object.values(out.results).flatMap(v => Array.from(linter_format_1.LintingResults.allInvolvedIds(v))).filter(assert_1.isNotUndefined);
}
};
function addLintingRuleResult(ruleName, results, result) {
const rule = linter_rules_1.LintingRules[ruleName];
result.push(` ╰ **${rule.info.name}** (${ruleName}):`);
if (linter_format_1.LintingResults.isError(results)) {
const error = linter_format_1.LintingResults.stringifyError(results).includes('At least one request must be set') ? 'No requests to lint for were found in the analysis.' : 'Error during execution of rule: ' + linter_format_1.LintingResults.stringifyError(results);
result.push(` ╰ ${error}`);
return;
}
for (const certainty of [linter_format_1.LintingResultCertainty.Certain, linter_format_1.LintingResultCertainty.Uncertain]) {
const certaintyResults = results.results.filter(r => r.certainty === certainty);
if (certaintyResults.length) {
result.push(` ╰ ${certainty}:`);
for (const res of certaintyResults) {
const pretty = rule.prettyPrint[linter_format_1.LintingPrettyPrintContext.Query](res, results['.meta']);
result.push(` ╰ ${pretty}${res.quickFix ? ` (${res.quickFix.length} quick fix(es) available)` : ''}`);
}
}
}
result.push(` ╰ _Metadata_: ${(0, doc_code_1.codeInline)(renderMetaData(results['.meta']))}`);
}
function renderMetaData(metadata) {
return Object.entries(metadata).map(r => `${r[0]}: ${JSON.stringify(r[1])}`).join(', ');
}
//# sourceMappingURL=linter-query-format.js.map