UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

661 lines 29.9 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.mermaidHide = void 0; exports.getTypeScriptSourceFiles = getTypeScriptSourceFiles; exports.dropGenericsFromTypeName = dropGenericsFromTypeName; exports.removeCommentSymbolsFromTypeScriptComment = removeCommentSymbolsFromTypeScriptComment; exports.getStartLineOfTypeScriptNode = getStartLineOfTypeScriptNode; exports.getTypePathLink = getTypePathLink; exports.visualizeMermaidClassDiagram = visualizeMermaidClassDiagram; exports.getTypesFromFolder = getTypesFromFolder; exports.printHierarchy = printHierarchy; exports.printCodeOfElement = printCodeOfElement; exports.shortLink = shortLink; exports.shortLinkFile = shortLinkFile; exports.getDocumentationForType = getDocumentationForType; const typescript_1 = __importStar(require("typescript")); const assert_1 = require("../../util/assert"); const doc_files_1 = require("./doc-files"); const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const doc_code_1 = require("./doc-code"); const doc_structure_1 = require("./doc-structure"); const html_hover_over_1 = require("../../util/html-hover-over"); const doc_general_1 = require("./doc-general"); const mermaid_1 = require("../../util/mermaid/mermaid"); const options = { target: typescript_1.default.ScriptTarget.ESNext, skipLibCheck: true, skipDefaultLibCheck: true, allowJs: true, strict: false, checkJs: false, strictNullChecks: false, noUncheckedIndexedAccess: false, noUncheckedSideEffectImports: false, noCheck: true, noEmit: true, noResolve: true, noUnusedLocals: false, alwaysStrict: true, incremental: false, types: [], lib: [], noLib: true, moduleResolution: typescript_1.default.ModuleResolutionKind.Classic, allowUnreachableCode: true, allowUnusedLabels: true, disableSolutionSearching: true, }; /** * Retrieve TypeScript source files from the given file names. */ function getTypeScriptSourceFiles(fileNames) { try { const program = typescript_1.default.createProgram(fileNames, options); return { program, files: fileNames.map(fileName => program.getSourceFile(fileName)).filter(file => !!file) }; } catch (err) { console.error('Failed to get source files', err); return { files: [], program: undefined }; } } const DropGenericsPattern = /<.*>/g; /** * Drop generics from a TypeScript type name. * @example * ```ts * const typeName = 'MyType<T, U>'; * const cleanName = dropGenericsFromTypeName(typeName); * console.log(cleanName); // 'MyType' * ``` */ function dropGenericsFromTypeName(type) { let previous; do { previous = type; type = type.replace(DropGenericsPattern, ''); } while (type !== previous); return type; } const PruneDocCommentPattern = /^\/\*\*?|\*\/$|^\s*\*\s?|\s*\*$/gm; const PrunedocLinkPattern = /\{@[a-zA-Z]+ ([^}]+\|)?(?<name>[^}]+)}/gm; /** * Remove comment symbols from a TypeScript comment string. * This also takes care of special JSDoc tags like `{@link ...}` and `{@see ...}`. * @example * ```ts * const comment = '/**\n* This is a comment.\n* It has multiple lines.\n *\/'; // closing comment sadly escaped for ts doc * const cleaned = removeCommentSymbolsFromTypeScriptComment(comment); * console.log(cleaned); * ``` * This will output: * ```md * This is a comment. * It has multiple lines. * ``` */ function removeCommentSymbolsFromTypeScriptComment(comment) { return comment // remove '/** \n * \n */... .replace(PruneDocCommentPattern, '') // replace {@key foo|bar} with `bar` and {@key foo} with `foo` .replace(PrunedocLinkPattern, '<code>$<name></code>') .trim(); } function getTextualCommentsFromTypeScript(node) { const comments = typescript_1.default.getJSDocCommentsAndTags(node); const out = []; for (const { comment } of comments) { if (typeof comment === 'string') { out.push(removeCommentSymbolsFromTypeScriptComment(comment)); } else if (comment !== undefined) { for (const c of comment) { out.push(removeCommentSymbolsFromTypeScriptComment(c.getText(c.getSourceFile()))); } } } return out; } /** * */ function getStartLineOfTypeScriptNode(node, sourceFile) { const lineStart = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line; return lineStart + 1; } function hasModifier(modifiers, modifier) { return modifiers.some(mod => typeof mod === 'object' && mod !== null && 'kind' in mod && mod.kind === modifier); } function formatNode(node, sourceFile, typeChecker) { const name = node.name?.getText(sourceFile); let prefix = '', suffix = ''; if ('modifiers' in node && Array.isArray(node.modifiers)) { if (hasModifier(node.modifiers, typescript_1.SyntaxKind.PrivateKeyword)) { prefix = '-'; } else if (hasModifier(node.modifiers, typescript_1.SyntaxKind.ProtectedKeyword)) { prefix = '#'; } else if (hasModifier(node.modifiers, typescript_1.SyntaxKind.PublicKeyword)) { prefix = '+'; } if (hasModifier(node.modifiers, typescript_1.SyntaxKind.AbstractKeyword)) { suffix = '*'; } else if (hasModifier(node.modifiers, typescript_1.SyntaxKind.StaticKeyword)) { suffix = '$'; } } const type = getType(node, typeChecker); const typeAnnotation = type.includes('=>') ? type.replaceAll(/\s+=>\s+/g, ' ') : ': ' + type; return `${prefix}${mermaid_1.Mermaid.escape(name + typeAnnotation)}${suffix}`; } function getType(node, typeChecker) { const tryDirect = typeChecker.getTypeAtLocation(node); return tryDirect ? typeChecker.typeToString(tryDirect) : 'unknown'; } const defaultSkip = ['Pick', 'Partial', 'Required', 'Readonly', 'Omit', 'DeepPartial', 'DeepReadonly', 'DeepWritable', 'StrictOmit']; function followTypeReference(type, sourceFile) { const node = type.typeName; if (typescript_1.default.isQualifiedName(node)) { return [node.right.getText(sourceFile) ?? '']; } const args = type.typeArguments?.map(arg => arg.getText(sourceFile)) ?? []; const nodeLexeme = node.getText(sourceFile) ?? ''; const baseLexeme = type.getText(sourceFile) ?? ''; if (defaultSkip.map(s => nodeLexeme.startsWith(s))) { return [baseLexeme, ...args]; } return [nodeLexeme, baseLexeme, ...args]; } function collectHierarchyInformation(sourceFiles, options) { const hierarchyList = []; const typeChecker = options.program.getTypeChecker(); const visit = (node, sourceFile) => { if (!node) { return; } if (typescript_1.default.isInterfaceDeclaration(node)) { const interfaceName = node.name?.getText(sourceFile) ?? ''; const baseTypes = node.heritageClauses?.flatMap(clause => clause.types .map(type => type.getText(sourceFile) ?? '') .map(dropGenericsFromTypeName)) ?? []; const generics = node.typeParameters?.map(param => param.getText(sourceFile) ?? '') ?? []; hierarchyList.push({ name: dropGenericsFromTypeName(interfaceName), node, kind: 'interface', extends: baseTypes, generics, comments: getTextualCommentsFromTypeScript(node), filePath: sourceFile.fileName, lineNumber: getStartLineOfTypeScriptNode(node, sourceFile), properties: node.members.map(member => formatNode(member, sourceFile, typeChecker)), }); } else if (typescript_1.default.isTypeAliasDeclaration(node)) { const typeName = node.name?.getText(sourceFile) ?? ''; let baseTypes = []; if (typescript_1.default.isIntersectionTypeNode(node.type) || typescript_1.default.isUnionTypeNode(node.type)) { baseTypes = node.type.types .filter(typeNode => typescript_1.default.isTypeReferenceNode(typeNode)) .flatMap(typeName => followTypeReference(typeName, sourceFile)) .map(dropGenericsFromTypeName); } else if (typescript_1.default.isTypeReferenceNode(node.type)) { baseTypes = followTypeReference(node.type, sourceFile).map(dropGenericsFromTypeName); } const generics = node.typeParameters?.map(param => param.getText(sourceFile) ?? '') ?? []; hierarchyList.push({ name: dropGenericsFromTypeName(typeName), node, kind: 'type', extends: baseTypes, comments: getTextualCommentsFromTypeScript(node), generics, filePath: sourceFile.fileName, lineNumber: getStartLineOfTypeScriptNode(node, sourceFile), }); } else if (typescript_1.default.isEnumDeclaration(node)) { const enumName = node.name?.getText(sourceFile) ?? ''; hierarchyList.push({ name: dropGenericsFromTypeName(enumName), node, kind: 'enum', extends: [], comments: getTextualCommentsFromTypeScript(node), generics: [], filePath: sourceFile.fileName, lineNumber: getStartLineOfTypeScriptNode(node, sourceFile), properties: node.members.map(member => formatNode(member, sourceFile, typeChecker)) }); } else if (typescript_1.default.isEnumMember(node)) { const typeName = node.parent.name?.getText(sourceFile) ?? ''; const enumName = dropGenericsFromTypeName(typeName); hierarchyList.push({ name: dropGenericsFromTypeName(node.name.getText(sourceFile)), node, kind: 'enum', extends: [enumName], comments: getTextualCommentsFromTypeScript(node), generics: [], filePath: sourceFile.fileName, lineNumber: getStartLineOfTypeScriptNode(node, sourceFile), }); } else if (typescript_1.default.isClassDeclaration(node)) { const className = node.name?.getText(sourceFile) ?? ''; const baseTypes = node.heritageClauses?.flatMap(clause => clause.types .map(type => type.getText(sourceFile) ?? '') .map(dropGenericsFromTypeName)) ?? []; const generics = node.typeParameters?.map(param => param.getText(sourceFile) ?? '') ?? []; hierarchyList.push({ name: dropGenericsFromTypeName(className), node, kind: 'class', extends: baseTypes, comments: getTextualCommentsFromTypeScript(node), generics, filePath: sourceFile.fileName, lineNumber: getStartLineOfTypeScriptNode(node, sourceFile), properties: node.members .filter(member => member.name !== undefined) .map(member => formatNode(member, sourceFile, typeChecker)), }); } else if (typescript_1.default.isVariableDeclaration(node) || typescript_1.default.isExportDeclaration(node) || typescript_1.default.isExportAssignment(node) || typescript_1.default.isDeclarationStatement(node)) { const name = node.name?.getText(sourceFile) ?? ''; const comments = getTextualCommentsFromTypeScript(node); hierarchyList.push({ name: dropGenericsFromTypeName(name), node, kind: 'variable', extends: [], comments, generics: [], filePath: sourceFile.fileName, lineNumber: getStartLineOfTypeScriptNode(node, sourceFile), }); } else if (typescript_1.default.isPropertyAssignment(node) || typescript_1.default.isPropertyDeclaration(node) || typescript_1.default.isPropertySignature(node) || typescript_1.default.isMethodDeclaration(node) || typescript_1.default.isMethodSignature(node) || typescript_1.default.isFunctionDeclaration(node) || typescript_1.default.isGetAccessorDeclaration(node) || typescript_1.default.isSetAccessorDeclaration(node)) { const name = node.name?.getText(sourceFile) ?? ''; // get the name of the object/enclosing type let parent = node.parent; while (typeof parent === 'object' && parent !== undefined && !('name' in parent)) { parent = parent.parent; } if (typeof parent === 'object' && 'name' in parent) { const comments = getTextualCommentsFromTypeScript(node); hierarchyList.push({ name: dropGenericsFromTypeName(name), node, kind: 'variable', extends: [parent.name?.getText(sourceFile) ?? ''], comments, generics: [], filePath: sourceFile.fileName, lineNumber: getStartLineOfTypeScriptNode(node, sourceFile), }); } } typescript_1.default.forEachChild(node, child => visit(child, sourceFile)); }; for (const sf of sourceFiles) { visit(sf, sf); } return hierarchyList; } function getTypePathForTypeScript({ filePath }) { return filePath.replace(/^.*\/src\//, 'src/').replace(/^.*\/test\//, 'test/'); } /** * Return the link to the type in the source code. * If you create a wiki, please refer to the functions provided by the {@link GeneralWikiContext}. */ function getTypePathLink(elem, prefix = doc_files_1.RemoteFlowrFilePathBaseRef) { const fromSource = getTypePathForTypeScript(elem); return `${prefix}/${fromSource}#L${elem.lineNumber}`; } function generateMermaidClassDiagram(hierarchyList, rootName, options, visited = new Set()) { const collect = { nodeLines: [], edgeLines: [] }; if (visited.has(rootName)) { return collect; } // Prevent circular references visited.add(rootName); const node = hierarchyList.find(h => h.name === rootName); if (!node) { return collect; } const genericPart = node.generics.length > 0 ? `~${node.generics.join(', ')}~` : ''; collect.nodeLines.push(`class ${node.name}${genericPart}{`); collect.nodeLines.push(` <<${node.kind}>>`); const writtenProperties = new Set(); if (!options.simplify && node.properties) { for (const property of node.properties) { collect.nodeLines.push(` ${property}`); writtenProperties.add(property); } } collect.nodeLines.push('}'); if (node.kind === 'type') { collect.nodeLines.push(`style ${node.name} opacity:.35,fill:#FAFAFA`); } collect.nodeLines.push(`click ${node.name} href "${getTypePathLink(node)}" "${mermaid_1.Mermaid.escape(node.comments?.join('; ').replace(/\n/g, ' ') ?? '')}"`); const inline = [...options.inlineTypes ?? [], ...defaultSkip]; let baseTypes = node.extends; if (options.reverse) { baseTypes = hierarchyList .filter(e => e.kind === 'class' || e.kind === 'interface' || e.kind === 'type' || e.kind === 'enum') .filter(e => e.extends.includes(rootName)) .map(e => e.name); } if (baseTypes.length > 0) { for (const baseType of baseTypes) { if (inline.includes(baseType)) { const info = hierarchyList.find(h => h.name === baseType); for (const property of info?.properties ?? []) { if (!writtenProperties.has(property)) { collect.nodeLines.push(` ${node.name} : ${property} [from ${baseType}]`); writtenProperties.add(property); } } } else { if (node.kind === 'type' || hierarchyList.find(h => h.name === baseType)?.kind === 'type') { collect.edgeLines.push(`${dropGenericsFromTypeName(baseType)} .. ${node.name}`); } else { collect.edgeLines.push(`${dropGenericsFromTypeName(baseType)} ${options.reverse ? '--|>' : '<|--'} ${node.name}`); } const { nodeLines, edgeLines } = generateMermaidClassDiagram(hierarchyList, baseType, options, visited); collect.nodeLines.push(...nodeLines); collect.edgeLines.push(...edgeLines); } } } return collect; } /** * Visualize the type hierarchy as a mermaid class diagram. */ function visualizeMermaidClassDiagram(hierarchyList, options) { if (!options.typeNameForMermaid) { return undefined; } const { nodeLines, edgeLines } = generateMermaidClassDiagram(hierarchyList, options.typeNameForMermaid, options); return nodeLines.length === 0 && edgeLines.length === 0 ? '' : ` --- config: class: hideEmptyMembersBox: true --- classDiagram direction ${options.reverse ? 'LR' : 'RL'} ${nodeLines.join('\n')} ${edgeLines.join('\n')} `; } function getTypesFromFileAsMermaid(fileNames, options) { const { files, program } = getTypeScriptSourceFiles(fileNames); (0, assert_1.guard)(files.length > 0, () => `No source files found for ${JSON.stringify(fileNames)}`); const withProgram = { ...options, program }; const hierarchyList = collectHierarchyInformation(files, withProgram); return { mermaid: visualizeMermaidClassDiagram(hierarchyList, withProgram), info: hierarchyList, program }; } /** * Inspect typescript source code for types and return a report. */ function getTypesFromFolder(options) { (0, assert_1.guard)(options.rootFolder !== undefined || options.files !== undefined, 'Either rootFolder or files must be provided'); let files = [...options.files ?? []]; if (options.rootFolder) { const folders = Array.isArray(options.rootFolder) ? options.rootFolder : [options.rootFolder]; for (const folder of folders) { files = files.concat(fs_1.default.readdirSync(folder, { recursive: true }) .filter(f => { const p = f.toString(); return p.endsWith('.ts') && !p.endsWith('.test.ts') && !p.endsWith('-app.ts') && !p.endsWith('.d.ts'); }) .map(f => path_1.default.join(folder, f.toString()))); } } return getTypesFromFileAsMermaid(files, options); } function implSnippet(node, program, showName = true, nesting = 0, open = false, showImplSnippet = true) { (0, assert_1.guard)(node !== undefined, 'Node must be defined => invalid change of type name?'); const indent = ' '.repeat(nesting * 2); const bold = node.kind === 'interface' || node.kind === 'enum' ? '**' : ''; const sep = node.comments ? ' \n' : '\n'; let text = node.comments?.join('\n') ?? ''; if (text.trim() !== '') { text = ' ' + text; } if (showImplSnippet) { const code = node.node.getFullText(program.getSourceFile(node.node.getSourceFile().fileName)); text += `\n<details${open ? ' open' : ''}><summary style="color:gray">Defined at <a href="${getTypePathLink(node)}">${getTypePathLink(node, '.')}</a></summary>\n\n${(0, doc_code_1.codeBlock)('ts', code)}\n\n</details>\n`; } else { text += `\n<br/><i>(Defined at <a href="${getTypePathLink(node)}">${getTypePathLink(node, '.')}</a>)</i>\n`; } const init = showName ? `* ${bold}[${node.name}](${getTypePathLink(node)})${bold} ${sep}${indent}` : ''; return ` ${indent}${showName ? init : ''} ${text.replaceAll('\t', ' ').split(/\n/g).join(`\n${indent} `)}`; } exports.mermaidHide = ['MergeableRecord', 'Leaf', 'Location', 'Namespace', 'Base', 'WithChildren', 'Partial', 'RAccessBase']; /** * Print the hierarchy of types starting from the given root. * If you create a wiki, please refer to the functions provided by the {@link GeneralWikiContext}. */ function printHierarchy({ program, info, root, ignoredTypes, collapseFromNesting = 1, initialNesting = 0, maxDepth = 20, skipNesting = 0, openTop, showImplSnippet = true, reverse = false }) { if (initialNesting > maxDepth) { return ''; } const node = info.find(e => e.name === root); if (!node) { return ''; } let thisLine = ''; if (initialNesting >= skipNesting) { thisLine = implSnippet(node, program, true, initialNesting, initialNesting === 0 && openTop, showImplSnippet); } let baseTypes = node.extends; if (reverse) { baseTypes = info .filter(e => e.kind === 'class' || e.kind === 'interface') .filter(e => e.extends.includes(root)) .map(e => e.name); } const result = []; for (const baseType of baseTypes) { if (exports.mermaidHide.includes(baseType) || ignoredTypes?.includes(baseType)) { continue; } const res = printHierarchy({ program, info, root: baseType, ignoredTypes, collapseFromNesting, initialNesting: initialNesting + 1, maxDepth, skipNesting, showImplSnippet, reverse }); result.push(res); } const out = result.join('\n'); if (initialNesting >= collapseFromNesting - 1) { const more = baseTypes.length > 4 ? baseTypes.slice(0, 4).join(', ') + ', ...' : baseTypes.join(', '); return thisLine + (out ? (0, doc_structure_1.details)(`View more (${more})`, out, { prefixInit: ' '.repeat(2 * (initialNesting + 2)) }) : ''); } else { return thisLine + (out ? '\n' + out : ''); } } /** * Print an element from the info as code block. * If you create a wiki, please refer to the functions provided by the {@link GeneralWikiContext}. * * This is great to show examples that are directly taken from the source code. */ function printCodeOfElement({ program, info, dropLinesEnd = 0, dropLinesStart = 0, doNotAutoGobble, hideDefinedAt }, name) { const node = info.find(e => e.name === name); if (!node) { console.error(`Could not find node ${name} when resolving function!`); return ''; } let code = node.node.getFullText(program.getSourceFile(node.node.getSourceFile().fileName)).trim(); if (dropLinesStart > 0 || dropLinesEnd > 0) { const lines = code.split(/\n/g); if (dropLinesStart + dropLinesEnd >= lines.length) { return ''; } code = lines.slice(dropLinesStart, lines.length - dropLinesEnd).join('\n'); } if (!doNotAutoGobble) { // gobble leading spaces const lines = code.replaceAll('\t', ' ').split(/\n/g); let gobble = Number.POSITIVE_INFINITY; for (const line of lines) { const match = line.match(/^(\s*)\S+/); if (match) { gobble = Math.min(gobble, match[1].length); } } if (gobble !== Number.POSITIVE_INFINITY && gobble > 0) { code = lines.map(line => line.startsWith(' '.repeat(gobble)) ? line.slice(gobble) : line).join('\n'); } } if (hideDefinedAt) { return (0, doc_code_1.codeBlock)('ts', code); } else { return `${(0, doc_code_1.codeBlock)('ts', code)}\n<i>Defined at <a href="${getTypePathLink(node)}">${getTypePathLink(node, '.')}</a></i>\n`; } } function fuzzyCompare(a, b) { const aStr = a.toLowerCase().replace(/[^a-z0-9]/g, '-').trim(); const bStr = b.toLowerCase().replace(/[^a-z0-9]/g, '-').trim(); return aStr === bStr || aStr.includes(bStr) || bStr.includes(aStr); } function retrieveNode(name, hierarchy, fuzzy = false, type = undefined) { let container = undefined; if (name.includes('::')) { [container, name] = name.split(/:::?/); } let node = hierarchy.filter(e => fuzzy ? fuzzyCompare(e.name, name) : e.name === name); if (node.length === 0) { return undefined; } else if (container) { node = node.filter(n => fuzzy ? n.extends.some(n => fuzzyCompare(n, container)) : n.extends.includes(container)); if (node.length === 0) { return undefined; } } if (type) { node = node.filter(n => n.kind === type); if (node.length === 0) { return undefined; } } return [container, name, node[0]]; } /** * Create a short link to a type in the documentation. * If you create a wiki, please refer to the functions provided by the {@link GeneralDocContext}. * @param name - The name of the type, e.g. `MyType`, may include a container, e.g.,`MyContainer::MyType` (this works with function nestings too) * Use `:::` if you want to access a scoped function, but the name should be displayed without the scope * @param hierarchy - The hierarchy of types to search in * @param codeStyle - Whether to use code style for the link * @param realNameWrapper - How to highlight the function in name in the `x::y` format? * @param fuzzy - Whether to use fuzzy matching when searching for the type * @param type - Optionally restrict to a certain type of element */ function shortLink(name, hierarchy, codeStyle = true, realNameWrapper = 'b', fuzzy, type) { const res = retrieveNode(name, hierarchy, fuzzy, type); if (!res) { console.error(`Could not find node ${name} when resolving short link!`); return ''; } const [, mainName, node] = res; let pkg = res[0]; if (name.includes(':::')) { pkg = undefined; } const comments = node.comments?.join('\n').replace(/\\?\n|```[a-zA-Z]*|\s\s*/g, ' ').replace(/<\/?code>|`/g, '').replace(/<\/?p\/?>/g, ' ').replace(/"/g, '\'') ?? ''; return `<a href="${getTypePathLink(node)}">${codeStyle ? '<code>' : ''}${(node.comments?.length ?? 0) > 0 ? (0, html_hover_over_1.textWithTooltip)(pkg ? `${pkg}::<${realNameWrapper}>${mainName}</${realNameWrapper}>` : mainName, comments.length > 400 ? comments.slice(0, 400) + '...' : comments) : pkg ? `${pkg}::<${realNameWrapper}>${mainName}</${realNameWrapper}>` : mainName}${codeStyle ? '</code>' : ''}</a>`; } /** * Create a short link to a type in the documentation. * If you create a wiki, please refer to the functions provided by the {@link GeneralWikiContext}. * @param name - The name of the type, e.g. `MyType`, may include a container, e.g.,`MyContainer::MyType` (this works with function nestings too) * Use `:::` if you want to access a scoped function, but the name should be displayed without the scope * @param hierarchy - The hierarchy of types to search in */ function shortLinkFile(name, hierarchy) { const res = retrieveNode(name, hierarchy); if (!res) { console.error(`Could not find node ${name} when resolving short link!`); return ''; } const [, , node] = res; return `<a href="${getTypePathLink(node)}">${getTypePathForTypeScript(node)}</a>`; } /** * Retrieve documentation comments for a type. * If you create a wiki, please refer to the functions provided by the {@link GeneralWikiContext}. * @param name - The name of the type, e.g. `MyType`, may include a container, e.g.,`MyContainer::MyType` (this works with function nestings too) * Use `:::` if you want to access a scoped function, but the name should be displayed without the scope * @param hierarchy - The hierarchy of types to search in * @param prefix - A prefix to add to each line of the documentation * @param filter - Optional filters for retrieving the documentation */ function getDocumentationForType(name, hierarchy, prefix = '', filter) { const res = retrieveNode(name, hierarchy, filter?.fuzzy, filter?.type); if (!res) { return ''; } const [, , node] = res; return (0, doc_general_1.prefixLines)(node.comments?.join('\n') ?? '', prefix); } //# sourceMappingURL=doc-types.js.map