1/* 2* Copyright (c) 2022 Shenzhen Kaihong Digital Industry Development 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*/ 15const { NapiLog } = require("../tools/NapiLog"); 16const fs = require("fs"); 17const os = require("os"); 18const { AllParseFileList } = require("../tools/common"); 19const path = require('path'); 20 21function parseFileAll(hFilePath) { 22 let execSync = require("child_process").execSync; 23 let cmd = ""; 24 if(fs.existsSync("./hdc/service/service-gen/src/gen/header_parser.py")) { 25 // call python file (for debug test) 26 cmd = "python ./hdc/service/service-gen/src/gen/header_parser.py " + hFilePath; 27 } else { 28 // call exe file (for real runtime) 29 let sysInfo = os.platform(); 30 let execPath = path.dirname(process.execPath); 31 let exeFile = sysInfo === 'win32' ? path.join(execPath, "header_parser.exe") : 32 path.join(execPath, "header_parser"); 33 cmd = exeFile + " " + hFilePath; 34 } 35 36 let parseResult = null; 37 let stdout = execSync(cmd); 38 parseResult = JSON.parse(stdout.toString()).result; 39 parseResult.rawContent = fs.readFileSync(hFilePath, 'UTF-8'); 40 return parseResult; 41} 42 43function analyzeNameSpace(rootInfo, parseResult) { 44 if (parseResult.namespaces.length == 0) { 45 return; 46 } 47 let lastNameSpace = parseResult.namespaces[parseResult.namespaces.length - 1]; 48 rootInfo.nameSpace = lastNameSpace.split('::'); 49} 50 51function createParam(parseParamInfo) { 52 let param = {}; 53 param.name = parseParamInfo.name; 54 param.type = parseParamInfo.reference ? parseParamInfo.type.replace("&", "").trim(): parseParamInfo.type 55 param.rawType = parseParamInfo.raw_type; 56 param.isPointer = (parseParamInfo.pointer == 1); 57 param.isReference = (parseParamInfo.reference == 1); 58 param.isArray = (parseParamInfo.array == 1); 59 param.isConstant = (parseParamInfo.constant == 1); 60 return param; 61} 62 63function createFuncInfo(parseFuncInfo) { 64 let funcInfo = { 65 "name": "", // 方法名 66 "params": [], // 参数列表 67 "retType": "", // 返回值 68 "rawStr": "" // 方法原始代码 69 } 70 funcInfo.name = parseFuncInfo.name; 71 72 let parseParams = parseFuncInfo.parameters; 73 for(var i = 0; i < parseParams.length; ++i) { 74 let param = createParam(parseParams[i]); 75 funcInfo.params.push(param); 76 } 77 78 funcInfo.retType = parseFuncInfo.returns === '' ? parseFuncInfo.rtnType : parseFuncInfo.returns; 79 funcInfo.rawStr = parseFuncInfo.debug; 80 return funcInfo; 81} 82 83function createClassFunctions(parseFuncs) { 84 let funcList = []; 85 for(var i = 0; i < parseFuncs.length; ++i) { 86 if (!(parseFuncs[i].constructor || parseFuncs[i].destructor)) { // 构造和析构方法不需要生成remote接口代码 87 let funcInfo = createFuncInfo(parseFuncs[i]); 88 funcList.push(funcInfo); 89 } 90 } 91 return funcList; 92} 93 94function createClassInfo(parseClassInfo) { 95 let classInfo = { 96 "name": "", 97 "namespace": [], 98 "properties": [], 99 "functions": [], 100 "extends":[] 101 } 102 classInfo.name = parseClassInfo.name; 103 classInfo.namespace = parseClassInfo.namespace.split('::'); 104 classInfo.functions = createClassFunctions(parseClassInfo.methods.public); 105 106 return classInfo; 107} 108 109function analyzeClasses(rootInfo, parseClasses) { 110 if (parseClasses.length == 0) { 111 NapiLog.logError("Can not find any class."); 112 return; 113 } 114 115 let firstClassName = null; // JSON集合中第一个class名称 116 let serviceClassName = null;// JSON集合中带“@ServiceClass”注解的class名称 117 let i = 0; 118 for(var className in parseClasses) { 119 if (++i == 1) { 120 firstClassName = className; 121 } 122 123 let doxygen = parseClasses[className].doxygen; 124 if (doxygen && doxygen.includes("@ServiceClass")) { 125 serviceClassName = className; 126 break; 127 } 128 } 129 130 if (parseClasses.length == 1) { 131 // h文件中只有唯一的一个类,基于该类的接口定义生成service 132 rootInfo.serviceName = firstClassName; 133 let classInfo = createClassInfo(parseClasses[firstClassName]); 134 rootInfo.class.push(classInfo); 135 } else { 136 // h文件中有多个类,基于带@ServiceClass注解的类生成service 137 if (serviceClassName == null) { 138 NapiLog.logError("There must be one class that contains @ServiceClass annotations."); 139 return; 140 } 141 rootInfo.serviceName = serviceClassName; 142 let classInfo = createClassInfo(parseClasses[serviceClassName]); 143 rootInfo.class.push(classInfo); 144 } 145} 146 147function doAnalyze(hFilePath, cmdParam) { 148 let parseResult = parseFileAll(hFilePath); 149 parseResult.isInclude = false; 150 AllParseFileList.push(parseResult); 151 let rootInfo = { 152 "serviceName": "", 153 "nameSpace": [], 154 "class": [], 155 "includes": [], 156 "using": [], 157 "serviceId": cmdParam.serviceId == null ? "9002" : cmdParam.serviceId, 158 "rawContent": parseResult.rawContent 159 } 160 161 analyzeNameSpace(rootInfo, parseResult); 162 analyzeClasses(rootInfo, parseResult.classes); 163 rootInfo.includes = parseResult.includes; 164 rootInfo.using = parseResult.using; 165 return rootInfo; 166} 167 168module.exports = { 169 doAnalyze 170} 171