@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
115 lines • 4.61 kB
JavaScript
;
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