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*/ 15import fs = require('fs'); 16import { DtscppRootInfo, FuncObj, InterfaceBody, ParamObj, FuncInfo, GenInfo, InterfaceList, TypeList } from './datatype'; 17import { cpp2DtsKey } from '../template/dtscpp/dts2cpp_key'; 18import path = require('path'); 19import { Logger } from '../common/log'; 20 21import { generateRandomInteger, removeComments, removeTab, replaceAll } from '../common/tool'; 22import util = require('util'); 23import re = require('../common/re'); 24import { dtsFuncTemplate } from '../template/func_template'; 25const dtsFileExt = '.d.ts'; 26 27export function genTsFunction(func: FuncInfo, rawFileName: string) { 28 let funcParams = ''; 29 for (let i = 0; i < func.params.length; ++i) { 30 funcParams += i > 0 ? ', ' : ''; 31 funcParams += func.params[i].name + ': ' + func.params[i].type; 32 } 33 let funcContent = replaceAll(dtsFuncTemplate, '[file_introduce_replace]', rawFileName); 34 funcContent = replaceAll(funcContent, '[func_introduce_replace]', func.name); 35 funcContent = replaceAll(funcContent, '[input_introduce_replace]', funcParams === '' ? 'void' : funcParams); 36 funcContent = replaceAll(funcContent, '[func_name_replace]', func.name); 37 funcContent = replaceAll(funcContent, '[func_param_replace]', funcParams); 38 funcContent = replaceAll(funcContent, '[func_return_replace]', func.retType); 39 40 return funcContent; 41} 42 43 44export function getInterFuncRetType(str: string) { 45 let strArr = str.split(' '); 46 // let retType = getJsTypeFromC(replaceAll(strArr[0], '*', '')); 47 return replaceAll(strArr[0], '*', ''); 48} 49 50export function getInterFuncName(str: string) { 51 let strArr = str.split(' '); 52 return replaceAll(strArr[1], '*', ''); 53} 54 55 56export function getInterFuncParams(str: string, paramObj: ParamObj[]) { 57 let paramsStr = ''; 58 let paramObject: ParamObj = { 59 name: '', 60 type: '', 61 arraySize: 0, 62 arraySizeList: [] 63 } 64 let paramArr = replaceAll(str, '*', '').split(','); 65 for (let i = 0; i < paramArr.length; i++) { 66 let param = removeTab(paramArr[i]).split(' '); 67 const paramType = replaceAll(param[0], ' ', ''); 68 const paramVal = replaceAll(param[1], ' ', ''); 69 paramObject.name = paramVal; 70 paramObject.type = paramType; 71 paramObj.push(paramObject); 72 let rawType = transTskey2Ckey(paramType); 73 paramsStr += paramVal + ': ' + rawType; 74 if (i !== paramArr.length - 1) { 75 paramsStr += ', '; 76 } 77 } 78 return paramsStr; 79} 80 81export function isJsBasicType(type: string) { 82 if (type === 'number' || type === 'string' || type === 'boolean') { 83 return true; 84 } else { 85 return false; 86 } 87} 88 89export function removeMarco(type: string) { 90 // 去掉宏定义 91 if (type) { 92 let leftCraftIndex = type.indexOf('('); 93 let rightCraftIndex = type.indexOf(')'); 94 if (leftCraftIndex >= 0 && rightCraftIndex > 0) { 95 type = removeTab(type.substring(leftCraftIndex + 1, rightCraftIndex)); 96 } 97 } 98 99 return type; 100} 101 102export function createParam(parseParamInfo: ParamObj) { 103 let tsParam: ParamObj = { 104 name: '', 105 type: '', 106 arraySize: 0, 107 arraySizeList: [] 108 }; 109 110 let cppParam: ParamObj = { 111 name: '', 112 type: '', 113 arraySize: 0, 114 arraySizeList: [] 115 }; 116 tsParam.name = replaceAll(parseParamInfo.name, '*', ''); 117 cppParam.name = tsParam.name; 118 cppParam.type = removeMarco(parseParamInfo.type); 119 let rawType = transTskey2Ckey(parseParamInfo.type); 120 tsParam.type = removeMarco(rawType); 121 return [tsParam, cppParam]; 122} 123 124export function createFuncInfo(parseFuncInfo: FuncObj) { 125 let funcInfo: FuncInfo = { 126 name: '', 127 params: [], 128 retType: '', 129 }; 130 131 let cppFuncInfo: FuncInfo = { 132 name: '', 133 params: [], 134 retType: '', 135 } 136 funcInfo.name = parseFuncInfo.name; 137 cppFuncInfo.name = parseFuncInfo.name; 138 let parseParams = parseFuncInfo.parameters; 139 for (let i = 0; i < parseParams.length; ++i) { 140 let paramsRes = createParam(parseParams[i]); 141 let tsParam = paramsRes[0] 142 let cppParam = paramsRes[1]; 143 if (tsParam.type !== '') { 144 funcInfo.params.push(tsParam); 145 cppFuncInfo.params.push(cppParam); 146 } 147 } 148 149 let retType = parseFuncInfo.returns === '' ? 'void' : parseFuncInfo.returns; 150 retType = removeMarco(retType); 151 cppFuncInfo.retType = retType; 152 funcInfo.retType = transTskey2Ckey(retType); 153 return [funcInfo, cppFuncInfo]; 154} 155 156export function analyzeRootFunction(funcInfo: FuncInfo[], cppFuncInfo: FuncInfo[], parseFunctions: FuncObj[]) { 157 for (let i = 0; i < parseFunctions.length; ++i) { 158 let result = createFuncInfo(parseFunctions[i]); 159 funcInfo[i] = result[0]; 160 cppFuncInfo[i] = result[1]; 161 } 162} 163 164export function genDtsInterface(path: string, typeList: TypeList[], interfaceList: InterfaceList[]) { 165 // 解析typedef: 使用正则表达式提取typedef struct定义 166 const typedefsRegex1 = /typedef\s+struct\s+\w+\s*{\s*[\s\S]*?}\s*\w+;/g; 167 // 正则表达式匹配 typedef 后跟基本数据类型和自定义类型名称 168 const typedefsRegex2 = /typedef\s+\w+\s+\w+\s*;/g; 169 // 正则表达式匹配 class xxx {}; 170 const classRegex = /class\s+(\w+)\s+([a-zA-Z0-9_]+)?\s*(\{[^}]*\};)/g; 171 let rawContent = removeComments(fs.readFileSync(path).toString()); 172 let structMatch = rawContent.match(typedefsRegex1); 173 if (!structMatch) { 174 structMatch = rawContent.match(classRegex); 175 } 176 let basicTypeMatch = rawContent.match(typedefsRegex2); 177 let interfaceListDef: string = ''; 178 179 // 使用正则表达式的 exec 方法来获取匹配项 180 if (structMatch) { 181 for (let index = 0; index < structMatch.length; index++) { 182 let matchs = removeComments(structMatch[index]); 183 let structIndex = matchs.indexOf('struct'); 184 let classIndex = matchs.indexOf('class') 185 let leftIndex = matchs.indexOf('{'); 186 let rightIndex = matchs.indexOf('}'); 187 let interfaceName = ''; 188 if (structIndex >= 0) { 189 interfaceName = matchs.substring(structIndex + 6, leftIndex).trim(); 190 } else if (classIndex >= 0) { 191 interfaceName = matchs.substring(classIndex + 5, leftIndex).trim(); 192 } 193 let params = matchs.substring(leftIndex + 1, rightIndex).split(';'); 194 let interDefine = 'interface ' + interfaceName + ' {\n'; 195 let paramsContent: ParamObj[] = []; 196 let interFuncsContent: FuncObj[] = []; 197 let interfaceBody: InterfaceBody = { 198 params: paramsContent, 199 funcs: interFuncsContent 200 } 201 let interfaceContent: InterfaceList = { 202 interfaceName: interfaceName, 203 interfaceBody: interfaceBody 204 } 205 for (let i = 0; i < params.length; i++) { 206 // 去除空格和换行符 207 let paramStr = removeTab(params[i]); 208 if (paramStr === '') { 209 continue; 210 } 211 // 成员函数的处理 212 const funcRegex = /\w+\s+\*?\(([^\)]+)\)\s*\(([^\)]*)\)\s*/; 213 const funcRegex2 = /(\w+)\s+(::\w+|[\w:]+)\s*\(([^)]*)\)\s*/; 214 let match = paramStr.match(funcRegex); 215 let match2 = paramStr.match(funcRegex2); 216 if (match) { 217 // 处理成员函数 仅仅限于成员函数是函数指针的情况 218 let interFuncParams: ParamObj[] = [] 219 let returnType = getInterFuncRetType(match[0]); 220 let funcName = getInterFuncName(match[1]); 221 let params = getInterFuncParams(match[2], interFuncParams); 222 interDefine += util.format(' %s:(%s) => %s;\n',funcName, params, returnType); 223 let funcObj: FuncObj = { 224 type: '', 225 name: funcName, 226 returns: returnType, 227 parameters: interFuncParams 228 } 229 interFuncsContent.push(funcObj); 230 } else if (match2) { 231 let interFuncParams: ParamObj[] = [] 232 let returnType = getInterFuncRetType(match2[1]); 233 let funcName = match2[2]; 234 let params = getInterFuncParams(match2[3], interFuncParams); 235 interDefine += util.format(' %s:(%s) => %s;\n',funcName, params, returnType); 236 let funcObj: FuncObj = { 237 type: '', 238 name: funcName, 239 returns: returnType, 240 parameters: interFuncParams 241 } 242 interFuncsContent.push(funcObj); 243 } else { 244 let lastTabIndex = paramStr.lastIndexOf(' '); 245 const variableName = paramStr.substring(lastTabIndex + 1, paramStr.length).replace('*', '') 246 const variabletype = paramStr.substring(0, lastTabIndex); 247 let rawType = transTskey2Ckey(variabletype); 248 if (!isJsBasicType(rawType)) { 249 rawType += ' | null'; 250 } 251 let variableDefine = ' ' + variableName + ': ' + rawType + ';\n' 252 interDefine += variableDefine; 253 let paramObj: ParamObj = { 254 name: variableName, 255 type: replaceAll(variabletype, 'struct', '').trim(), 256 arraySize: 0, 257 arraySizeList: [] 258 } 259 paramsContent.push(paramObj); 260 } 261 } 262 interfaceBody.funcs = interFuncsContent; 263 interfaceBody.params = paramsContent; 264 interfaceContent.interfaceBody = interfaceBody; 265 interfaceList.push(interfaceContent); 266 267 interDefine += '}\n'; 268 interfaceListDef += interDefine; 269 } 270 } 271 272 if (basicTypeMatch) { 273 for (let index = 0; index < basicTypeMatch.length; index++) { 274 // 输出匹配的基本类型定义 275 Logger.getInstance().debug('Basic type typedef match:' + basicTypeMatch[0]); 276 let matchs = basicTypeMatch[index].split(' '); 277 let rawType = transTskey2Ckey(matchs[1].trim()); 278 let defineType = matchs[2].split(';') 279 let typedefine = 'type ' + defineType[0] + ' = ' + rawType + ';\n'; 280 interfaceListDef += typedefine; 281 let typeListContent: TypeList = { 282 typeName: defineType[0], 283 typeBody: matchs[1].trim() 284 } 285 typeList.push(typeListContent); 286 } 287 } 288 289 return interfaceListDef; 290} 291 292export function getTypeBody(testType: string, typeList: TypeList[]) { 293 for (let i = 0; i < typeList.length; i++) 294 { 295 if (typeList[i].typeName === testType) { 296 return typeList[i].typeBody; 297 } 298 return ''; 299 } 300} 301 302export function getInterfaceBody(testType: string, interfaceList: InterfaceList[]) { 303 for (let i = 0; i < interfaceList.length; i++) 304 { 305 if (interfaceList[i].interfaceName === testType) { 306 return interfaceList[i].interfaceBody; 307 } 308 } 309} 310 311//---------------------------- 312 313// h2dts 314export function transTskey2Ckey(key: string): string { 315 // 判断是否是std::function, 转换为箭头函数 如:std::function<void(int, int)> 转换为 (a: number, b: number)=>void 316 const regexFunction = /\b(std::)?function<([\w\s\:\*]+)\s*\(([\w\:\<\>\,\s*]*)\)>/; 317 const matchFunction = key.match(regexFunction); 318 if (matchFunction) { 319 const returnType = matchFunction[2].trim(); // 返回类型 320 let paramstr = matchFunction[3] ? matchFunction[3].trim() : '' 321 let paramreg = /([\w\s\:\*]+<[^>]*>|[\*\w\s\:]+)/g; 322 let pmatch; 323 let paramList = []; 324 while ((pmatch = paramreg.exec(paramstr)) !== null) { 325 paramList.push(pmatch[0]); 326 } 327 let str = ''; 328 for (let i = 0; i < paramList.length; ++i) { 329 str += paramList[i].trim() === ''? '': `param${i}: ${transTskey2Ckey(paramList[i])}`; 330 if (i != paramList.length - 1) { 331 str += ', '; 332 } 333 } 334 return `(${str})=>${transTskey2Ckey(returnType)}`; 335 } 336 337 // 智能指针,例如: std::unique_ptr<int> -> number 338 const regexSmartPtr = /\b((std::)?(?:unique_ptr|shared_ptr|weak_ptr))\s*<([\w\:\<\>\,\s*]+)>/; 339 const matchSmartPtr = key.match(regexSmartPtr); 340 if (matchSmartPtr) { 341 return transTskey2Ckey(matchSmartPtr[3].trim()); 342 } 343 344 // 判断迭代器: 如std::vector<int>::iterator -> IterableIterator<Array<number>> 345 const regexIterator = /(std::(string|(\w+<[^>]+>)))::iterator/; 346 const matchIterator = key.match(regexIterator); 347 if (matchIterator) { 348 return 'IterableIterator<' + transTskey2Ckey(matchIterator[1].trim()) + '>'; 349 } 350 351 // 转换为Array<xxx>类型 352 const regexArray = /\b((std::)?(?:vector|array|deque|list|forward_list|stack|queue|valarray|priority_queue))\s*<([^>]*)>/; 353 const matchArray = key.match(regexArray); 354 if (matchArray) { 355 return `Array<${transTskey2Ckey(matchArray[3])}>`; 356 } 357 358 // 转换为Map<xxx, xxx>类型 359 const regexMap = /\b((std::)?(?:map|unordered_map|multimap|unordered_multimap))\s*<([^>]*)>/; 360 const matchMap = key.match(regexMap); 361 if (matchMap) { 362 const arr = matchMap[3].split(','); 363 if (arr.length == 2) { 364 return `Map<${transTskey2Ckey(arr[0])}, ${transTskey2Ckey(arr[1])}>`; 365 } 366 } 367 368 // 转换为Set<xxx> 369 const regexSet = /\b((std::)?(?:set|unordered_set|multiset|unordered_multiset))\s*<([^>]*)>/; 370 const matchSet = key.match(regexSet); 371 if (matchSet) { 372 return `Set<${transTskey2Ckey(matchSet[3])}>`; 373 } 374 375 // 转换为元组 376 const regexTuple = /\b((std::)?(?:tuple|pair))\s*<([^>]*)>/; 377 const matchTuple = key.match(regexTuple); 378 if (matchTuple) { 379 const arr = matchTuple[3].split(','); 380 let str = ''; 381 for (let i = 0; i < arr.length; ++i) { 382 str += transTskey2Ckey(arr[i]); 383 if (i != arr.length - 1) { 384 str += ', '; 385 } 386 } 387 return `[${str}]`; 388 } 389 390 // 判断是否是std::complex , 将复数类型转换为{real: number, imag: number}类型 391 const regexComplex = /\b((std::)?(?:complex))\s*<([^<>]*)>/; 392 const matchComplex = key.match(regexComplex); 393 if (matchComplex) { 394 const type = transTskey2Ckey(matchComplex[3].trim()); // 返回类型 395 return `{real: ${type}, imag: ${type}}`; 396 } 397 398 // 判断日期类型: std::time_t /std::clock_t /std::tm 转换为ts的Date类型 399 const regexDate = /\b((std::)?(?:time_t|clock_t|tm|(?:chrono::(time_point|duration|system_clock|steady_clock|high_resolution_clock|hours|minutes|seconds|milliseconds|microseconds|nanoseconds))))\b/; 400 const matchDate = key.match(regexDate); 401 if (matchDate) { 402 return 'Date'; 403 } 404 for(const keyItem of cpp2DtsKey) { 405 for(const str of keyItem.keys) { 406 if (key.includes(str)) { 407 return keyItem.value; 408 } 409 } 410 } 411 let replaceKeyList = ['enum', 'struct', 'union']; 412 for(const rkey of replaceKeyList) { 413 key = key.replace(rkey, '').trim(); 414 } 415 // 其他类型转换为 any 类型,如typeDef定义的类型 416 return 'any' 417} 418 419export function getDtsEnum(rootInfo: GenInfo) { 420 let enumList = rootInfo.parseObj.enums; 421 let out = ''; 422 for(const enumItem of enumList) { 423 let enumHead = `export enum ${enumItem.name} {\n` 424 let enumBody = '' 425 try { 426 enumItem.members.forEach(element => { 427 enumBody += `\t${element},\n` 428 }); 429 } catch (e) { 430 let errmsg = 'generate dts file error: ' + JSON.stringify(e); 431 Logger.getInstance().error(errmsg); 432 } 433 out += enumHead + enumBody + '};\n\n' 434 if (enumItem.name && enumItem.alias && enumItem.name !== enumItem.alias) { 435 out += `export type ${enumItem.alias} = ${enumItem.name};\n\n` 436 } 437 } 438 return out; 439} 440 441export function getDtsFunction(rootInfo: GenInfo) { 442 let funcList = rootInfo.parseObj.funcs; 443 let out = ''; 444 for(const funcItem of funcList) { 445 let funcHead = ''; 446 let funcTail = ''; 447 let enumBody = '' 448 let returnType = transTskey2Ckey(funcItem.returns); 449 try { 450 if (funcItem.type === 'typedef') { 451 funcHead = `export interface ${funcItem.name} {\n`; 452 funcTail = '};\n\n'; 453 funcItem.parameters.forEach(element => { 454 if (element.name && element.type) { 455 enumBody += `${element.name}: ${transTskey2Ckey(element.type)}, ` 456 } 457 }); 458 enumBody = `\t(${enumBody.slice(0, -2)}): ${returnType};\n` 459 out += funcHead + `${enumBody}` + funcTail; 460 } else { 461 funcHead = `export function ${funcItem.name}(` 462 funcTail = `): ${returnType};\n\n`; 463 funcItem.parameters.forEach(element => { 464 if (element.name && element.type) { 465 enumBody += `${element.name}: ${transTskey2Ckey(element.type)}, ` 466 } 467 }); 468 out += funcHead + enumBody.slice(0, -2) + funcTail; 469 // 生成异步方法(callback)的dts 470 funcHead = `export function ${funcItem.name}Async(` 471 funcTail = returnType === 'void'? 'cbf: () => void): void;\n\n' : `cbf: (param: ${returnType}) => void): void;\n\n` 472 out += funcHead + enumBody + funcTail; 473 // 生成异步方法(promise)的dts 474 funcHead = `export function ${funcItem.name}Promise(` 475 funcTail = `): Promise<${returnType}>;\n\n`; 476 out += funcHead + enumBody.slice(0, -2) + funcTail; 477 } 478 } catch (e) { 479 let errmsg = 'generate dts file error: ' + JSON.stringify(e); 480 Logger.getInstance().error(errmsg); 481 } 482 } 483 return out; 484} 485 486export function getDtsClasses(rootInfo: GenInfo) { 487 let classList = rootInfo.parseObj.classes; 488 let out = ''; 489 for(const classItem of classList) { 490 let classHead = `export class ${classItem.name} {\n` 491 let classBody = '' 492 try { 493 if (classItem.variableList.length > 0) { 494 for (const attribute of classItem.variableList) { 495 classBody += `\t${attribute.name}: ${transTskey2Ckey(attribute.type)};\n` 496 }; 497 } 498 } catch (e) { 499 let errmsg = 'generate dts file error: ' + JSON.stringify(e); 500 Logger.getInstance().error(errmsg); 501 } 502 try { 503 if (classItem.functionList.length > 0) { 504 for (const method of classItem.functionList) { 505 let methodContent = ''; 506 for (const param of method.parameters) { 507 methodContent += `${param.name}: ${transTskey2Ckey(param.type)}, `; 508 } 509 classBody += `\t${method.name}(${methodContent.slice(0, -2)}): ${transTskey2Ckey(method.returns)};\n` 510 // callback方法 511 let callbackContent = method.returns === 'void'? 'cbf: () => void' : `cbf: (param: ${transTskey2Ckey(method.returns)}) => void` 512 classBody += `\t${method.name}Async(${methodContent}${callbackContent}): void;\n` 513 // promise方法 514 classBody += `\t${method.name}Promsie(${methodContent.slice(0, -2)}): Promise<${transTskey2Ckey(method.returns)}>;\n` 515 }; 516 } 517 } catch (e) { 518 let errmsg = 'generate dts file error: ' + JSON.stringify(e); 519 Logger.getInstance().error(errmsg); 520 } 521 out += classHead + classBody + '}\n\n' 522 if (classItem.name && classItem.alias) { 523 out += `export type ${classItem.alias} = ${classItem.name};\n\n` 524 } 525 } 526 return out; 527} 528 529export function getDtsStructs(rootInfo: GenInfo) { 530 let structList = rootInfo.parseObj.structs; 531 let out = ''; 532 for(const structItem of structList) { 533 let structHead = `export type ${structItem.name} = {\n` 534 let structBody = '' 535 try { 536 if (structItem.members.length > 0) { 537 for (const attribute of structItem.members) { 538 structBody += `\t${attribute.name}: ${transTskey2Ckey(attribute.type)};\n` 539 }; 540 } 541 } catch (e) { 542 let errmsg = 'generate dts file error: ' + JSON.stringify(e); 543 Logger.getInstance().error(errmsg); 544 } 545 try { 546 if (structItem.functions.length > 0) { 547 for (const method of structItem.functions) { 548 let methodContent = ''; 549 for (const param of method.parameters) { 550 if (param.name && param.type) { 551 methodContent += `${param.name}: ${transTskey2Ckey(param.type)}, `; 552 } 553 } 554 structBody += `\t${method.name}(${methodContent.slice(0, -2)}): ${transTskey2Ckey(method.returns)};\n` 555 // callback方法 556 let callbackContent = method.returns === 'void'? 'cbf: () => void' : `cbf: (param: ${transTskey2Ckey(method.returns)}) => void` 557 structBody += `\t${method.name}Async(${methodContent}${callbackContent}): void;\n` 558 // promise方法 559 structBody += `\t${method.name}Promise(${methodContent.slice(0, -2)}): Promise<${transTskey2Ckey(method.returns)}>;\n`; 560 }; 561 } 562 } catch (e) { 563 let errmsg = 'generate dts file error: ' + JSON.stringify(e); 564 Logger.getInstance().error(errmsg); 565 } 566 out += structHead + structBody + '};\n\n' 567 if (structItem.name && structItem.alias && structItem.name !== structItem.alias) { 568 out += `export type ${structItem.alias} = ${structItem.name};\n\n` 569 } 570 } 571 return out; 572} 573 574export function getDtsUnions(rootInfo: GenInfo) { 575 let unionList = rootInfo.parseObj.unions; 576 let out = ''; 577 for(const unionItem of unionList) { 578 let unionHead = `export type ${unionItem.name} = ` 579 let unionBody = '' 580 try { 581 for (const element of unionItem.members) { 582 unionBody += `${transTskey2Ckey(element.type)} | ` 583 }; 584 } catch (e) { 585 let errmsg = 'generate dts file error: ' + JSON.stringify(e); 586 Logger.getInstance().error(errmsg); 587 } 588 out += unionHead + unionBody.slice(0, -2) + ';\n\n' 589 if (unionItem.name && unionItem.alias && unionItem.name !== unionItem.alias) { 590 out += `export type ${unionItem.alias} = ${unionItem.name};\n\n` 591 } 592 } 593 return out; 594} 595 596export function genDtsFile(rootInfo: GenInfo, out: string) { 597 // gen enums 598 let fileContent = getDtsEnum(rootInfo); 599 // gen functions 600 fileContent += getDtsFunction(rootInfo); 601 // gen classes 602 fileContent += getDtsClasses(rootInfo); 603 // gen struct 604 fileContent += getDtsStructs(rootInfo); 605 // gen union 606 fileContent += getDtsUnions(rootInfo); 607 608 let dtsFileName = rootInfo.fileName + dtsFileExt; 609 let outPath = '' 610 if (out === undefined || out === null || out.trim() === '') { 611 let dirPath = path.dirname(rootInfo.rawFilePath); 612 outPath = path.join(dirPath, dtsFileName); 613 } else { 614 outPath = path.join(out, dtsFileName); 615 } 616 fs.writeFileSync(outPath, fileContent); 617 Logger.getInstance().info('generate success!') 618 return outPath; 619}