• 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 { NapiLog } = require('../tools/napi_log');
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('./header_parser.py')) {
25        // call python file (for debug test)
26        cmd = 'python ./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 (let 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 (let 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 (let 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 || serviceClassName === undefined) {
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 || cmdParam.serviceId === undefined) ?
158            '9002' : cmdParam.serviceId,
159        'versionTag': (cmdParam.versionTag === null || cmdParam.versionTag === undefined) ?
160            '3.2' : cmdParam.versionTag,
161        'rawContent': parseResult.rawContent
162    };
163
164    analyzeNameSpace(rootInfo, parseResult);
165    analyzeClasses(rootInfo, parseResult.classes);
166    rootInfo.includes = parseResult.includes;
167    rootInfo.using = parseResult.using;
168    return rootInfo;
169}
170
171module.exports = {
172    doAnalyze
173};