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