UNPKG

@eagleoutice/flowr-dev

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

106 lines 5.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ROXYGEN_ARGS = void 0; const linter_format_1 = require("../linter-format"); const range_1 = require("../../util/range"); const flowr_search_builder_1 = require("../../search/flowr-search-builder"); const linter_tags_1 = require("../linter-tags"); const assert_1 = require("../../util/assert"); const vertex_1 = require("../../dataflow/graph/vertex"); const roxygen_ast_1 = require("../../r-bridge/roxygen2/roxygen-ast"); const r_function_definition_1 = require("../../r-bridge/lang-4.x/ast/model/nodes/r-function-definition"); const search_enrichers_1 = require("../../search/search-executor/search-enrichers"); function calculateArgumentDiff(inheritedParams, functionParam, roxygenParam) { //match documented against existing params let underDocumented = new Set(functionParam); const notOverDocumented = underDocumented.has('...'); let overDocumented = new Set(roxygenParam); const commonParams = underDocumented.intersection(overDocumented); underDocumented = underDocumented.difference(commonParams); overDocumented = overDocumented.difference(commonParams); //case: '...', overdocumentation not possible if (notOverDocumented) { //if still remaining overdocumented parameters, "..." doesn't need to be documented if (overDocumented.size > 0) { underDocumented.delete('...'); } //can't be overdocumented overDocumented.clear(); } //inherited params removed from list of overdocumented params overDocumented = overDocumented.difference(new Set(inheritedParams)); return underDocumented.size === 0 && overDocumented.size === 0 ? false : { under: Array.from(underDocumented), over: Array.from(overDocumented) }; } exports.ROXYGEN_ARGS = { createSearch: () => flowr_search_builder_1.Q.all() .filter(vertex_1.VertexType.FunctionDefinition) .with(search_enrichers_1.Enrichment.Roxygen), processSearchResult: (elements, _config) => { return { results: elements.getElements() .map(element => ({ element, underDocumented: [], overDocumented: [] })) .filter(({ element, underDocumented, overDocumented }) => { const roxygen = (0, search_enrichers_1.enrichmentContent)(element, search_enrichers_1.Enrichment.Roxygen); if (!roxygen.documentation.length) { return false; } //get parameter names const params = roxygen.tags[roxygen_ast_1.KnownRoxygenTags.Param] ?? []; const functionParamNames = getParameters(element.node).map(p => p.name.content.toString()); const inheritedParams = params.filter(tag => tag.inherited).map(tag => tag.value.name); const roxygenParamNames = params.map(tag => tag.value.name); const result = calculateArgumentDiff(inheritedParams ?? [], functionParamNames, roxygenParamNames); if (result === false) { return false; } underDocumented.push(...result.under); overDocumented.push(...result.over); return true; }) .map(({ element, overDocumented, underDocumented }) => ({ certainty: linter_format_1.LintingResultCertainty.Uncertain, involvedId: element.node.info.id, loc: range_1.SourceLocation.fromNode(element.node), underDocumented: underDocumented, overDocumented: overDocumented })) .filter(element => (0, assert_1.isNotUndefined)(element.loc)), '.meta': {} }; }, prettyPrint: { [linter_format_1.LintingPrettyPrintContext.Query]: result => `Function at ${range_1.SourceLocation.format(result.loc)} has ${describeArgumentDiff(result)}`, [linter_format_1.LintingPrettyPrintContext.Full]: result => `Function at ${range_1.SourceLocation.format(result.loc)} has ${describeArgumentDiff(result)}` }, info: { name: 'Roxygen Arguments', tags: [linter_tags_1.LintingRuleTag.Smell, linter_tags_1.LintingRuleTag.Documentation, linter_tags_1.LintingRuleTag.Style], certainty: linter_format_1.LintingRuleCertainty.BestEffort, description: 'Checks whether a function has undocumented or overdocumented parameters', defaultConfig: {} } }; function getParameters(node) { return r_function_definition_1.RFunctionDefinition.is(node) ? node.parameters : []; } function quoteAll(names) { return names.map(name => `'${name}'`).join(', '); } /** Describes the concrete mismatch between roxygen `@param` documentation and the actual function arguments. */ function describeArgumentDiff(result) { const parts = []; const under = result.underDocumented ?? []; const over = result.overDocumented ?? []; if (under.length > 0) { parts.push(`undocumented argument${under.length > 1 ? 's' : ''} ${quoteAll(under)}`); } if (over.length > 0) { parts.push(`documented @param${over.length > 1 ? 's' : ''} with no matching argument: ${quoteAll(over)}`); } return parts.join(', and '); } //# sourceMappingURL=roxygen-arguments.js.map