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 fs = require("fs"); 16const os = require("os"); 17const { NapiLog } = require("../tools/NapiLog"); 18const { writeFile, createFolder } = require("../tools/FileRW"); 19const re = require("../tools/re"); 20const gen = require("./generate"); 21const path = require('path'); 22 23function parseFileAll(hFilePath) { 24 let execSync = require("child_process").execSync; 25 let cmd = ""; 26 if(fs.existsSync("./hdc/service-gen/src/gen/header_parser.py")) { 27 // call python file (for debug test) 28 cmd = "python ./hdc/service-gen/src/gen/header_parser.py " + hFilePath; 29 } else { 30 // call exe file (for real runtime) 31 let sysInfo = os.platform(); 32 let execPath = path.dirname(process.execPath); 33 let exeFile = sysInfo === 'win32' ? path.join(execPath, "header_parser.exe") : 34 path.join(execPath, "header_parser"); 35 cmd = exeFile + " " + hFilePath; 36 } 37 38 let parseResult = null; 39 let stdout = execSync(cmd); 40 parseResult = JSON.parse(stdout.toString()).result; 41 return parseResult; 42} 43 44function analyzeNameSpace(rootInfo, parseResult) { 45 if (parseResult.namespaces.length == 0) { 46 return; 47 } 48 let lastNameSpace = parseResult.namespaces[parseResult.namespaces.length - 1]; 49 rootInfo.nameSpace = lastNameSpace.split('::'); 50} 51 52function createParam(parseParamInfo) { 53 let param = {}; 54 param.name = parseParamInfo.name; 55 param.type = parseParamInfo.type; 56 param.rawType = parseParamInfo.raw_type; 57 param.isPointer = (parseParamInfo.pointer == 1); 58 param.isReference = (parseParamInfo.reference == 1); 59 param.isArray = (parseParamInfo.array == 1); 60 param.isConstant = (parseParamInfo.constant == 1); 61 return param; 62} 63 64function createFuncInfo(parseFuncInfo) { 65 let funcInfo = { 66 "name": "", // 方法名 67 "params": [], // 参数列表 68 "retType": "", // 返回值 69 "rawStr": "" // 方法原始代码 70 } 71 funcInfo.name = parseFuncInfo.name; 72 73 let parseParams = parseFuncInfo.parameters; 74 for(var i = 0; i < parseParams.length; ++i) { 75 let param = createParam(parseParams[i]); 76 funcInfo.params.push(param); 77 } 78 79 funcInfo.retType = parseFuncInfo.returns === '' ? parseFuncInfo.rtnType : parseFuncInfo.returns; 80 funcInfo.rawStr = parseFuncInfo.debug; 81 return funcInfo; 82} 83 84function createClassFunctions(parseFuncs) { 85 let funcList = []; 86 for(var i = 0; i < parseFuncs.length; ++i) { 87 if (!(parseFuncs[i].constructor || parseFuncs[i].destructor)) { // 构造和析构方法不需要生成remote接口代码 88 let funcInfo = createFuncInfo(parseFuncs[i]); 89 funcList.push(funcInfo); 90 } 91 } 92 return funcList; 93} 94 95function createClassInfo(parseClassInfo) { 96 let classInfo = { 97 "name": "", 98 "namespace": [], 99 "properties": [], 100 "functions": [], 101 "extends":[] 102 } 103 classInfo.name = parseClassInfo.name; 104 classInfo.namespace = parseClassInfo.namespace.split('::'); 105 classInfo.functions = createClassFunctions(parseClassInfo.methods.public); 106 107 return classInfo; 108} 109 110function analyzeClasses(rootInfo, parseClasses) { 111 if (parseClasses.length == 0) { 112 return; 113 } 114 115 for(var className in parseClasses) { 116 rootInfo.serviceName = className; 117 let classInfo = createClassInfo(parseClasses[className]); 118 rootInfo.class.push(classInfo); 119 break; // 只取首个class(每个接口文件中应该只包含一个service class) 120 } 121} 122 123function wirte2Disk(fileInfo, destDir) { 124 let filePath = re.pathJoin(destDir, fileInfo.name); 125 writeFile(filePath, fileInfo.content); 126} 127 128function doAnalyze(hFilePath, cmdParam) { 129 let destDir = cmdParam.out; 130 let parseResult = parseFileAll(hFilePath); 131 let rootInfo = { 132 "serviceName": "", 133 "nameSpace": [], 134 "class": [], 135 "includes": [], 136 "serviceId": cmdParam.serviceId == null ? "9002" : cmdParam.serviceId 137 } 138 // 1. h文件解析保存为结构体 139 analyzeNameSpace(rootInfo, parseResult); 140 analyzeClasses(rootInfo, parseResult.classes); 141 rootInfo.includes = parseResult.includes; 142 143 // 2. 根据结构体生成代码 144 let fileContent = gen.doGenerate(rootInfo); 145 146 // 3. 创建service工程目录 147 let serviceFolder = rootInfo.serviceName.toLowerCase() + "service"; 148 let outputPath = destDir + "/" + serviceFolder; 149 createFolder(re.pathJoin(destDir, serviceFolder)); 150 createFolder(re.pathJoin(outputPath, "include")); 151 createFolder(re.pathJoin(outputPath, "interface")); 152 createFolder(re.pathJoin(outputPath, "sa_profile")); 153 createFolder(re.pathJoin(outputPath, "etc")); 154 createFolder(re.pathJoin(outputPath, "src")); 155 156 // 4. 生成代码保存为文件 157 wirte2Disk(fileContent.iServiceHFile, outputPath + "/interface"); 158 wirte2Disk(fileContent.proxyHFile, outputPath + "/include"); 159 wirte2Disk(fileContent.stubHFile, outputPath + "/include"); 160 wirte2Disk(fileContent.serviceHFile, outputPath + "/include"); 161 wirte2Disk(fileContent.proxyCppFile, outputPath + "/src"); 162 wirte2Disk(fileContent.stubCppFile, outputPath + "/src"); 163 wirte2Disk(fileContent.serviceCppFile, outputPath + "/src"); 164 wirte2Disk(fileContent.clientCppFile, outputPath + "/src"); 165 wirte2Disk(fileContent.buildGnFile, outputPath); 166 wirte2Disk(fileContent.bundleJsonFile, outputPath); 167 wirte2Disk(fileContent.profileGnFile, outputPath + "/sa_profile"); 168 wirte2Disk(fileContent.profileXmlFile, outputPath + "/sa_profile"); 169 wirte2Disk(fileContent.serviceCfgFile, outputPath + "/etc"); 170 wirte2Disk(fileContent.serviceCfgGnFile, outputPath + "/etc"); 171} 172 173module.exports = { 174 doAnalyze 175} 176