UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

137 lines 7.56 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DependenciesQueryDefinition = exports.DefaultDependencyCategories = exports.Unknown = void 0; exports.getAllCategories = getAllCategories; const ansi_1 = require("../../../util/text/ansi"); const time_1 = require("../../../util/text/time"); const joi_1 = __importDefault(require("joi")); const dependencies_query_executor_1 = require("./dependencies-query-executor"); const library_functions_1 = require("./function-info/library-functions"); const source_functions_1 = require("./function-info/source-functions"); const read_functions_1 = require("./function-info/read-functions"); const write_functions_1 = require("./function-info/write-functions"); const visualize_functions_1 = require("./function-info/visualize-functions"); const type_1 = require("../../../r-bridge/lang-4.x/ast/model/type"); const test_functions_1 = require("./function-info/test-functions"); const identifier_1 = require("../../../dataflow/environments/identifier"); const r_project_1 = require("../../../r-bridge/lang-4.x/ast/model/nodes/r-project"); const model_1 = require("../../../r-bridge/lang-4.x/ast/model/model"); exports.Unknown = 'unknown'; exports.DefaultDependencyCategories = { 'library': { queryDisplayName: 'Libraries', functions: library_functions_1.LibraryFunctions, defaultValue: exports.Unknown, /* for libraries, we have to additionally track all uses of `::` and `:::`, for this we currently simply traverse all uses */ additionalAnalysis: async (data, ignoreDefault, _functions, _queryResults, result) => { if (!ignoreDefault) { r_project_1.RProject.visitAst((await data.analyzer.normalize()).ast, node => { let ns; if (node.type === type_1.RType.Symbol && (ns = identifier_1.Identifier.getNamespace(node.content)) !== undefined) { const dep = data.analyzer.inspectContext().deps.getDependency(ns); /* we should improve the identification of ':::' */ result.push({ nodeId: node.info.id, functionName: model_1.RNode.lexeme(node).includes(':::') ? ':::' : '::', value: ns, versionConstraints: dep?.versionConstraints, derivedVersion: dep?.derivedVersion, namespaceInfo: dep?.namespaceInfo }); } }); } } }, 'source': { queryDisplayName: 'Sourced Files', functions: source_functions_1.SourceFunctions, defaultValue: exports.Unknown }, 'read': { queryDisplayName: 'Read Data', functions: read_functions_1.ReadFunctions, defaultValue: exports.Unknown }, 'write': { queryDisplayName: 'Written Data', functions: write_functions_1.WriteFunctions, defaultValue: 'stdout' }, 'visualize': { queryDisplayName: 'Visualizations', functions: visualize_functions_1.VisualizeFunctions }, 'test': { queryDisplayName: 'Tests', functions: test_functions_1.TestFunctions } }; function printResultSection(title, infos, result) { if (infos.length <= 0) { return; } result.push(` ╰ ${title}`); const grouped = infos.reduce(function (groups, i) { const array = groups.get(i.functionName); if (array) { array.push(i); } else { groups.set(i.functionName, [i]); } return groups; }, new Map()); for (const [functionName, infos] of grouped) { result.push(` ╰ \`${functionName}\``); result.push(infos.map(i => ` ╰ Node Id: ${i.nodeId}${i.value !== undefined ? `, \`${i.value}\`` : ''}${i.derivedVersion !== undefined ? `, Version: \`${i.derivedVersion.format()}\`` : ''}${i.linkedIds ? `, linked: [${i.linkedIds.join(', ')}]` : ''}`).join('\n')); } } /** * Gets all dependency categories, including user-defined additional categories. */ function getAllCategories(queries) { let categories = exports.DefaultDependencyCategories; for (const query of queries) { if (query.additionalCategories) { categories = { ...categories, ...query.additionalCategories }; } } return categories; } const functionInfoSchema = joi_1.default.array().items(joi_1.default.object({ name: joi_1.default.string().required().description('The name of the library function.'), package: joi_1.default.string().optional().description('The package name of the library function'), argIdx: joi_1.default.number().optional().description('The index of the argument that contains the library name.'), argName: joi_1.default.string().optional().description('The name of the argument that contains the library name.'), })).optional(); exports.DependenciesQueryDefinition = { executor: dependencies_query_executor_1.executeDependenciesQuery, asciiSummarizer: (formatter, _analyzer, queryResults, result, queries) => { const out = queryResults; result.push(`Query: ${(0, ansi_1.bold)('dependencies', formatter)} (${(0, time_1.printAsMs)(out['.meta'].timing, 0)})`); for (const [category, value] of Object.entries(getAllCategories(queries))) { printResultSection(value.queryDisplayName ?? category, out[category] ?? [], result); } return true; }, schema: joi_1.default.object({ type: joi_1.default.string().valid('dependencies').required().description('The type of the query.'), ignoreDefaultFunctions: joi_1.default.boolean().optional().description('Should the set of functions that are detected by default be ignored/skipped? Defaults to false.'), ...Object.fromEntries(Object.keys(exports.DefaultDependencyCategories).map(c => [`${c}Functions`, functionInfoSchema.description(`The set of ${c} functions to search for.`)])), enabledCategories: joi_1.default.array().optional().items(joi_1.default.string()).description('A set of flags that determines what types of dependencies are searched for. If unset, all dependency types are searched for.'), additionalCategories: joi_1.default.object().allow(joi_1.default.object({ queryDisplayName: joi_1.default.string().description('The display name in the query result.'), functions: functionInfoSchema.description('The functions that this additional category should search for.'), defaultValue: joi_1.default.string().description('The default value to return when there is no value to gather from the function information.').optional() })).description('A set of additional, user-supplied dependency categories, whose results will be included in the query return value.').optional() }).description('The dependencies query retrieves and returns the set of all dependencies in the dataflow graph, which includes libraries, sourced files, read data, and written data.'), flattenInvolvedNodes: (queryResults, query) => { const out = queryResults; return Object.keys(getAllCategories(query)).flatMap(c => out[c] ?? []).map(o => o.nodeId); } }; //# sourceMappingURL=dependencies-query-format.js.map