• 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*/
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}