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 type { 19 comment, Context, ISourceCodeProcessor, ModifyLogResult, ProcessResult, sourceParser, 20 MethodNodeType, ApiSplitProcessorInterface 21} from './typedef'; 22import { ErrorInfo, JSDocModifyType } from './typedef'; 23import { CommentHelper, LogResult } from './coreImpls'; 24import { LogReportStringUtils } from '../utils/stringUtils'; 25 26export class ApiSplitProcessor implements ISourceCodeProcessor, sourceParser.ITransformCallback { 27 28 context?: Context; 29 30 async process(context: Context, content: string): Promise<ProcessResult> { 31 if (!context.getOptions().splitUnionTypeApi) { 32 return { code: Code.OK, content: content }; 33 } 34 this.context = context; 35 const sourceParser = context.getSourceParser(content); 36 const sourceFile = sourceParser.transform(this); 37 return { 38 code: Code.OK, 39 content: sourceFile ? sourceParser.printSourceFile(sourceFile) : content 40 }; 41 } 42 43 onTransformNode(node: comment.CommentNode): ts.Node | undefined { 44 if (node.astNode === undefined) { 45 return undefined; 46 } 47 const nodeProcessor = nodeProcessorMap.get(node.astNode.kind); 48 return nodeProcessor ? nodeProcessor(node.astNode, this.context) : undefined; 49 } 50} 51 52/** 53 * 订阅事件api拆分工具类 54 */ 55class ApiSplitProcessorHelper { 56 57 static splitEventValues(node: ts.Node): string[] { 58 let eventValues: Array<string> = []; 59 if (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node) || ts.isMethodSignature(node)) { 60 let functionName: string = ''; 61 if (node.name && ts.isIdentifier(node.name)) { 62 functionName = node.name.getText(); 63 } 64 if ((functionName !== 'on') && (functionName !== 'off')) { 65 return eventValues; 66 } 67 if ((node.parameters[0].type) && (node.parameters[0].type.kind === ts.SyntaxKind.UnionType)) { 68 const types: ts.NodeArray<ts.TypeNode> = (node.parameters[0].type as ts.UnionTypeNode).types; 69 for (let i = 0; i < types.length; i++) { 70 const eventValueNode: ts.TypeNode = types[i]; 71 if (eventValueNode.kind === ts.SyntaxKind.LiteralType && 72 (eventValueNode as ts.LiteralTypeNode).literal.kind === ts.SyntaxKind.StringLiteral) { 73 const eventValue = (eventValueNode as ts.LiteralTypeNode).literal.getText(); 74 // 这里获取的eventValue包含了单引号或双引号,因此需要进行截取 75 eventValues.push(eventValue.slice(1, eventValue.length - 1)); 76 } else { 77 eventValues = []; 78 break; 79 } 80 } 81 } 82 } 83 return eventValues; 84 } 85 86 static logReportProcess(node: MethodNodeType, context?: Context): void { 87 const apiName: string = `${node.name?.getText()}(${node.parameters[0].type?.getFullText()})`; 88 const description: string = LogReportStringUtils.createErrorInfo(ErrorInfo.EVENT_SUBSCRIPTION_SPLITTION, [`${apiName}`]); 89 const comments: Array<comment.CommentInfo> = CommentHelper.getNodeLeadingComments(node, node.getSourceFile()); 90 const modifyLogResult: ModifyLogResult = LogResult.createModifyResult(node, comments, description, context, 91 apiName, JSDocModifyType.EVENT_SUBSCRIPTION_SPLITTION); 92 context?.getLogReporter().addModifyResult(modifyLogResult); 93 } 94 95 static createNewParams(node: MethodNodeType, eventValue: string, typeParam: ts.ParameterDeclaration): ts.ParameterDeclaration[] { 96 const literalTypeNode = ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(eventValue)); 97 const newTypeParam: ts.ParameterDeclaration = ts.factory.createParameterDeclaration(typeParam.modifiers, 98 typeParam.dotDotDotToken, typeParam.name, typeParam.questionToken, literalTypeNode, typeParam.initializer); 99 const newParams: Array<ts.ParameterDeclaration> = []; 100 newParams.push(newTypeParam); 101 for (let i = 1; i < node.parameters.length; i++) { 102 const param: ts.ParameterDeclaration = node.parameters[i]; 103 const paramNode: ts.ParameterDeclaration = ts.factory.createParameterDeclaration(param.modifiers, 104 param.dotDotDotToken, param.name, param.questionToken, param.type, param.initializer); 105 newParams.push(paramNode); 106 } 107 return newParams; 108 } 109 110 /** 111 * 创建新的FunctionDeclaration类型节点数组 112 * @param node 当前节点 113 * @param eventValues 事件名称数组 114 * @returns 新创建的节点数组 115 */ 116 static createFunctionDecNodes(node: ts.FunctionDeclaration, eventValues: Array<string>): Array<ts.FunctionDeclaration> { 117 const newFunctionNodes: Array<ts.FunctionDeclaration> = []; 118 const typeParam: ts.ParameterDeclaration = node.parameters[0]; 119 const modifiers: Array<ts.Modifier> = []; 120 node.modifiers?.forEach((modifier: ts.Modifier) => { 121 ts.setEmitFlags(modifier, ts.EmitFlags.NoLeadingComments); 122 const newModifier = ts.factory.createModifier(modifier.kind); 123 modifiers.push(newModifier); 124 }); 125 const newModifiers: ts.NodeArray<ts.Modifier> = ts.factory.createNodeArray(modifiers); 126 eventValues.forEach((eventValue: string) => { 127 const newParams: Array<ts.ParameterDeclaration> = ApiSplitProcessorHelper.createNewParams(node, eventValue, typeParam); 128 const newFunctionNode: ts.FunctionDeclaration = ts.factory.createFunctionDeclaration(newModifiers, 129 node.asteriskToken, node.name, node.typeParameters, newParams, node.type, node.body); 130 const comments: Array<comment.CommentInfo> = CommentHelper.getNodeLeadingComments(node, node.getSourceFile()); 131 CommentHelper.setComment(newFunctionNode, [CommentHelper.getEmptyLineComment(), ...comments]); 132 newFunctionNodes.push(newFunctionNode); 133 }); 134 return newFunctionNodes; 135 } 136 137 /** 138 * 创建新的MethodDeclaration类型节点数组 139 * @param node 当前节点 140 * @param eventValues 事件名称数组 141 * @returns 新创建的节点数组 142 */ 143 static createMethodDecNodes(node: ts.MethodDeclaration, eventValues: Array<string>): Array<ts.MethodDeclaration> { 144 const newFunctionNodes: Array<ts.MethodDeclaration> = []; 145 const typeParam: ts.ParameterDeclaration = node.parameters[0]; 146 eventValues.forEach((eventValue: string) => { 147 const newParams: Array<ts.ParameterDeclaration> = ApiSplitProcessorHelper.createNewParams(node, eventValue, typeParam); 148 ts.setEmitFlags(node.name, ts.EmitFlags.NoLeadingComments); 149 const newFunctionNode: ts.MethodDeclaration = ts.factory.createMethodDeclaration(node.modifiers, node.asteriskToken, 150 node.name, node.questionToken, node.typeParameters, newParams, node.type, node.body); 151 const comments: Array<comment.CommentInfo> = CommentHelper.getNodeLeadingComments(node, node.getSourceFile()); 152 CommentHelper.setComment(newFunctionNode, [CommentHelper.getEmptyLineComment(), ...comments]); 153 newFunctionNodes.push(newFunctionNode); 154 }); 155 return newFunctionNodes; 156 } 157 158 /** 159 * 创建新的MethodSignature类型节点数组 160 * @param node 当前节点 161 * @param eventValues 事件名称数组 162 * @returns 新创建的节点数组 163 */ 164 static createMethodSigNodes(node: ts.MethodSignature, eventValues: Array<string>): Array<ts.MethodSignature> { 165 const newFunctionNodes: Array<ts.MethodSignature> = []; 166 const typeParam: ts.ParameterDeclaration = node.parameters[0]; 167 eventValues.forEach((eventValue: string) => { 168 const newParams: Array<ts.ParameterDeclaration> = ApiSplitProcessorHelper.createNewParams(node, eventValue, typeParam); 169 ts.setEmitFlags(node.name, ts.EmitFlags.NoLeadingComments); 170 const newFunctionNode: ts.MethodSignature = ts.factory.createMethodSignature(node.modifiers, node.name, 171 node.questionToken, node.typeParameters, newParams, node.type); 172 const comments: Array<comment.CommentInfo> = CommentHelper.getNodeLeadingComments(node, node.getSourceFile()); 173 CommentHelper.setComment(newFunctionNode, [CommentHelper.getEmptyLineComment(), ...comments]); 174 newFunctionNodes.push(newFunctionNode); 175 }); 176 177 return newFunctionNodes; 178 } 179 180 static processSourceFile(node: ts.Node, context: Context | undefined): ts.Node | undefined { 181 const sourceFile: ts.SourceFile = node as ts.SourceFile; 182 const newStatements: Array<ts.Statement> = []; 183 const statements: ts.NodeArray<ts.Statement> = sourceFile.statements; 184 statements.forEach((statement: ts.Statement) => { 185 const eventValues: Array<string> = ApiSplitProcessorHelper.splitEventValues(statement); 186 if (eventValues.length === 0) { 187 newStatements.push(statement); 188 } else { 189 const funcDecNode: ts.FunctionDeclaration = statement as ts.FunctionDeclaration; 190 const newFunctionNodes: Array<ts.FunctionDeclaration> = ApiSplitProcessorHelper.createFunctionDecNodes(funcDecNode, eventValues); 191 newStatements.push(...newFunctionNodes); 192 // 添加报告输出处理逻辑 193 ApiSplitProcessorHelper.logReportProcess(funcDecNode, context); 194 } 195 }); 196 if (statements.length === newStatements.length) { 197 return undefined; 198 } 199 return ts.factory.updateSourceFile(sourceFile, newStatements, sourceFile.isDeclarationFile, 200 sourceFile.referencedFiles, sourceFile.typeReferenceDirectives, sourceFile.hasNoDefaultLib, 201 sourceFile.libReferenceDirectives); 202 } 203 204 static processModuleDeclaration(node: ts.Node, context: Context | undefined): ts.Node | undefined { 205 const moduleDeclaration: ts.ModuleDeclaration = node as ts.ModuleDeclaration; 206 if (moduleDeclaration.body && moduleDeclaration.body.kind === ts.SyntaxKind.ModuleBlock) { 207 const statements: ts.NodeArray<ts.Statement> = moduleDeclaration.body.statements; 208 const newStatements: Array<ts.Statement> = []; 209 statements.forEach((statement: ts.Statement) => { 210 const eventValues: Array<string> = ApiSplitProcessorHelper.splitEventValues(statement); 211 if (eventValues.length === 0) { 212 newStatements.push(statement); 213 } else { 214 const funcDecNode: ts.FunctionDeclaration = statement as ts.FunctionDeclaration; 215 const newFunctionNodes: Array<ts.FunctionDeclaration> = ApiSplitProcessorHelper.createFunctionDecNodes(funcDecNode, eventValues); 216 newStatements.push(...newFunctionNodes); 217 // 添加报告输出处理逻辑 218 ApiSplitProcessorHelper.logReportProcess(funcDecNode, context); 219 } 220 }); 221 if (statements.length === newStatements.length) { 222 return undefined; 223 } 224 const newModuleBlock: ts.ModuleBlock = ts.factory.updateModuleBlock(moduleDeclaration.body, newStatements); 225 return ts.factory.updateModuleDeclaration(moduleDeclaration, moduleDeclaration.modifiers, 226 moduleDeclaration.name, newModuleBlock); 227 } 228 return undefined; 229 } 230 231 static processClassDeclaration(node: ts.Node, context: Context | undefined): ts.Node | undefined { 232 const classDeclaration: ts.ClassDeclaration = node as ts.ClassDeclaration; 233 const members: ts.NodeArray<ts.ClassElement> = classDeclaration.members; 234 const newMembers: Array<ts.ClassElement> = []; 235 members.forEach((member: ts.ClassElement) => { 236 const eventValues: Array<string> = ApiSplitProcessorHelper.splitEventValues(member); 237 if (eventValues.length === 0) { 238 newMembers.push(member); 239 } else { 240 const funcDecNode: ts.MethodDeclaration = member as ts.MethodDeclaration; 241 const newFunctionNodes: Array<ts.MethodDeclaration> = ApiSplitProcessorHelper.createMethodDecNodes(funcDecNode, eventValues); 242 newMembers.push(...newFunctionNodes); 243 // 添加报告输出处理逻辑 244 ApiSplitProcessorHelper.logReportProcess(funcDecNode, context); 245 } 246 }); 247 if (members.length === newMembers.length) { 248 return undefined; 249 } 250 return ts.factory.updateClassDeclaration(classDeclaration, classDeclaration.modifiers, classDeclaration.name, 251 classDeclaration.typeParameters, classDeclaration.heritageClauses, newMembers); 252 } 253 254 static processInterfaceDeclaration(node: ts.Node, context: Context | undefined): ts.Node | undefined { 255 const interfaceDeclaration: ts.InterfaceDeclaration = node as ts.InterfaceDeclaration; 256 const members: ts.NodeArray<ts.TypeElement> = interfaceDeclaration.members; 257 const newMembers: Array<ts.TypeElement> = []; 258 members.forEach((member: ts.TypeElement) => { 259 const eventValues: Array<string> = ApiSplitProcessorHelper.splitEventValues(member); 260 if (eventValues.length === 0) { 261 newMembers.push(member); 262 } else { 263 const funcDecNode: ts.MethodSignature = member as ts.MethodSignature; 264 const newFunctionNodes: Array<ts.MethodSignature> = ApiSplitProcessorHelper.createMethodSigNodes(funcDecNode, eventValues); 265 newMembers.push(...newFunctionNodes); 266 // 添加报告输出处理逻辑 267 ApiSplitProcessorHelper.logReportProcess(funcDecNode, context); 268 } 269 }); 270 if (members.length === newMembers.length) { 271 return undefined; 272 } 273 return ts.factory.updateInterfaceDeclaration(interfaceDeclaration, interfaceDeclaration.modifiers, interfaceDeclaration.name, 274 interfaceDeclaration.typeParameters, interfaceDeclaration.heritageClauses, newMembers); 275 } 276} 277 278const nodeProcessorMap: Map<ts.SyntaxKind, ApiSplitProcessorInterface> = new Map([ 279 [ts.SyntaxKind.SourceFile, ApiSplitProcessorHelper.processSourceFile], 280 [ts.SyntaxKind.ModuleDeclaration, ApiSplitProcessorHelper.processModuleDeclaration], 281 [ts.SyntaxKind.InterfaceDeclaration, ApiSplitProcessorHelper.processInterfaceDeclaration], 282 [ts.SyntaxKind.ClassDeclaration, ApiSplitProcessorHelper.processClassDeclaration] 283]);