UNPKG

@compodoc/compodoc

Version:

The missing documentation tool for your Angular application

1,134 lines (1,050 loc) 114 kB
import * as path from "path"; import * as _ from '../../utils/collection.util'; import { Project, ts, SyntaxKind } from "ts-morph"; import { IsKindType, kindToType } from "../../utils/kind-to-type"; import { logger } from "../../utils/logger"; import { cleanLifecycleHooksFromMethods, markedtags, mergeTagsAndArgs, } from "../../utils/utils"; import ComponentsTreeEngine from "../engines/components-tree.engine"; import { FrameworkDependencies } from "./framework-dependencies"; import ImportsUtil from "../../utils/imports.util"; import { getModuleWithProviders, isCoverageIgnore, isIgnore, isModuleWithProviders, JsdocParserUtil, } from "../../utils"; import ExtendsMerger from "../../utils/extends-merger.util"; import RouterParserUtil from "../../utils/router-parser.util"; import { CodeGenerator } from "./angular/code-generator"; import { PublicApiFilter } from "./angular/public-api-filter"; import { ComponentDepFactory } from "./angular/deps/component-dep.factory"; import { ControllerDepFactory } from "./angular/deps/controller-dep.factory"; import { DirectiveDepFactory } from "./angular/deps/directive-dep.factory"; import { ComponentCache } from "./angular/deps/helpers/component-helper"; import { JsDocHelper } from "./angular/deps/helpers/js-doc-helper"; import { ModuleHelper } from "./angular/deps/helpers/module-helper"; import { SymbolHelper } from "./angular/deps/helpers/symbol-helper"; import { ModuleDepFactory } from "./angular/deps/module-dep.factory"; import { EntityDepFactory } from "./angular/deps/entity-dep.factory"; import Configuration from "../configuration"; import { IDep, IEnumDecDep, IFunctionDecDep, IInjectableDep, IInterfaceDep, IPipeDep, ITypeAliasDecDep, } from "./angular/dependencies.interfaces"; import { v4 as uuidv4 } from "uuid"; import { getNodeDecorators, nodeHasDecorator } from "../../utils/node.util"; import { markedAcl } from "../../utils/marked.acl"; const crypto = require("crypto"); const project = new Project(); type NodeWithJsDoc = ts.Node & { jsDoc?: ReadonlyArray<ts.JSDoc | ts.JSDocTag>; }; type InterfaceDeclarationWithSymbol = ts.InterfaceDeclaration & { symbol?: ts.Symbol; }; // TypeScript reference : https://github.com/Microsoft/TypeScript/blob/master/lib/typescript.d.ts export class AngularDependencies extends FrameworkDependencies { private engine: any; private cache: ComponentCache = new ComponentCache(); private moduleHelper = new ModuleHelper(this.cache); private jsDocHelper = new JsDocHelper(); private symbolHelper = new SymbolHelper(); private jsdocParserUtil = new JsdocParserUtil(); private publicApiFilter: PublicApiFilter; constructor(files: string[], options: any) { super(files, options); this.publicApiFilter = new PublicApiFilter(Configuration.mainData); } private isSymbolAllowed(symbolName: string, fileName: string): boolean { return this.publicApiFilter.isSymbolAllowed(symbolName, fileName); } private isDependencyOfAllowedSymbol( symbolName: string, fileName: string, ): boolean { return this.publicApiFilter.isDependencyOfAllowedSymbol(fileName); } private getTagsFromJSDoc(jsdoctags: any): any[] | undefined { if (!jsdoctags || jsdoctags.length < 1) { return undefined; } return jsdoctags[0]?.tags; } public getDependencies() { let deps: any = { aliases: {}, modules: [], modulesForGraph: [], components: [], controllers: [], entities: [], injectables: [], interceptors: [], guards: [], pipes: [], directives: [], routes: [], classes: [], interfaces: [], typescriptImports: [], miscellaneous: { variables: [], functions: [], typealiases: [], enumerations: [], }, routesTree: undefined, }; const sourceFiles = Array.from(this.program.getSourceFiles() || []); RouterParserUtil.scannedFiles = sourceFiles; sourceFiles.forEach((file: ts.SourceFile) => { const filePath = file.fileName; if ( path.extname(filePath) === ".ts" || path.extname(filePath) === ".tsx" ) { if ( !Configuration.mainData.angularJSProject && path.extname(filePath) === ".js" ) { logger.info("parsing", filePath); this.getSourceFileDecorators(file, deps); } else { if ( filePath.lastIndexOf(".d.ts") === -1 && filePath.lastIndexOf("spec.ts") === -1 ) { logger.info("parsing", filePath); this.getTypescriptExportsAliases(file, deps); this.getTypescriptImportsAliases(file, deps); this.getSourceFileDecorators(file, deps); } } } }); // End of file scanning // Try merging inside the same file declarated variables & modules with imports | exports | declarations | providers if (deps.miscellaneous.variables.length > 0) { // Detect variable names that appear in more than one source file. // When a collision exists we must scope the substitution to the declaring file // to avoid replacing a same-named variable in an unrelated module. const variableFilesByName = new Map<string, Set<string>>(); deps.miscellaneous.variables.forEach((v: any) => { if (!variableFilesByName.has(v.name)) { variableFilesByName.set(v.name, new Set()); } variableFilesByName.get(v.name)?.add(v.file); }); deps.miscellaneous.variables.forEach((_variable: any) => { let newVar: any[] = []; // link ...VAR to VAR values, recursively ((_var, _newVar) => { // getType pr reconstruire.... const elementsMatcher = (variabelToReplace: any) => { if (variabelToReplace.initializer) { if (variabelToReplace.initializer.elements) { if ( variabelToReplace.initializer.elements .length > 0 ) { variabelToReplace.initializer.elements.forEach( (element: any) => { // Direct value -> Kind 79 if ( element.text && element.kind === SyntaxKind.Identifier ) { newVar.push({ name: element.text, type: this.symbolHelper.getType( element.text, ), }); } // if _variable is ArrayLiteralExpression 203 // and has SpreadElements in his elements // merge them if ( element.kind === SyntaxKind.SpreadElement && element.expression ) { const el = deps.miscellaneous.variables.find( (variable: any) => variable.name === element .expression .text && variable.file === _variable.file, ); if (el) { elementsMatcher(el); } } }, ); } } } }; elementsMatcher(_var); })(_variable, newVar); const onLink = (mod: any) => { // When the same variable name is declared in multiple source files, // restrict substitution to the module that lives in the same file. // This prevents cross-file contamination while still allowing the // common pattern of importing an array from a separate barrel file. const nameHasCollision = (variableFilesByName.get(_variable.name)?.size ?? 0) > 1; if (nameHasCollision && mod.file !== _variable.file) { return; } const process = (initialArray: any[], _var: any) => { let indexToClean = 0; let found = false; const findVariableInArray = ( el: any, index: number, ) => { if (el.name === _var.name) { indexToClean = index; found = true; } }; initialArray.forEach(findVariableInArray); // Clean indexes to replace if (found) { initialArray.splice(indexToClean, 1); // Add variable newVar.forEach((newEle) => { if ( typeof _.find(initialArray, { name: newEle.name, }) === "undefined" ) { initialArray.push(newEle); } }); } }; process(mod.imports, _variable); process(mod.exports, _variable); process(mod.controllers, _variable); process(mod.declarations, _variable); process(mod.providers, _variable); }; deps.modules.forEach(onLink); deps.modulesForGraph.forEach(onLink); }); } /** * If one thing extends another, merge them, only for internal sources * - classes * - components * - injectables * - directives * for * - inputs * - outputs * - properties * - methods */ deps = ExtendsMerger.merge(deps); // RouterParserUtil.printModulesRoutes(); // RouterParserUtil.printRoutes(); if (!Configuration.mainData.disableRoutesGraph) { RouterParserUtil.linkModulesAndRoutes(); RouterParserUtil.constructModulesTree(); deps.routesTree = RouterParserUtil.constructRoutesTree(); } return deps; } private processClass( node: any, file: any, srcFile: any, outputSymbols: any, fileBody: any, astFile: any, ) { const name = this.getSymboleName(node); if (!name) { return; } const IO = this.getClassIO(file, srcFile, node, fileBody, astFile); const sourceCode = srcFile.getText(); const hash = crypto .createHash("sha512") .update(sourceCode) .digest("hex"); const deps: any = { name, id: "class-" + name + "-" + hash, file: file, coverageIgnore: !!IO.coverageIgnore, deprecated: IO.deprecated, deprecationMessage: IO.deprecationMessage, type: "class", sourceCode: srcFile.getText(), }; const typeParameters = this.getTypeParameters(node, srcFile); deps.displayName = this.getDisplayName(name, typeParameters); if (typeParameters.length > 0) { deps.typeParameters = typeParameters; } let excludeFromClassArray = false; if (IO.constructor && !Configuration.mainData.disableConstructors) { deps.constructorObj = IO.constructor; } deps.inputsClass = IO.inputs ?? []; deps.outputsClass = IO.outputs ?? []; if (IO.properties) { const { inputSignals, outputSignals, properties } = this.componentHelper.getInputOutputSignals(IO.properties); deps.inputsClass = deps.inputsClass.concat(inputSignals); deps.outputsClass = deps.outputsClass.concat(outputSignals); deps.properties = properties; } if (IO.description) { deps.description = IO.description; } if (IO.rawdescription) { deps.rawdescription = IO.rawdescription; } if (IO.methods) { deps.methods = IO.methods; } if (IO.indexSignatures) { deps.indexSignatures = IO.indexSignatures; } if (IO.extends) { deps.extends = IO.extends; } if (IO.jsdoctags && IO.jsdoctags.length > 0) { deps.jsdoctags = IO.jsdoctags[0].tags; } if (IO.accessors) { deps.accessors = IO.accessors; } if (IO.hostBindings) { deps.hostBindings = IO.hostBindings; } if (IO.hostListeners) { deps.hostListeners = IO.hostListeners; } if (Configuration.mainData.disableLifeCycleHooks) { deps.methods = cleanLifecycleHooksFromMethods(deps.methods); } if (IO.implements && IO.implements.length > 0) { deps.implements = IO.implements; if (this.isGuard(IO.implements)) { // We don't want the Guard to show up in the Classes menu excludeFromClassArray = true; deps.type = "guard"; outputSymbols.guards.push(deps); } } if (typeof IO.ignore === "undefined") { this.debug(deps); if (!excludeFromClassArray) { outputSymbols.classes.push(deps); } } else { this.ignore(deps); } } private getTypescriptImportsAliases( initialSrcFile: ts.SourceFile, outputSymbols: any, ): void { const astFile = typeof project.getSourceFile(initialSrcFile.fileName) !== "undefined" ? project.getSourceFile(initialSrcFile.fileName) : project.addSourceFileAtPath(initialSrcFile.fileName); if (astFile) { const importDeclarations = astFile.getImportDeclarations(); if (importDeclarations && importDeclarations.length > 0) { importDeclarations.forEach((importDeclaration) => { const namedImports = importDeclaration.getNamedImports(); if (namedImports && namedImports.length > 0) { namedImports.forEach((namedImport) => { if (namedImport.getAliasNode()) { const aliasNode = namedImport.getAliasNode(); if ( outputSymbols.aliases.hasOwnProperty( namedImport.getName(), ) ) { outputSymbols.aliases[ namedImport.getName() ].push(aliasNode?.getText()); } else { outputSymbols.aliases[ namedImport.getName() ] = [aliasNode?.getText()]; } } }); } }); } } } private getTypescriptExportsAliases( initialSrcFile: ts.SourceFile, outputSymbols: any, ): void { const astFile = typeof project.getSourceFile(initialSrcFile.fileName) !== "undefined" ? project.getSourceFile(initialSrcFile.fileName) : project.addSourceFileAtPath(initialSrcFile.fileName); if (astFile) { const exportDeclarations = astFile.getExportDeclarations(); if (exportDeclarations && exportDeclarations.length > 0) { exportDeclarations.forEach((exportDeclaration) => { const hasNamedExports = exportDeclaration.hasNamedExports(); if (hasNamedExports) { const namedExports = exportDeclaration.getNamedExports(); if (namedExports && namedExports.length > 0) { namedExports.forEach((namedExport) => { if (namedExport.getAliasNode()) { if ( outputSymbols.aliases.hasOwnProperty( namedExport.getName(), ) ) { const aliasNode = namedExport.getAliasNode(); outputSymbols.aliases[ namedExport.getName() ].push(aliasNode?.getText()); } else { const aliasNode = namedExport.getAliasNode(); outputSymbols.aliases[ namedExport.getName() ] = [aliasNode?.getText()]; } } }); } } }); } } } private getSourceFileDecorators( initialSrcFile: ts.SourceFile, outputSymbols: any, ): void { const cleaner = (process.cwd() + path.sep).replace(/\\/g, "/"); const fileName = initialSrcFile.fileName.replace(cleaner, ""); let scannedFile = initialSrcFile; // Search in file for variable statement as routes definitions let astFile: any = typeof project.getSourceFile(initialSrcFile.fileName) !== "undefined" ? project.getSourceFile(initialSrcFile.fileName) : project.addSourceFileAtPath(initialSrcFile.fileName); const variableRoutesStatements = astFile.getVariableStatements(); let hasRoutesStatements = false; if (variableRoutesStatements.length > 0) { hasRoutesStatements = variableRoutesStatements.some( (statement: any) => RouterParserUtil.isVariableRoutes(statement.compilerNode), ); } if (hasRoutesStatements && !Configuration.mainData.disableRoutesGraph) { // Clean file for spread and dynamics inside routes definitions logger.info( "Analysing routes definitions and clean them if necessary", ); // scannedFile = RouterParserUtil.cleanFileIdentifiers(astFile).compilerNode; RouterParserUtil.cleanFileSpreads(astFile); astFile = RouterParserUtil.cleanCallExpressions(astFile); scannedFile = RouterParserUtil.cleanFileDynamics(astFile).compilerNode; (scannedFile as any).kind = SyntaxKind.SourceFile; } ts.forEachChild(scannedFile, (initialNode: ts.Node) => { if ( this.jsDocHelper.hasJSDocInternalTag( fileName, scannedFile, initialNode, ) && Configuration.mainData.disableInternal ) { return; } const parseNode = ( file: any, srcFile: any, node: any, fileBody: any, astFile: any, ) => { const sourceCode = srcFile.getText(); const hash = crypto .createHash("sha512") .update(sourceCode) .digest("hex"); const routeIO: any = this.getRouteIO(file, srcFile, node); if (routeIO.routes) { let newRoutes: any; try { newRoutes = RouterParserUtil.cleanRawRouteParsed( routeIO.routes, ); } catch (e) { logger.error( "Routes parsing error, maybe a trailing comma or an external variable, trying to fix that later after sources scanning.", ); newRoutes = routeIO.routes.replace(/ /gm, ""); RouterParserUtil.addIncompleteRoute({ data: newRoutes, file: file, }); return true; } outputSymbols.routes = [ ...outputSymbols.routes, ...newRoutes, ]; } if (nodeHasDecorator(node)) { let classWithCustomDecorator = false; const nodeDecorators = getNodeDecorators(node); const visitDecorator = (visitedDecorator: any) => { let deps: any; const name = this.getSymboleName(node); if (!name) { return; } // Check if this decorated class is allowed by public API filter if (!this.isSymbolAllowed(name, file)) { logger.debug( `Skipping decorated class ${name} (not in public API)`, ); return; } const props = this.findProperties( visitedDecorator, srcFile, ); const IO = this.componentHelper.getComponentIO( file, srcFile, node, fileBody, astFile, ); if (this.isModule(visitedDecorator)) { const moduleDep = new ModuleDepFactory( this.moduleHelper, ).create(file, srcFile, name, props, IO); if ( RouterParserUtil.hasRouterModuleInImports( moduleDep.imports, ) ) { RouterParserUtil.addModuleWithRoutes( name, this.moduleHelper.getModuleImportsRaw( props, srcFile, ), file, ); } deps = moduleDep; if (typeof IO.ignore === "undefined") { RouterParserUtil.addModule( name, moduleDep.imports, ); outputSymbols.modules.push(moduleDep); outputSymbols.modulesForGraph.push(moduleDep); } } else if (this.isComponent(visitedDecorator)) { if (props.length === 0) { return; } const componentDep = new ComponentDepFactory( this.componentHelper, ).create(file, srcFile, name, props, IO); deps = componentDep; if (typeof IO.ignore === "undefined") { ComponentsTreeEngine.addComponent(componentDep); outputSymbols.components.push(componentDep); } } else if (this.isController(visitedDecorator)) { const controllerDep = new ControllerDepFactory().create( file, srcFile, name, props, IO, ); deps = controllerDep; if (typeof IO.ignore === "undefined") { outputSymbols.controllers.push(controllerDep); } } else if (this.isEntity(visitedDecorator)) { const entityDep = new EntityDepFactory().create( file, srcFile, name, props, IO, ); deps = entityDep; if (typeof IO.ignore === "undefined") { outputSymbols.entities.push(entityDep); } } else if (this.isInjectable(visitedDecorator)) { const injectableDeps: IInjectableDep = { name, id: "injectable-" + name + "-" + hash, file: file, coverageIgnore: !!IO.coverageIgnore, properties: IO.properties, methods: IO.methods, deprecated: IO.deprecated, deprecationMessage: IO.deprecationMessage, description: IO.description, rawdescription: IO.rawdescription, sourceCode: srcFile.getText(), exampleUrls: this.componentHelper.getComponentExampleUrls( srcFile.getText(), ), }; if ( IO.constructor && !Configuration.mainData.disableConstructors ) { injectableDeps.constructorObj = IO.constructor; } if (IO.jsdoctags && IO.jsdoctags.length > 0) { injectableDeps.jsdoctags = IO.jsdoctags[0].tags; } if (IO.accessors) { injectableDeps.accessors = IO.accessors; } if (IO.extends) { injectableDeps.extends = IO.extends; } const providedInRaw = this.symbolHelper.getSymbolDepsRaw( props, "providedIn", ); if (providedInRaw.length > 0) { const rawNode = providedInRaw[0] as ts.PropertyAssignment; if (rawNode && rawNode.initializer) { injectableDeps.providedIn = ts.isStringLiteral(rawNode.initializer) ? rawNode.initializer.text : rawNode.initializer.getText( srcFile, ); } } if (Configuration.mainData.disableLifeCycleHooks) { injectableDeps.methods = cleanLifecycleHooksFromMethods( injectableDeps.methods, ); } deps = injectableDeps; if (typeof IO.ignore === "undefined") { if ( _.includes(IO.implements, "HttpInterceptor") ) { injectableDeps.type = "interceptor"; outputSymbols.interceptors.push( injectableDeps, ); } else if (this.isGuard(IO.implements)) { injectableDeps.type = "guard"; outputSymbols.guards.push(injectableDeps); } else { injectableDeps.type = "injectable"; this.addNewEntityInStore( injectableDeps, outputSymbols.injectables, ); } } } else if (this.isPipe(visitedDecorator)) { const pipeDeps: IPipeDep = { name, id: "pipe-" + name + "-" + hash, file: file, type: "pipe", coverageIgnore: !!IO.coverageIgnore, deprecated: IO.deprecated, deprecationMessage: IO.deprecationMessage, description: IO.description, rawdescription: IO.rawdescription, properties: IO.properties, methods: IO.methods, standalone: this.componentHelper.getComponentStandalone( props, srcFile, ) ? true : false, pure: this.componentHelper.getComponentPure( props, srcFile, ), ngname: this.componentHelper.getComponentName( props, srcFile, ), sourceCode: srcFile.getText(), exampleUrls: this.componentHelper.getComponentExampleUrls( srcFile.getText(), ), }; if (Configuration.mainData.disableLifeCycleHooks) { pipeDeps.methods = cleanLifecycleHooksFromMethods( pipeDeps.methods, ); } if (IO.jsdoctags && IO.jsdoctags.length > 0) { pipeDeps.jsdoctags = IO.jsdoctags[0].tags; } deps = pipeDeps; if (typeof IO.ignore === "undefined") { outputSymbols.pipes.push(pipeDeps); } } else if (this.isDirective(visitedDecorator)) { const directiveDeps = new DirectiveDepFactory( this.componentHelper, ).create(file, srcFile, name, props, IO); deps = directiveDeps; if (typeof IO.ignore === "undefined") { outputSymbols.directives.push(directiveDeps); } } else { const hasMultipleDecoratorsWithInternalOne = this.hasInternalDecorator(nodeDecorators); // Just a class if ( !classWithCustomDecorator && !hasMultipleDecoratorsWithInternalOne ) { classWithCustomDecorator = true; this.processClass( node, file, srcFile, outputSymbols, fileBody, astFile, ); } } this.cache.set(name, deps); if (typeof IO.ignore === "undefined") { this.debug(deps); } else { this.ignore(deps); } }; const filterByDecorators = (filteredNode: any) => { if ( filteredNode.expression && filteredNode.expression.expression ) { let _test = /(NgModule|Component|Injectable|Pipe|Directive)/.test( filteredNode.expression.expression.text, ); if (!_test && ts.isClassDeclaration(node)) { _test = true; } return _test; } if (ts.isClassDeclaration(node)) { return true; } return false; }; nodeDecorators .filter(filterByDecorators) .forEach((decorator: any) => visitDecorator(decorator)); } else if (node.symbol) { if (node.symbol.flags === ts.SymbolFlags.Class) { // Check if class is allowed by public API filter const className = this.getSymboleName(node); if (!className) { return; } if (!this.isSymbolAllowed(className, file)) { logger.debug( `Skipping class ${className} (not in public API)`, ); return; } this.processClass( node, file, srcFile, outputSymbols, fileBody, astFile, ); } else if (node.symbol.flags === ts.SymbolFlags.Interface) { if (!ts.isInterfaceDeclaration(node)) { return; } const name = this.getSymboleName(node); if (!name) { return; } // Check if interface is allowed by public API filter if (!this.isSymbolAllowed(name, file)) { logger.debug( `Skipping interface ${name} (not in public API)`, ); return; } const mergedInterfaceDeclarations = this.getMergedInterfaceDeclarations(node); const declarationToProcess = mergedInterfaceDeclarations.find( (declaration) => !declaration .getSourceFile() .fileName.endsWith(".d.ts"), ) || mergedInterfaceDeclarations[0]; if ( mergedInterfaceDeclarations.length > 1 && declarationToProcess !== node ) { return; } const declarationMergeId = this.getInterfaceDeclarationMergeId( mergedInterfaceDeclarations, ); const IO = this.getInterfaceIO( file, srcFile, node, fileBody, astFile, ); const interfaceDeps: IInterfaceDep = { name, id: "interface-" + name + "-" + hash, file: file, deprecated: IO.deprecated, deprecationMessage: IO.deprecationMessage, type: "interface", sourceCode: srcFile.getText(), }; const typeParameters = this.getTypeParameters(declarationToProcess); interfaceDeps.displayName = this.getDisplayName( name, typeParameters, ); if (typeParameters.length > 0) { interfaceDeps.typeParameters = typeParameters; } if (declarationMergeId) { interfaceDeps.declarationMergeId = declarationMergeId; } if (IO.properties) { interfaceDeps.properties = IO.properties; } if (IO.indexSignatures) { interfaceDeps.indexSignatures = IO.indexSignatures; } if (IO.kind) { interfaceDeps.kind = IO.kind; } if (IO.description) { interfaceDeps.description = IO.description; interfaceDeps.rawdescription = IO.rawdescription; } if (IO.methods) { interfaceDeps.methods = IO.methods; } if (IO.extends) { interfaceDeps.extends = IO.extends; } if (typeof IO.ignore === "undefined") { this.debug(interfaceDeps); outputSymbols.interfaces.push(interfaceDeps); } else { this.ignore(interfaceDeps); } } else if (ts.isFunctionDeclaration(node)) { const infos = this.visitFunctionDeclaration(node); const name = infos.name; // Check if function is allowed by public API filter if (!this.isSymbolAllowed(name, file)) { logger.debug( `Skipping function ${name} (not in public API)`, ); return; } const deprecated = infos.deprecated; const deprecationMessage = infos.deprecationMessage; const functionDep: IFunctionDecDep = { name, file: file, ctype: "miscellaneous", subtype: "function", coverageIgnore: isCoverageIgnore(node), deprecated, deprecationMessage, rawdescription: this.visitEnumTypeAliasFunctionDeclarationRawDescription( node, ), description: this.visitEnumTypeAliasFunctionDeclarationDescription( node, ), }; functionDep.displayName = this.getDisplayName( name, infos.typeParameters, ); if ( infos.typeParameters && infos.typeParameters.length > 0 ) { functionDep.typeParameters = infos.typeParameters; } if (infos.args) { functionDep.args = infos.args; } if (infos.returnType) { functionDep.returnType = infos.returnType; } if (infos.jsdoctags && infos.jsdoctags.length > 0) { functionDep.jsdoctags = infos.jsdoctags; } if (typeof infos.ignore === "undefined") { if ( !( this.hasPrivateJSDocTag( functionDep.jsdoctags, ) && Configuration.mainData.disablePrivate ) ) { this.debug(functionDep); outputSymbols.miscellaneous.functions.push( functionDep, ); } } } else if (ts.isEnumDeclaration(node)) { const infos = this.visitEnumDeclaration(node); const name = infos.name; // Check if enum is allowed by public API filter if (!this.isSymbolAllowed(name, file)) { logger.debug( `Skipping enum ${name} (not in public API)`, ); return; } const deprecated = infos.deprecated; const deprecationMessage = infos.deprecationMessage; const enumDeps: IEnumDecDep = { name, childs: infos.members, ctype: "miscellaneous", subtype: "enum", deprecated, deprecationMessage, rawdescription: this.visitEnumTypeAliasFunctionDeclarationRawDescription( node, ), description: this.visitEnumTypeAliasFunctionDeclarationDescription( node, ), file: file, }; if (!isIgnore(node)) { this.debug(enumDeps); outputSymbols.miscellaneous.enumerations.push( enumDeps, ); } } else if (ts.isTypeAliasDeclaration(node)) { const infos = this.visitTypeDeclaration(node); const name = infos.name; // Check if type alias is allowed by public API filter if (!this.isSymbolAllowed(name, file)) { logger.debug( `Skipping type alias ${name} (not in public API)`, ); return; } const deprecated = infos.deprecated; const deprecationMessage = infos.deprecationMessage; const typeAliasDeps: ITypeAliasDecDep = { name, ctype: "miscellaneous", subtype: "typealias", coverageIgnore: isCoverageIgnore(node), rawtype: this.classHelper.visitType(node), file: file, deprecated, deprecationMessage, rawdescription: this.visitEnumTypeAliasFunctionDeclarationRawDescription( node, ), description: this.visitEnumTypeAliasFunctionDeclarationDescription( node, ), }; if (node.type) { typeAliasDeps.kind = node.type.kind; if (typeAliasDeps.rawtype === "") { typeAliasDeps.rawtype = this.classHelper.visitType(node); } } if ( typeAliasDeps.kind && typeAliasDeps.kind === SyntaxKind.TemplateLiteralType && node.type ) {