UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

115 lines 4.61 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getDocumentationOf = getDocumentationOf; const roxygen_ast_1 = require("./roxygen-ast"); const type_1 = require("../lang-4.x/ast/model/type"); const roxygen_parse_1 = require("./roxygen-parse"); const CommentRetriever = { [type_1.RType.Comment]: n => (0, roxygen_parse_1.parseRoxygenComment)([n.lexeme]), [type_1.RType.Parameter]: (n, idMap) => { // get the documentation of the parent function const doc = n.info.parent ? getDocumentationOf(n.info.parent, idMap) : undefined; const paramName = n.lexeme; if (doc && paramName) { if (Array.isArray(doc)) { const res = doc.filter(t => t.type === roxygen_ast_1.KnownRoxygenTags.Param && t.value.name === paramName); if (res.length === 1) { return res[0]; } else { return res; } } else { if (doc.type === roxygen_ast_1.KnownRoxygenTags.Param && doc.value.name === paramName) { return doc; } } } return undefined; } }; /** * Given a normalized AST and a node ID, returns the Roxygen documentation (if any) associated with that node. * Please note that this does more than {@link parseRoxygenCommentsOfNode}, as it also traverses up the AST to find documentation. * Additionally, this function instruments the normalized AST to cache the parsed documentation for future queries. * @param idMap - The AST ID map to use for looking up nodes and traversing the AST. * @param nodeId - The ID of the node to get documentation for. */ function getDocumentationOf(nodeId, idMap) { const node = idMap.get(nodeId); if (!node) { return undefined; } else if ('doc' in node.info) { return node.info.doc; } const retriever = CommentRetriever[node.type] ?? ((c, a) => (0, roxygen_parse_1.parseRoxygenCommentsOfNode)(c, a)?.tags); const doc = retriever(node, idMap); if (doc) { // to avoid endless recursion, we block the caching here once: node.info.doc = undefined; // cache the documentation for future queries const expanded = expandInheritsOfTags(doc, idMap); node.info.doc = expanded; return expanded; } return doc; } function expandInheritsOfTags(tags, idMap) { const expandedTags = []; const tagArray = Array.isArray(tags) ? tags : [tags]; for (const tag of tagArray) { const expanded = expandInheritOfTag(tag, tagArray, idMap); if (!expanded) { continue; } if (Array.isArray(expanded)) { expandedTags.push(...expanded); } else { expandedTags.push(expanded); } } if (expandedTags.length === 1) { return expandedTags[0]; } return expandedTags; } function getDocumentationOfByName(name, idMap) { for (const [, node] of idMap) { const nodeName = node.lexeme ?? node.info.fullLexeme; if (nodeName !== name) { continue; } return getDocumentationOf(node.info.id, idMap); } } function filterDocumentationForParams(doc, filter) { if (!doc) { return doc; } if (Array.isArray(doc)) { return doc.filter(filter); } else { return filter(doc) ? doc : undefined; } } function expandInheritOfTag(tag, otherTags, idMap) { if (tag.type === roxygen_ast_1.KnownRoxygenTags.Inherit) { const inheritDoc = getDocumentationOfByName(tag.value.source, idMap); return filterDocumentationForParams(inheritDoc, t => tag.value.components.includes(t.type)); } else if (tag.type === roxygen_ast_1.KnownRoxygenTags.InheritDotParams) { const inheritDoc = getDocumentationOfByName(tag.value.source, idMap); return filterDocumentationForParams(inheritDoc, t => t.type === roxygen_ast_1.KnownRoxygenTags.Param && t.value.name === '...'); } else if (tag.type === roxygen_ast_1.KnownRoxygenTags.InheritParams) { const inheritDoc = getDocumentationOfByName(tag.value, idMap); const alreadyExplainedParams = new Set(otherTags.filter(t => t.type === roxygen_ast_1.KnownRoxygenTags.Param).map(t => t.value.name)); return filterDocumentationForParams(inheritDoc, t => t.type === roxygen_ast_1.KnownRoxygenTags.Param && !alreadyExplainedParams.has(t.value.name)); } return tag; } //# sourceMappingURL=documentation-provider.js.map