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