• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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}