1/* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import ts from 'typescript'; 17import { Code } from '../utils/constant'; 18import { LogReportStringUtils } from '../utils/stringUtils'; 19import { CommentHelper, LogResult } from './coreImpls'; 20import type { 21 Context, ISourceCodeProcessor, MethodNodeType, 22 ModifyLogResult, ProcessResult, comment 23} from './typedef'; 24import { JSDocModifyType, ErrorInfo } from './typedef'; 25 26export class AsynchronousFunctionProcessor implements ISourceCodeProcessor { 27 28 context?: Context; 29 30 async process(context: Context, content: string): Promise<ProcessResult> { 31 const sourceParser = context.getSourceParser(content); 32 this.context = context; 33 const sourceFile: ts.SourceFile | undefined = sourceParser.createSourceFile(content); 34 if (!sourceFile) { 35 return { code: Code.OK, content: content }; 36 } 37 const preNode: PreNode = new PreNode('', []); 38 ts.forEachChild(sourceFile, (cNode) => { 39 this.nodeVisitor(cNode, preNode); 40 }); 41 return { 42 code: Code.OK, 43 content: sourceParser.printSourceFile(sourceFile) 44 }; 45 } 46 47 logReportProcess(node: MethodNodeType, comments: Array<comment.CommentInfo>): void { 48 const apiName: string = node.name ? node.name.getText() : ''; 49 const description: string = LogReportStringUtils.createErrorInfo(ErrorInfo.AYYNCHRONOUS_FUNCTION_JSDOC_COPY, [`${apiName}`]); 50 const modifyLogResult: ModifyLogResult = LogResult.createModifyResult(node, comments, description, this.context, 51 apiName, JSDocModifyType.AYYNCHRONOUS_FUNCTION_JSDOC_COPY); 52 this.context?.getLogReporter().addModifyResult(modifyLogResult); 53 } 54 55 nodeVisitor(cNode: ts.Node, preNode: PreNode): void { 56 if (ts.isModuleDeclaration(cNode) && cNode.body && ts.isModuleBlock(cNode.body)) { 57 const preNode: PreNode = new PreNode('', []); 58 ts.forEachChild(cNode.body, (child) => { 59 this.nodeVisitor(child, preNode); 60 }); 61 return; 62 } 63 64 if (ts.isSourceFile(cNode) || ts.isClassDeclaration(cNode) || ts.isInterfaceDeclaration(cNode)) { 65 const preNode: PreNode = new PreNode('', []); 66 ts.forEachChild(cNode, (child) => { 67 this.nodeVisitor(child, preNode); 68 }); 69 return; 70 } 71 72 if ((ts.isFunctionDeclaration(cNode) || ts.isMethodDeclaration(cNode) || ts.isMethodSignature(cNode)) && 73 this.isAsynchronousFunction(cNode)) { 74 const nodeComments: Array<comment.CommentInfo> = CommentHelper.getNodeLeadingComments(cNode, cNode.getSourceFile()); 75 let functionName: string = ''; 76 if (cNode.name && ts.isIdentifier(cNode.name)) { 77 functionName = cNode.name.escapedText.toString(); 78 } 79 if (nodeComments.length !== 0) { 80 if (functionName !== '') { 81 preNode.name = functionName; 82 preNode.doc = nodeComments; 83 } else { 84 preNode.name = ''; 85 preNode.doc = []; 86 } 87 } else { 88 if (preNode.name === '') { 89 return; 90 } 91 if (preNode.name === functionName) { 92 // 添加报告输出处理 93 this.logReportProcess(cNode, preNode.doc); 94 CommentHelper.setComment(cNode, [CommentHelper.getEmptyLineComment(), ...preNode.doc]); 95 return; 96 } 97 preNode.name = ''; 98 preNode.doc = []; 99 } 100 101 } else { 102 preNode.name = ''; 103 preNode.doc = []; 104 } 105 } 106 107 isAsynchronousFunction(node: MethodNodeType): boolean { 108 if (node.type && (node.type.kind === ts.SyntaxKind.TypeReference) && 109 (node.type as ts.TypeReferenceNode).typeName.getText() === 'Promise') { 110 return true; 111 } 112 if (node.parameters.length !== 0) { 113 for (let i = node.parameters.length - 1; i >= 0; i--) { 114 const param: ts.ParameterDeclaration = node.parameters[i]; 115 if (param.type && (param.type.kind === ts.SyntaxKind.TypeReference) && 116 (param.type as ts.TypeReferenceNode).typeName.getText() === 'AsyncCallback') { 117 return true; 118 } 119 } 120 } 121 return false; 122 } 123} 124 125class PreNode { 126 name: string; 127 doc: Array<comment.CommentInfo>; 128 constructor(name: string, doc: Array<comment.CommentInfo>) { 129 this.name = name; 130 this.doc = doc; 131 } 132}