UNPKG

@compodoc/compodoc

Version:

The missing documentation tool for your Angular application

821 lines (728 loc) 34.6 kB
import { ts, SyntaxKind } from 'ts-morph'; import { getNamesCompareFn, mergeTagsAndArgs, markedtags } from '../../../../../utils/utils'; import { kindToType } from '../../../../../utils/kind-to-type'; import { isCoverageIgnore, isIgnore } from '../../../../../utils'; import Configuration from '../../../../configuration'; import { getNodeDecorators, nodeHasDecorator } from '../../../../../utils/node.util'; import { markedAcl } from '../../../../../utils/marked.acl'; import type { JsdocParserUtil } from '../../../../../utils/jsdoc-parser.util'; import { DecoratorResolver } from './decorator-resolver'; import { MemberVisibilityPolicy } from './member-visibility-policy'; const crypto = require('crypto'); export interface ClassMemberVisitorContext { typeChecker: ts.TypeChecker; getJsdocParserUtil: () => JsdocParserUtil; decoratorResolver: DecoratorResolver; memberVisibility: MemberVisibilityPolicy; stringifyDefaultValue: (node: ts.Node) => string; initializeDocumentationFields: () => { deprecated: boolean; deprecationMessage: string }; visitType: (node: any) => string; visitTypeIndex: (node: any) => string; shouldResolveTypeWithTypeChecker: (typeNode: ts.TypeNode) => boolean; tryResolveTypeFromTypeChecker: (node: ts.Node, enclosingDeclaration?: ts.Node) => string | undefined; extractAndProcessJSDocComment: (node: any, sourceFile: ts.SourceFile, result: any) => void; processJSDocTags: (jsdoctags: any, result: any, includeTagsArray?: boolean) => void; checkForDeprecation: (tags: any[], result: { [key in string | number]: any }) => void; } export class ClassMemberVisitor { constructor(private readonly context: ClassMemberVisitorContext) {} public visitMembers(members: any, sourceFile: any): any { return this.visitMembersInternal(members, sourceFile); } private visitType(node: any): string { return this.context.visitType(node); } private visitTypeIndex(node: any): string { return this.context.visitTypeIndex(node); } private shouldResolveTypeWithTypeChecker(typeNode: ts.TypeNode): boolean { return this.context.shouldResolveTypeWithTypeChecker(typeNode); } private tryResolveTypeFromTypeChecker( node: ts.Node, enclosingDeclaration?: ts.Node ): string | undefined { return this.context.tryResolveTypeFromTypeChecker(node, enclosingDeclaration); } private setFallbackDescription(result: any, node: any): void { if (!result.description && node.jsDoc && node.jsDoc.length > 0) { const lastJsDoc = node.jsDoc[node.jsDoc.length - 1]; if (typeof lastJsDoc.comment !== 'undefined') { const rawDescription = lastJsDoc.comment; result.rawdescription = rawDescription; result.description = markedAcl(rawDescription); } } } public getPosition(node: ts.Node, sourceFile: ts.SourceFile): ts.LineAndCharacter { let position: ts.LineAndCharacter; if ((node as any).name && (node as any).name.end) { position = ts.getLineAndCharacterOfPosition(sourceFile, (node as any).name.end); } else { position = ts.getLineAndCharacterOfPosition(sourceFile, node.pos); } return position; } public addAccessor(accessors: any, nodeAccessor: any, sourceFile: any) { let nodeName = ''; if (nodeAccessor.name) { nodeName = nodeAccessor.name.text; let jsdoctags = this.context.getJsdocParserUtil().getJSDocs(nodeAccessor); if (!accessors[nodeName]) { accessors[nodeName] = { name: nodeName, setSignature: undefined, getSignature: undefined }; } if (nodeAccessor.kind === SyntaxKind.SetAccessor) { let setSignature: any = { name: nodeName, type: 'void', ...this.context.initializeDocumentationFields(), args: nodeAccessor.parameters.map((param: any) => this.visitArgument(param)), returnType: nodeAccessor.type ? this.visitType(nodeAccessor.type) : 'void', line: this.getPosition(nodeAccessor, sourceFile).line + 1 }; this.context.extractAndProcessJSDocComment(nodeAccessor, sourceFile, setSignature); this.context.processJSDocTags(jsdoctags, setSignature); if (setSignature.jsdoctags && setSignature.jsdoctags.length > 0) { setSignature.jsdoctags = mergeTagsAndArgs( setSignature.args, setSignature.jsdoctags ); } else if (setSignature.args && setSignature.args.length > 0) { setSignature.jsdoctags = mergeTagsAndArgs(setSignature.args); } accessors[nodeName].setSignature = setSignature; } if (nodeAccessor.kind === SyntaxKind.GetAccessor) { let getSignature: any = { name: nodeName, type: nodeAccessor.type ? kindToType(nodeAccessor.type.kind) : '', returnType: nodeAccessor.type ? this.visitType(nodeAccessor.type) : '', line: this.getPosition(nodeAccessor, sourceFile).line + 1 }; this.context.extractAndProcessJSDocComment(nodeAccessor, sourceFile, getSignature); this.context.processJSDocTags(jsdoctags, getSignature); accessors[nodeName].getSignature = getSignature; } } } /** * VISITERS */ private visitMembersInternal(members: any, sourceFile: any) { /** * Copyright https://github.com/ng-bootstrap/ng-bootstrap */ let inputs: any[] = []; let outputs: any[] = []; let methods: any[] = []; let properties: any[] = []; let indexSignatures: any[] = []; let kind; let inputDecorator; let hostBindings: any[] = []; let hostListeners: any[] = []; let constructor; let outputDecorator; let accessors: any = {}; let result: any = {}; for (let i = 0; i < members.length; i++) { // Allows typescript guess type when using ts.is* let member = members[i]; inputDecorator = this.context.decoratorResolver.getDecoratorOfType(member, 'Input'); outputDecorator = this.context.decoratorResolver.getDecoratorOfType(member, 'Output'); const parsedHostBindings = this.context.decoratorResolver.getDecoratorOfType( member, 'HostBinding' ); const parsedHostListeners = this.context.decoratorResolver.getDecoratorOfType( member, 'HostListener' ); kind = member.kind; if (isIgnore(member)) { continue; } if (this.context.memberVisibility.isInternal(member) && Configuration.mainData.disableInternal) { continue; } if (inputDecorator && inputDecorator.length > 0) { inputs.push(this.visitInputAndHostBinding(member, inputDecorator[0], sourceFile)); if (ts.isSetAccessorDeclaration(member)) { this.addAccessor(accessors, members[i], sourceFile); } } else if (outputDecorator && outputDecorator.length > 0) { outputs.push(this.visitOutput(member, outputDecorator[0], sourceFile)); } else if (parsedHostBindings && parsedHostBindings.length > 0) { let k = 0; const lenHB = parsedHostBindings.length; for (k; k < lenHB; k++) { hostBindings.push( this.visitInputAndHostBinding(member, parsedHostBindings[k], sourceFile) ); } } else if (parsedHostListeners && parsedHostListeners.length > 0) { let l = 0; const lenHL = parsedHostListeners.length; for (l; l < lenHL; l++) { hostListeners.push( this.visitHostListener(member, parsedHostListeners[l], sourceFile) ); } } if (!this.context.memberVisibility.isHiddenMember(member)) { if (!(this.context.memberVisibility.isPrivate(member) && Configuration.mainData.disablePrivate)) { if (!(this.context.memberVisibility.isInternal(member) && Configuration.mainData.disableInternal)) { if ( !(this.context.memberVisibility.isProtected(member) && Configuration.mainData.disableProtected) ) { if (ts.isMethodDeclaration(member) || ts.isMethodSignature(member)) { methods.push(this.visitMethodDeclaration(member, sourceFile)); } else if ( ts.isPropertyDeclaration(member) || ts.isPropertySignature(member) ) { if (!inputDecorator && !outputDecorator) { properties.push(this.visitProperty(member, sourceFile)); } } else if (ts.isCallSignatureDeclaration(member)) { properties.push(this.visitCallDeclaration(member, sourceFile)); } else if ( ts.isGetAccessorDeclaration(member) || ts.isSetAccessorDeclaration(member) ) { this.addAccessor(accessors, members[i], sourceFile); } else if (ts.isIndexSignatureDeclaration(member)) { indexSignatures.push( this.visitIndexDeclaration(member, sourceFile) ); } else if (ts.isConstructorDeclaration(member)) { let _constructorProperties = this.visitConstructorProperties( member, sourceFile ); let j = 0; let len = _constructorProperties.length; for (j; j < len; j++) { properties.push(_constructorProperties[j]); } constructor = this.visitConstructorDeclaration(member, sourceFile); } } } } } } inputs.sort(getNamesCompareFn()); outputs.sort(getNamesCompareFn()); hostBindings.sort(getNamesCompareFn()); hostListeners.sort(getNamesCompareFn()); properties.sort(getNamesCompareFn()); methods.sort(getNamesCompareFn()); indexSignatures.sort(getNamesCompareFn()); result = { inputs, outputs, hostBindings, hostListeners, methods, properties, indexSignatures, kind, constructor }; if (Object.keys(accessors).length) { result['accessors'] = accessors; } return result; } private extractTypeLiteralProperties(typeNode: ts.TypeNode, sourceFile: ts.SourceFile): any[] { if (!ts.isTypeLiteralNode(typeNode) || !typeNode.members) { return []; } const subProperties: any[] = []; for (const member of typeNode.members) { if (!ts.isPropertySignature(member) || !member.name || !member.type) { continue; } const memberName = (member.name as any).text || (member.name as any).escapedText; if (!memberName) { continue; } const subProperty: any = { name: memberName, type: this.visitType(member.type), optional: typeof member.questionToken !== 'undefined', description: '' }; this.context.extractAndProcessJSDocComment(member, sourceFile, subProperty); const nestedSubProperties = this.extractTypeLiteralProperties(member.type, sourceFile); if (nestedSubProperties.length > 0) { subProperty.subProperties = nestedSubProperties; } subProperties.push(subProperty); } return subProperties; } public visitCallDeclaration(method: ts.CallSignatureDeclaration, sourceFile: ts.SourceFile) { let sourceCode = sourceFile.getText(); let hash = crypto.createHash('sha512').update(sourceCode).digest('hex'); let result: any = { id: 'call-declaration-' + hash, args: method.parameters ? method.parameters.map(prop => this.visitArgument(prop)) : [], returnType: this.visitType(method.type), line: this.getPosition(method, sourceFile).line + 1, ...this.context.initializeDocumentationFields() }; this.context.extractAndProcessJSDocComment(method, sourceFile, result); const jsdoctags = this.context.getJsdocParserUtil().getJSDocs(method); this.context.processJSDocTags(jsdoctags, result); return result; } public visitIndexDeclaration(method: ts.IndexSignatureDeclaration, sourceFile: ts.SourceFile) { let sourceCode = sourceFile.getText(); let hash = crypto.createHash('sha512').update(sourceCode).digest('hex'); let result = { id: 'index-declaration-' + hash, args: method.parameters ? method.parameters.map(prop => this.visitArgument(prop)) : [], returnType: this.visitType(method.type), line: this.getPosition(method, sourceFile).line + 1, ...this.context.initializeDocumentationFields() }; this.context.extractAndProcessJSDocComment(method, sourceFile, result); const jsdoctags = this.context.getJsdocParserUtil().getJSDocs(method); this.context.processJSDocTags(jsdoctags, result); return result; } public visitConstructorDeclaration( method: ts.ConstructorDeclaration, sourceFile: ts.SourceFile ) { /** * Copyright https://github.com/ng-bootstrap/ng-bootstrap */ let result: any = { name: 'constructor', description: '', ...this.context.initializeDocumentationFields(), args: method.parameters ? method.parameters.map(prop => this.visitArgument(prop)) : [], line: this.getPosition(method, sourceFile).line + 1 }; this.context.extractAndProcessJSDocComment(method, sourceFile, result); const kinds = this.context.memberVisibility.extractModifierKinds(method); if (kinds) { result.modifierKind = kinds; } const jsdoctags = this.context.getJsdocParserUtil().getJSDocs(method); this.context.processJSDocTags(jsdoctags, result); if (result.jsdoctags && result.jsdoctags.length > 0) { result.jsdoctags = mergeTagsAndArgs(result.args, result.jsdoctags); } else if (result.args.length > 0) { result.jsdoctags = mergeTagsAndArgs(result.args); } // Thread @param descriptions back into result.args so that consumers // reading args directly (e.g. JSON export) see the per-parameter description. if (result.args.length > 0 && result.jsdoctags && result.jsdoctags.length > 0) { const commentByName = new Map<string, any>(); for (const tag of result.jsdoctags) { const tagName = tag.name?.text ?? tag.name; if (tagName && tag.comment) { commentByName.set(String(tagName), tag.comment); } } for (const arg of result.args) { const comment = commentByName.get(arg.name); if (comment != null) { arg.description = comment; } } } return result; } public visitProperty( property: ts.PropertyDeclaration | ts.PropertySignature, sourceFile: ts.SourceFile ) { // PropertySignature (interfaces) don't have initializer, PropertyDeclaration (classes) do const initializer = ts.isPropertyDeclaration(property) ? property.initializer : undefined; // Extract property name, handling different node types: // - Identifier: regular property names // - PrivateIdentifier: ECMAScript private fields like #privateField // - ComputedPropertyName: computed names like ['__allAnd'] let propertyName = ''; // Check for mock objects first (for testing) if ((property.name as any).text) { propertyName = (property.name as any).text; } else if (ts.isIdentifier(property.name)) { propertyName = property.name.text; } else if (ts.isPrivateIdentifier(property.name)) { propertyName = property.name.text; // includes the # prefix } else if (ts.isComputedPropertyName(property.name)) { // Handle computed property names like ['__allAnd'] if (ts.isStringLiteral(property.name.expression)) { propertyName = property.name.expression.text; } else if (ts.isIdentifier(property.name.expression)) { propertyName = property.name.expression.text; } } const result: any = { name: propertyName, coverageIgnore: isCoverageIgnore(property), defaultValue: initializer ? this.context.stringifyDefaultValue(initializer) : undefined, ...this.context.initializeDocumentationFields(), type: this.visitType(property), indexKey: this.visitTypeIndex(property), optional: typeof property.questionToken !== 'undefined', description: '', line: this.getPosition(property, sourceFile).line + 1 }; if (property.type && this.shouldResolveTypeWithTypeChecker(property.type)) { const resolvedType = this.tryResolveTypeFromTypeChecker(property.type, property); if (resolvedType) { result.type = resolvedType; } } if (property.type && ts.isTypeLiteralNode(property.type)) { result.subProperties = this.extractTypeLiteralProperties(property.type, sourceFile); } if (initializer && initializer.kind === SyntaxKind.ArrowFunction) { result.defaultValue = '() => {...}'; } if (typeof result.name === 'undefined' && (property.name as any).expression) { result.name = (property.name as any).expression.text; } this.context.extractAndProcessJSDocComment(property, sourceFile, result); if (nodeHasDecorator(property)) { const propertyDecorators = getNodeDecorators(property); result.decorators = this.context.decoratorResolver.formatDecorators(propertyDecorators); } const kinds = this.context.memberVisibility.extractModifierKinds(property); if (kinds) { result.modifierKind = kinds; } // Check for ECMAScript Private Fields this.context.memberVisibility.ensurePrivateKeyword(result, property); const jsdoctags = this.context.getJsdocParserUtil().getJSDocs(property); if (jsdoctags && jsdoctags.length >= 1) { const jsdoc = jsdoctags[0] as any; if (jsdoc && jsdoc.tags) { this.context.checkForDeprecation(jsdoc.tags, result); if ((property as any).jsDoc) { result.jsdoctags = markedtags(jsdoc.tags); } } } return result; } public visitConstructorProperties(constr: any, sourceFile: ts.SourceFile) { if (constr.parameters) { let _parameters: any[] = []; let i = 0; let len = constr.parameters.length; for (i; i < len; i++) { const parameterOfConstructor = constr.parameters[i]; if (isIgnore(parameterOfConstructor)) { continue; } if ( this.context.memberVisibility.isInternal(parameterOfConstructor) && Configuration.mainData.disableInternal ) { continue; } if (this.context.memberVisibility.isPublic(parameterOfConstructor)) { _parameters.push(this.visitProperty(constr.parameters[i], sourceFile)); } } /** * Merge JSDoc tags description from constructor with parameters */ if (constr.jsDoc) { if (constr.jsDoc.length > 0) { let constrTags = constr.jsDoc[0].tags; if (constrTags && constrTags.length > 0) { constrTags.forEach((tag: any) => { _parameters.forEach((param: any) => { if ( tag.tagName && tag.tagName.escapedText && tag.tagName.escapedText === 'param' ) { if ( tag.name && tag.name.escapedText && tag.name.escapedText === param.name ) { param.description = tag.comment; } } }); }); } } } return _parameters; } else { return []; } } public visitMethodDeclaration( method: ts.MethodDeclaration | ts.MethodSignature, sourceFile: ts.SourceFile ) { let result: any = { name: (method.name as any).text || (ts.isIdentifier(method.name) ? method.name.text : ''), coverageIgnore: isCoverageIgnore(method), args: method.parameters ? method.parameters.map(prop => this.visitArgument(prop)) : [], optional: typeof method.questionToken !== 'undefined', returnType: this.visitType(method.type), typeParameters: [], line: this.getPosition(method, sourceFile).line + 1, ...this.context.initializeDocumentationFields() }; if (typeof method.type === 'undefined') { // Try to get inferred type if ((method as any).symbol) { let symbol: ts.Symbol = (method as any).symbol; if (symbol.valueDeclaration) { let symbolType = this.context.typeChecker.getTypeOfSymbolAtLocation( symbol, symbol.valueDeclaration ); if (symbolType) { try { const signature = this.context.typeChecker.getSignatureFromDeclaration(method); const returnType = signature?.getReturnType(); if (returnType) { result.returnType = this.context.typeChecker.typeToString(returnType); } // tslint:disable-next-line:no-empty } catch (error) {} } } } } if (method.typeParameters && method.typeParameters.length > 0) { result.typeParameters = method.typeParameters.map(typeParameter => this.visitType(typeParameter) ); } this.context.extractAndProcessJSDocComment(method, sourceFile, result); if (nodeHasDecorator(method)) { const methodDecorators = getNodeDecorators(method); result.decorators = this.context.decoratorResolver.formatDecorators(methodDecorators); } const kinds = this.context.memberVisibility.extractModifierKinds(method); if (kinds) { result.modifierKind = kinds; } // Check for ECMAScript Private Fields this.context.memberVisibility.ensurePrivateKeyword(result, method); const jsdoctags = this.context.getJsdocParserUtil().getJSDocs(method); this.context.processJSDocTags(jsdoctags, result); if (result.jsdoctags && result.jsdoctags.length > 0) { result.jsdoctags = mergeTagsAndArgs(result.args, result.jsdoctags); } else if (result.args.length > 0) { result.jsdoctags = mergeTagsAndArgs(result.args); } return result; } public visitOutput( property: ts.PropertyDeclaration, outDecorator: ts.Decorator, sourceFile: ts.SourceFile ) { let inArgs = (outDecorator.expression as any).arguments; let _return: any = { name: inArgs.length > 0 ? (inArgs[0] as any).text : (property.name as any).text || (ts.isIdentifier(property.name) ? property.name.text : ''), coverageIgnore: isCoverageIgnore(property), defaultValue: property.initializer ? this.context.stringifyDefaultValue(property.initializer) : undefined, ...this.context.initializeDocumentationFields() }; if ((property as any).jsDoc) { this.context.extractAndProcessJSDocComment(property, sourceFile, _return); const jsdoctags = this.context.getJsdocParserUtil().getJSDocs(property); this.context.processJSDocTags(jsdoctags, _return); } this.setFallbackDescription(_return, property); _return.line = this.getPosition(property, sourceFile).line + 1; if (property.type) { _return.type = this.visitType(property); if (this.shouldResolveTypeWithTypeChecker(property.type)) { const resolvedType = this.tryResolveTypeFromTypeChecker(property.type, property); if (resolvedType) { _return.type = resolvedType; } } } else { // handle NewExpression if (property.initializer) { if (ts.isNewExpression(property.initializer)) { if (property.initializer.expression) { _return.type = (property.initializer.expression as any).text; } } } } return _return; } public visitArgument(arg: ts.ParameterDeclaration) { let _result: any = { name: (arg.name as any).text || (ts.isIdentifier(arg.name) ? arg.name.text : ''), type: this.visitType(arg), optional: !!arg.questionToken, dotDotDotToken: !!arg.dotDotDotToken, ...this.context.initializeDocumentationFields() }; if (arg.type && this.shouldResolveTypeWithTypeChecker(arg.type)) { const resolvedType = this.tryResolveTypeFromTypeChecker(arg.type, arg); if (resolvedType) { _result.type = resolvedType; } } if (arg.type && arg.type.kind && ts.isFunctionTypeNode(arg.type)) { _result.function = arg.type.parameters ? arg.type.parameters.map(prop => this.visitArgument(prop)) : []; } if (arg.initializer) { _result.defaultValue = this.context.stringifyDefaultValue(arg.initializer); } const jsdoctags = this.context.getJsdocParserUtil().getJSDocs(arg); this.context.processJSDocTags(jsdoctags, _result, false); return _result; } public visitInputAndHostBinding(property: any, inDecorator: any, sourceFile: ts.SourceFile) { const inArgs = inDecorator.expression.arguments; let _return: any = { coverageIgnore: isCoverageIgnore(property) }; let isInputConfigStringLiteral = false; let isInputConfigObjectLiteralExpression = false; let hasRequiredField = false; let hasAlias = false; const getRequiredField = () => inArgs[0].properties.find((property: any) => property.name.escapedText === 'required'); const getAliasProperty = () => inArgs[0].properties.find((property: any) => property.name.escapedText === 'alias'); if (inArgs.length > 0) { isInputConfigStringLiteral = inArgs[0] && ts.isStringLiteral(inArgs[0]); isInputConfigObjectLiteralExpression = inArgs[0] && ts.isObjectLiteralExpression(inArgs[0]); if (isInputConfigObjectLiteralExpression && inArgs[0].properties) { hasRequiredField = isInputConfigObjectLiteralExpression && !!getRequiredField(); hasAlias = isInputConfigObjectLiteralExpression ? !!getAliasProperty() : false; _return.required = !!getRequiredField(); } if (isInputConfigStringLiteral) { _return.name = inArgs[0].text; _return.actualName = property.name.text; } else if (hasAlias) { _return.name = getAliasProperty().initializer.text; _return.actualName = property.name.text; } else { _return.name = property.name.text; } } else { _return.name = property.name.text; } _return.defaultValue = property.initializer ? this.context.stringifyDefaultValue(property.initializer) : undefined; Object.assign(_return, this.context.initializeDocumentationFields()); if (inArgs.length > 0 && inArgs[0].properties && hasRequiredField) { _return.optional = getRequiredField().initializer.kind !== SyntaxKind.TrueKeyword; } if (!_return.description) { const jsdoctags = this.context.getJsdocParserUtil().getJSDocs(property); this.context.processJSDocTags(jsdoctags, _return); this.context.extractAndProcessJSDocComment(property, sourceFile, _return); } _return.line = this.getPosition(property, sourceFile).line + 1; if (property.type) { _return.type = this.visitType(property); if (this.shouldResolveTypeWithTypeChecker(property.type)) { const resolvedType = this.tryResolveTypeFromTypeChecker(property.type, property); if (resolvedType) { _return.type = resolvedType; } } } else { // handle NewExpression if (property.initializer) { if (ts.isNewExpression(property.initializer)) { if (property.initializer.expression) { _return.type = property.initializer.expression.text; } } } // Try to get inferred type if (property.symbol) { const symbol: ts.Symbol = property.symbol; if (symbol.valueDeclaration) { const symbolType = this.context.typeChecker.getTypeOfSymbolAtLocation( symbol, symbol.valueDeclaration ); if (symbolType) { _return.type = this.context.typeChecker.typeToString(symbolType); } } } } if (property.kind === SyntaxKind.SetAccessor) { // For setter accessor, find type in first parameter if (property.parameters && property.parameters.length === 1) { if (property.parameters[0].type) { _return.type = this.visitType(property.parameters[0].type); } } } if (nodeHasDecorator(property)) { const propertyDecorators = getNodeDecorators(property); _return.decorators = this.context.decoratorResolver.formatDecorators(propertyDecorators).filter( (item: any) => item.name !== 'Input' && item.name !== 'HostBinding' ); } return _return; } public visitHostListener( property: any, hostListenerDecorator: any, sourceFile: ts.SourceFile ) { let inArgs = hostListenerDecorator.expression.arguments; let _return: any = { coverageIgnore: isCoverageIgnore(property) }; _return.name = inArgs.length > 0 ? inArgs[0].text : property.name.text; _return.args = property.parameters ? property.parameters.map((prop: any) => this.visitArgument(prop)) : []; _return.argsDecorator = inArgs.length > 1 ? inArgs[1].elements.map((prop: any) => { return prop.text; }) : []; Object.assign(_return, this.context.initializeDocumentationFields()); if (property.jsDoc) { this.context.extractAndProcessJSDocComment(property, sourceFile, _return); const jsdoctags = this.context.getJsdocParserUtil().getJSDocs(property); this.context.processJSDocTags(jsdoctags, _return); } this.setFallbackDescription(_return, property); _return.line = this.getPosition(property, sourceFile).line + 1; return _return; } }