@compodoc/compodoc
Version:
The missing documentation tool for your Angular application
1,134 lines (1,050 loc) • 114 kB
text/typescript
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
) {