• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2* Copyright (c) 2024 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*/
15
16import { DirTemp, FuncInfo, GenInfo, InterfaceList, TypeList } from "./datatype";
17import { getInterfaceBody, getTypeBody } from "./gendts";
18import {
19  boolIn, boolRet, doubleIn, doubleRet, funcGetParamTemplate, int32tIn,
20  int32tRet, int64tIn, int64tRet, napiFuncCppTemplate,
21  napiFuncRetTemplate, objectRet, objectTosetRet, paramGenTemplate, stringIn,
22  stringRet, uint32tIn, uint32tRet
23} from "../template/func_template";
24import { replaceAll } from "../common/tool";
25import { cppdir } from "../template/dtscpp/dtscppdir";
26import * as path from 'path';
27import * as fs from 'fs';
28import { genInitCppFile } from "./tools/gennapiinit";
29import { genNapiHFile } from "./tools/gennapih";
30import { genNapiCppFile } from "./tools/gennapicpp";
31import { genCommonHFile } from "./tools/gennapicommonh";
32import { genCommonCppFile } from "./tools/gennapicommoncpp";
33import { genNapiCommonFile } from "./tools/gencommonfile";
34
35interface RetObjInfo {
36  objName: string;
37  flag: boolean;
38}
39
40export function generateDirectFunction(funcInfo: FuncInfo, rawFileName: string, typeList: TypeList[], interfaceList: InterfaceList[]) {
41
42  // 生成
43  let paramGenResult = genParamInfo(funcInfo, typeList);
44
45  // 返回值处理  对于对象要使用循环处理
46  let retGenResult = '';
47  let retObjInfo: RetObjInfo = {
48      objName: '',
49      flag: false
50  };
51
52  let returnType = replaceAll(funcInfo.retType, '*', '').trim();
53  retGenResult = returnTypeC2Js(funcInfo.name, returnType, retGenResult, retObjInfo, typeList, interfaceList);
54
55  let bodyReplace = getReplaceInfo(funcInfo, rawFileName);
56
57  let genParamReplace = getGenParamReplace(funcInfo, paramGenResult);
58  bodyReplace = getBodyReplace2(funcInfo, bodyReplace, genParamReplace);
59  if (funcInfo.retType.replace('*', '').trim() !== 'void') {
60      let returnType = funcInfo.retType === 'std::string' ? 'const char *' : funcInfo.retType;
61      returnType = returnType === 'size_t' ? 'int64_t' : returnType;
62      let funcReturnReplace = replaceAll(napiFuncRetTemplate, '[return_name]', retObjInfo.objName);
63      funcReturnReplace = replaceAll(funcReturnReplace, '[func_name_replace]', funcInfo.name);
64      funcReturnReplace = replaceAll(funcReturnReplace, '[return_replace]', retGenResult);
65      bodyReplace = replaceAll(bodyReplace, '[func_return_replace]', funcReturnReplace);
66  } else {
67      bodyReplace = replaceAll(bodyReplace, '[func_return_replace]', '    return NULL;\n');
68  }
69  bodyReplace = replaceAll(bodyReplace, '[return_replace]', retGenResult);
70
71
72  return bodyReplace;
73}
74
75export function getReplaceInfo(funcInfo: FuncInfo, hFileName: string) {
76  let funcInfoParams = genFuncInfoParams(funcInfo);
77  let bodyReplace = replaceAll(napiFuncCppTemplate, '[func_name_replace]', funcInfo.name);
78  bodyReplace = replaceAll(bodyReplace, '[get_error_msg_tag]', funcInfo.name);
79  bodyReplace = replaceAll(bodyReplace, '[file_introduce_replace]', hFileName);
80  bodyReplace = replaceAll(bodyReplace, '[func_introduce_replace]', funcInfo.name);
81  bodyReplace = replaceAll(bodyReplace, '[input_introduce_replace]', funcInfoParams === '' ? 'void' : funcInfoParams);
82  bodyReplace = replaceAll(bodyReplace, '[output_introduce_replace]', funcInfo.retType);
83  return bodyReplace;
84}
85
86export function getBodyReplace2(funcInfo: FuncInfo, bodyReplace: string, genParamReplace: string) {
87  if (funcInfo.params.length !== 0) {
88    bodyReplace = replaceAll(bodyReplace, '[func_getParam_replace]', genParamReplace);
89  } else {
90    bodyReplace = replaceAll(bodyReplace, '[func_getParam_replace]', '');
91  }
92  return bodyReplace;
93}
94
95export function getGenParamReplace(funcInfo: FuncInfo, paramGenResult: string) {
96  let genParamReplace = replaceAll(funcGetParamTemplate, '[param_length]', 'PARAMS' + funcInfo.params.length);
97  genParamReplace = replaceAll(genParamReplace, '[func_name_replace]', funcInfo.name);
98  genParamReplace = replaceAll(genParamReplace, '[getAllParam_replace]', paramGenResult);
99  return genParamReplace;
100}
101
102export function genFuncInfoParams(funcInfo: FuncInfo) {
103  let funcInfoParams = '';
104  let funcInfoParamTemp = '[paramName]: [paramType]; ';
105  for (let i = 0; i < funcInfo.params.length; i++) {
106    let funcInfoParamReplace = replaceAll(funcInfoParamTemp, '[paramName]', funcInfo.params[i].name);
107    funcInfoParamReplace = replaceAll(funcInfoParamReplace, '[paramType]', funcInfo.params[i].type);
108    funcInfoParams += funcInfoParamReplace;
109  }
110  return funcInfoParams;
111}
112
113
114export function genParamInfo(funcInfo: FuncInfo, typeList: TypeList[]) {
115  let paramGenResult = '';
116  // napi 获取参数
117  for (let i = 0; i < funcInfo.params.length; i++) {
118    paramGenResult = getParamJs2C(funcInfo, i, paramGenResult, typeList);
119  }
120  return paramGenResult;
121}
122
123
124export function getParamJs2C(funcInfo: FuncInfo, i: number, paramGenResult: string, typeList: TypeList[]) {
125  let paramType = funcInfo.params[i].type === 'size_t' ? 'int64_t' : funcInfo.params[i].type;
126  // 去除const 和 *
127  paramType = paramType.replace('const', '').replace('*', '').trim();
128  let paramName = funcInfo.params[i].name;
129  let paramGen = replaceAll(paramGenTemplate, '[param_index_replace]', 'PARAMS' + i);
130  paramGen = replaceAll(paramGen, '[param_name_replace]', paramName);
131  if (paramType === 'double') {
132    paramGen = getParamGenCon(doubleIn, i, paramName, paramGen);
133    paramGenResult += paramGen;
134  } else if (paramType === 'uint32_t') {
135    paramGen = getParamGenCon(uint32tIn, i, paramName, paramGen);
136    paramGenResult += paramGen;
137  } else if (paramType === 'int32_t' || paramType === 'int') {
138    paramGen = getParamGenCon(int32tIn, i, paramName, paramGen);
139    paramGenResult += paramGen;
140  } else if (paramType === 'int64_t' || paramType === 'size_t') {
141    paramGen = getParamGenCon(int64tIn, i, paramName, paramGen);
142    paramGenResult += paramGen;
143  } else if (paramType === 'bool') {
144    paramGen = getParamGenCon(boolIn, i, paramName, paramGen);
145    paramGenResult += paramGen;
146  } else if (paramType === 'std::string' || paramType.indexOf('char') >= 0) {
147    paramGen = getParamGenCon(stringIn, i, paramName, paramGen);
148    paramGenResult += paramGen;
149  } else if (getTypeBody(paramType, typeList)) {
150    // typedefs
151    funcInfo.params[i].type = getTypeBody(paramType, typeList) as string;
152    paramGenResult = getParamJs2C(funcInfo, i, paramGenResult, typeList);
153  }
154  // 其他情况,处理成对象 napi_get_cb_info之后不做任何处理
155  return paramGenResult;
156}
157
158export function getParamGenCon(getParamContent: string, i: number, paramName: string, paramGen: string) {
159  let getParam = replaceAll(getParamContent, '[param_index_replace]', 'PARAMS' + i);
160  getParam = replaceAll(getParam, '[param_name_replace]', paramName);
161  paramGen = replaceAll(paramGen, '[getParam_replace]', getParam);
162  return paramGen;
163}
164
165export function returnTypeC2Js(returnName: string, retType: string, retGenResult: string, retObjInfo: RetObjInfo, typeList: TypeList[], interfaceList: InterfaceList[]) {
166  if (!retObjInfo.flag) {
167      retObjInfo.objName = returnName;
168  }
169  if (retType === 'uint32_t') {
170      retGenResult = getRetTypeContent(uint32tRet, returnName, retGenResult, retObjInfo, objectTosetRet);
171  } else if (retType === 'double') {
172      retGenResult = getRetTypeContent(doubleRet, returnName, retGenResult, retObjInfo, objectTosetRet);
173  } else if (retType === 'int32_t' || retType === 'int') {
174      retGenResult = getRetTypeContent(int32tRet, returnName, retGenResult, retObjInfo, objectTosetRet);
175  } else if (retType === 'int64_t' || retType === 'size_t') {
176      retGenResult = getRetTypeContent(int64tRet, returnName, retGenResult, retObjInfo, objectTosetRet);
177  } else if (retType === 'bool') {
178      retGenResult = getRetTypeContent(boolRet, returnName, retGenResult, retObjInfo, objectTosetRet);
179  } else if (retType === 'std::string' || retType.substring(0, 10) === 'const char' ||
180        retType === 'char') {
181      retGenResult = getRetTypeContent(stringRet, returnName, retGenResult, retObjInfo, objectTosetRet);
182  } else if (getInterfaceBody(retType, interfaceList)) {
183      // 返回值是对象
184      if (!retObjInfo.flag) {
185          retGenResult += replaceAll(objectRet, '[return_name_replace]', returnName);
186          retObjInfo.flag = true;
187          let objectProperty = getInterfaceBody(retType, interfaceList)
188          // 遍历属性
189          for (let i = 0; i < objectProperty!.params.length; i++) {
190              let name = objectProperty!.params[i].name;
191              let type = objectProperty!.params[i].type;
192              let testRes = returnTypeC2Js(name, type, retGenResult, retObjInfo, typeList, interfaceList);
193              retGenResult = testRes;
194          }
195      } else {
196          retGenResult = getObjRetGenResult(retObjInfo, retGenResult, returnName);
197      }
198  } else if (getTypeBody(retType, typeList)) {
199    // typedefs
200    let funcRetType = getTypeBody(retType, typeList) as string;
201    retGenResult = returnTypeC2Js(returnName, funcRetType, retGenResult, retObjInfo,typeList, interfaceList);
202  }
203  return retGenResult;
204}
205
206export function getObjRetGenResult(retObjInfo: RetObjInfo, retGenResult: string, returnName: string) {
207  if (retObjInfo.objName !== '') {
208    retGenResult += replaceAll(objectRet, '[return_name_replace]', returnName);
209    let setRetPropertyObj = replaceAll(objectTosetRet, '[set_objname_replace]', retObjInfo.objName);
210    setRetPropertyObj = replaceAll(setRetPropertyObj, '[set_propname_replace]', returnName);
211    setRetPropertyObj = replaceAll(setRetPropertyObj, '[set_propvalue_replace]', returnName);
212    retGenResult += setRetPropertyObj;
213  }
214  return retGenResult;
215}
216
217export function getRetTypeContent(retTypeTemplate: string, returnName: string, retGenResult: string,
218  retObjInfo: RetObjInfo, setRetProperty: string) {
219  let funcReturnType = replaceAll(retTypeTemplate, '[return_name_replace]', returnName);
220  retGenResult += funcReturnType;
221  if (retObjInfo.flag) {
222    setRetProperty = replaceAll(setRetProperty, '[set_objname_replace]', retObjInfo.objName);
223    setRetProperty = replaceAll(setRetProperty, '[set_propname_replace]', returnName);
224    setRetProperty = replaceAll(setRetProperty, '[set_propvalue_replace]', returnName);
225    retGenResult += setRetProperty;
226  }
227  return retGenResult;
228}
229
230
231// ------------------------------  gencpp -----------------------------
232const fileHandlers: { [key: string]: Function } = {
233  '[fileName]init.cpp': genInitCppFile,
234  '[fileName]napi.h': genNapiHFile,
235  '[fileName]napi.cpp': genNapiCppFile,
236  '[fileName]common.h': genCommonHFile,
237  '[fileName]common.cpp': genCommonCppFile,
238  '[fileName].h': genNapiCommonFile,
239  'readme.md': genNapiCommonFile
240};
241
242export function genDir(dirItem: DirTemp, rootInfo: GenInfo, out: string) {
243  let dirPath = path.join(out, dirItem.name);
244  let lowerFileName = rootInfo.fileName.toLocaleLowerCase();
245  // 创建目录
246  if (!fs.existsSync(dirPath)) {
247    fs.mkdirSync(dirPath, { recursive: true });
248  }
249  // 遍历生成当前目录文件
250  dirItem.files.forEach(file => {
251    let fileName = file.name.replace('[fileName]', lowerFileName);
252    let filePath = path.join(dirPath, fileName);
253    // 将content写入文件, 这里的content是模板,需要replace里面的部分内容
254    if (!fs.existsSync(filePath)) {
255      // 拿到每个文件并且根据文件生成内容并写入
256      const handler = fileHandlers[file.name];
257      if (handler) {
258        // 调用对应的生成文件方法
259        handler(rootInfo, filePath, file.content);
260      }
261    }
262  })
263  // 遍历子目录,生成子目录的文件
264  dirItem.dirs.forEach(subDir => {
265    genDir(subDir, rootInfo, dirPath);
266  })
267}
268
269// gen h and cpp file.
270export function genHCppFile(rootInfo: GenInfo, out: string) {
271  if (out === undefined || out === null || out.trim() === '') {
272    out = path.dirname(rootInfo.rawFilePath);
273  }
274  genDir(cppdir, rootInfo, out);
275}
276
277
278