• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021-2022 Huawei Device 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
16const path = require('path');
17const fs = require('fs');
18const ts = require('typescript');
19const ExcelJS = require('exceljs');
20const applicationModules = [];
21
22const typeCollection = true;
23const isNotMerge = false;
24function collectArkUiApis() {
25  const apis = [];
26  const arkUiApiDir = path.resolve(__dirname, '../sdk/build-tools/ets-loader/declarations');
27  try {
28    readFile(arkUiApiDir, apis);
29  } catch (error) {
30    return;
31  }
32  return apis;
33}
34
35function parseFiles(files) {
36  files = files.concat(collectArkUiApis());
37  const fileContentList = [];
38  files.forEach(file => {
39    let fileContent = fs.readFileSync(file, 'utf-8');
40    fileContentList.push({
41      fileName: path.basename(file).replace(/.d.ts$/g, '.ts'),
42      fileContent: fileContent,
43      fileRoot: file,
44    });
45  });
46
47  const api = [];
48  const exportApi = [];
49  const returnDeclarationArr = new Set([]);
50  const hash = new Set([]);
51
52  fileContentList.forEach(item => {
53    const fileName = item.fileName.replace(/\.d.ts$/g, '.ts');
54    let packageName = item.fileRoot.indexOf('build-tools\\ets-loader\\declarations') >= 0 ||
55      item.fileRoot.indexOf('build-tools/ets-loader/declarations') >= 0 ?
56      'ArkUI' : fileName.replace(/\@|.ts$/g, '');
57    ts.transpileModule(item.fileContent, {
58      compilerOptions: {
59        'target': ts.ScriptTarget.ES2017,
60      },
61      fileName: fileName,
62      transformers: { before: [getReturnDeclarationArr(packageName, exportApi, returnDeclarationArr, fileName)] },
63    });
64  });
65
66  fileContentList.forEach(item => {
67    const fileName = item.fileName.replace(/\.d.ts$/g, '.ts');
68    let packageName = item.fileRoot.indexOf('build-tools\\ets-loader\\declarations') >= 0 ||
69      item.fileRoot.indexOf('build-tools/ets-loader/declarations') >= 0 ? 'ArkUI' :
70      fileName.replace(/\@|.ts$/g, '');
71    ts.transpileModule(item.fileContent, {
72      compilerOptions: {
73        'target': ts.ScriptTarget.ES2017,
74      },
75      fileName: fileName,
76      transformers: { before: [processDeclarationSourceFile(packageName, api, exportApi, returnDeclarationArr, hash)] },
77    });
78  });
79  return api;
80}
81exports.parseFiles = parseFiles;
82
83
84function visitAllNode(node, returnDeclarationArr, packageName) {
85  if ((ts.isMethodDeclaration(node) || ts.isFunctionDeclaration(node)) && node && node.type &&
86    ts.isTypeReferenceNode(node.type)) {
87    returnDeclarationArr.add(node.type.typeName.getText());
88  }
89
90  if (ts.isModuleDeclaration(node) && ts.isModuleBlock(node.body) && node.body && node.body.statements) {
91    node.body.statements.forEach(statement => {
92      if (statement.name) {
93        applicationModules.push({
94          packageName: packageName,
95          className: node.name.escapedText,
96          methodName: statement.name.escapedText,
97        });
98      }
99    });
100  }
101  node.getChildren().forEach(item => visitAllNode(item, returnDeclarationArr, packageName));
102}
103
104function getExportApi(node, packageName, exportApi) {
105  node.statements.forEach(stat => {
106    if (ts.isModuleDeclaration(stat)) {
107      if (stat.getText().indexOf('namespace') > 0) {
108        let apiInfo = {
109          isSystemApi: '公开API',
110          version: '',
111          deprecated: '',
112          permission: 'N/A',
113          sysCap: 'N/A',
114          model: '',
115        };
116        exportApi.push({
117          packageName: packageName,
118          className: stat.name.escapedText.toString(),
119          methodName: '',
120          apiInfo: getApiInfo(stat, apiInfo),
121        });
122      }
123    }
124  });
125}
126
127const getReturnDeclarationArr = (packageName, exportApi, returnDeclarationArr, fileName) => {
128  return (context) => {
129    return (node) => {
130      visitAllNode(node, returnDeclarationArr, packageName);
131      getExportApi(node, packageName, exportApi);
132      return node;
133    };
134  };
135};
136exports.applicationModules = applicationModules;
137
138function processDeclarationSourceFile(packageName, api, exportApi, returnDeclarationArr, hash) {
139  return (context) => {
140    return (node) => {
141      const statements = node.statements;
142      const currentClassFunSet = new Set([]);
143      const currentTypeList = new Array();
144      statements.forEach(stat => {
145        if (ts.isTypeAliasDeclaration(stat)) {
146          if (stat.type.types) {
147            let typeObj = {
148              name: stat.name.escapedText,
149              value: [],
150            };
151            stat.type.types.forEach(type => {
152              if (type.literal && type.literal.text) {
153                typeObj.value.push(type.literal.text);
154              }
155            });
156            if (typeObj.value.length > 0) {
157              currentTypeList.push(typeObj);
158            }
159          }
160        }
161      });
162
163      statements.forEach(stat => {
164        let apiInfo = {
165          isSystemApi: '公开API',
166          version: '',
167          deprecated: '',
168          permission: 'N/A',
169          sysCap: 'N/A',
170          model: '',
171        };
172        if (ts.isInterfaceDeclaration(stat)) {
173          collectInterfaceDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, currentTypeList);
174        } else if (ts.isModuleDeclaration(stat)) {
175          collectModuleDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, currentTypeList);
176        } else if (ts.isClassDeclaration(stat)) {
177          collectClassDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, currentTypeList);
178        } else if (ts.isEnumDeclaration(stat)) {
179          collectEnumDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, currentTypeList);
180        } else if (ts.isTypeAliasDeclaration(stat)) {
181
182        } else {
183          if (ts.isMethodDeclaration(stat) || ts.isMethodSignature(stat) || ts.isFunctionDeclaration(stat)) {
184            var methodName = stat.name.escapedText ? stat.name.escapedText.toString() : stat.name.text.toString();
185            let className = '';
186            exportApi.forEach(item => {
187              if (item.methodName === methodName && item.packageName === packageName) {
188                className = item.className;
189                if (item.apiInfo) {
190                  apiInfo = item.apiInfo;
191                }
192              }
193            });
194            addFunctionOnOffApi(packageName, className, methodName, getApiInfo(stat, apiInfo), 'Method', api,
195              hash, currentClassFunSet, stat);
196          }
197        }
198      });
199      return node;
200    };
201  };
202}
203
204function collectInterfaceDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, currentTypeList) {
205  const className = stat.name.escapedText.toString();
206  const interfaceChildren = stat.members;
207  collectEachChildNode(interfaceChildren, packageName, className, 'Field', api, exportApi, returnDeclarationArr, hash,
208    getApiInfo(stat, apiInfo), currentTypeList);
209}
210
211function collectClassDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, currentTypeList) {
212  const className = stat.name.escapedText.toString();
213  const classChildren = stat.members;
214  collectEachChildNode(classChildren, packageName, className, 'Field', api, exportApi, returnDeclarationArr, hash,
215    getApiInfo(stat, apiInfo), currentTypeList);
216}
217
218function collectEnumDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, currentTypeList) {
219  const className = stat.name.escapedText.toString();
220  const enumChildren = stat.members;
221  collectEachChildNode(enumChildren, packageName, className, 'Enum', api, exportApi, returnDeclarationArr, hash,
222    getApiInfo(stat, apiInfo), currentTypeList);
223}
224
225function collectModuleDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, currentTypeList) {
226  const className = stat.name.escapedText ? stat.name.escapedText.toString() : stat.name.text.toString();
227  const moduleChildren = stat.body.statements;
228  collectEachChildNode(moduleChildren, packageName, className, 'Field', api, exportApi, returnDeclarationArr, hash,
229    getApiInfo(stat, apiInfo), currentTypeList);
230}
231
232function collectEachChildNode(children, packageName, className, faterApiType, api, exportApi, returnDeclarationArr,
233  hash, apiInfo, currentTypeList) {
234  const currentClassFunSet = new Set([]);
235  children.forEach(child => {
236    if (ts.isTypeAliasDeclaration(child)) {
237      if (child.type) {
238        let typeObj = collectTypeApi(child, packageName, className, faterApiType, api, exportApi, returnDeclarationArr,
239          hash, apiInfo);
240        if (typeObj.value.length > 0) {
241          currentTypeList.push(typeObj);
242        }
243      }
244    }
245  });
246
247  children.forEach(child => {
248    let faterApiInfo = JSON.parse(JSON.stringify(apiInfo));
249    let apiType = new String(faterApiType);
250
251    if (/export.*\{.*\}/g.test(child.getText())) {
252      exportApi.push({
253        packageName: packageName,
254        className: className,
255        methodName: child.getText().replace('export', '').replace('{', '').replace('}', '').replace(';', '').trim(),
256        apiInfo: faterApiInfo,
257      });
258      return;
259    }
260
261    if (ts.isInterfaceDeclaration(child)) {
262      collectInterfaceDeclaration(child, packageName, api, exportApi, returnDeclarationArr, hash, faterApiInfo);
263    } else if (ts.isModuleDeclaration(child)) {
264      collectModuleDeclaration(child, packageName, api, exportApi, returnDeclarationArr, hash, faterApiInfo);
265    } else if (ts.isClassDeclaration(child)) {
266      collectClassDeclaration(child, packageName, api, exportApi, returnDeclarationArr, hash, faterApiInfo);
267    } else if (ts.isEnumDeclaration(child)) {
268      collectEnumDeclaration(child, packageName, api, exportApi, returnDeclarationArr, hash, faterApiInfo);
269    } else {
270      if ((ts.isMethodDeclaration(child) || ts.isMethodSignature(child) || ts.isFunctionDeclaration(child)) &&
271        (child.name.escapedText === 'on' || child.name.escapedText === 'off') && child.parameters && child.parameters.length > 0) {
272        apiType = 'Method';
273        collectSpecialApis(child, apiType, packageName, className, faterApiInfo, api, exportApi, currentTypeList,
274          hash, apiInfo, currentClassFunSet);
275      } else {
276        collectMethodOrFieldApis(child, packageName, className, faterApiInfo, apiType, api,
277          hash, currentClassFunSet, child, returnDeclarationArr);
278      }
279    }
280  });
281}
282
283function collectMethodOrFieldApis(child, packageName, className, faterApiInfo, apiType, api,
284  hash, currentClassFunSet, child, returnDeclarationArr) {
285  let methodName = '';
286  if (ts.isMethodDeclaration(child) || ts.isMethodSignature(child) || ts.isFunctionDeclaration(child) ||
287    ts.isCallSignatureDeclaration(child) || ts.isConstructSignatureDeclaration(child) ||
288    ts.isIndexSignatureDeclaration(child)) {
289    if (child.name) {
290      methodName = child.name.getText();
291    } else {
292      methodName = className;
293    }
294    apiType = 'Method';
295  } else if (ts.isPropertyDeclaration(child) || ts.isPropertySignature(child)) {
296    if (child.type && child.type.parameters) {
297      methodName = child.name.escapedText;
298      apiType = 'Method';
299    } else {
300      methodName = child.name.escapedText;
301      apiType = 'Field';
302    }
303  } else {
304    if (child.name) {
305      methodName = child.name.getText();
306    }
307  }
308
309  if (methodName !== '') {
310    addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api,
311      hash, currentClassFunSet, child);
312  } else {
313    if (child.getText().indexOf('constructor') === 0) {
314      methodName = 'constructor';
315      apiType = 'Method';
316    } else if (child.getText().indexOf('const') === 0) {
317      const dataObj = collectFiledOrConstant(apiType, methodName, child, returnDeclarationArr);
318      methodName = dataObj.name;
319      apiType = dataObj.apiType;
320    } else if (/\w+:\s*\w+/g.test(child.getText())) {
321      apiType = 'Field';
322      methodName = child.getText().split(':')[0].trim();
323    }
324
325    if (methodName !== '') {
326      addApi(packageName, className, methodName, child.getText(),
327        getApiInfo(child, faterApiInfo), apiType, api, hash);
328    }
329  }
330}
331
332function collectFiledOrConstant(apiType, methodName, child, returnDeclarationArr) {
333  if (child.getText().replace('const', '').indexOf(':') > 0) {
334    if (returnDeclarationArr.has(child.getText().replace('const', '').split(':')[1].trim())) {
335      apiType = 'Field';
336    } else {
337      apiType = 'Constant';
338    }
339    methodName = child.getText().replace('const', '').split(':')[0].trim();
340  } else if (child.getText().replace('const', '').indexOf('=') > 0) {
341    if (returnDeclarationArr.has(child.getText().replace('const', '').split('=')[1].trim())) {
342      apiType = 'Field';
343    } else {
344      apiType = 'Constant';
345    }
346    methodName = child.getText().replace('const', '').split('=')[0].trim();
347  }
348  return { apiType, methodName };
349}
350
351function collectSpecialApis(child, apiType, packageName, className, faterApiInfo, api, exportApi, currentTypeList,
352  hash, apiInfo, currentClassFunSet) {
353  for (let i = 0; i < child.parameters.length; i++) {
354    const param = child.parameters[i];
355    if (param.name.escapedText === 'type' || param.name.escapedText === 'event' ||
356      param.name.escapedText === 'eventType') {
357      collectCommonTypesOfApi(packageName, className, faterApiInfo, apiType, api, hash, currentClassFunSet,
358        child, currentTypeList, param);
359      break;
360    } else {
361      let methodName = child.name.escapedText;
362      addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api,
363        hash, currentClassFunSet, child);
364    }
365  }
366}
367
368function collectCommonTypesOfApi(packageName, className, faterApiInfo, apiType, api, hash, currentClassFunSet,
369  child, currentTypeList, param) {
370  if (param.type && param.type.literal && param.type.literal.text) {
371    const typeTextArr = param.getText().replace(/\s*/g, '').split(':');
372    if (typeTextArr[0] === 'type' || typeTextArr[0] === 'event') {
373      let methodName = child.name.escapedText + '_' + param.type.literal.text;
374      addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api,
375        hash, currentClassFunSet, child);
376    }
377  } else if (param.type && param.type.types && param.type.types.length > 0) {
378    param.type.types.forEach(type => {
379      if (type.literal && type.literal.text) {
380        let methodName = child.name.escapedText + '_' + type.literal.text;
381        addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api,
382          hash, currentClassFunSet, child);
383      }
384    });
385  } else if (param.type && param.type.typeName && param.type.typeName.escapedText) {
386    collectInCurrentTypeListApi(packageName, className, faterApiInfo, apiType, api,
387      hash, currentClassFunSet, child, currentTypeList, param);
388  } else {
389    let methodName = child.name.escapedText;
390    addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api,
391      hash, currentClassFunSet, child);
392  }
393}
394
395function collectInCurrentTypeListApi(packageName, className, faterApiInfo, apiType, api,
396  hash, currentClassFunSet, child, currentTypeList, param) {
397  if (currentTypeList && currentTypeList.length > 0) {
398    currentTypeList.forEach(type => {
399      if (type.name === param.type.typeName.escapedText) {
400        type.value.forEach(typeString => {
401          let methodName = child.name.escapedText + '_' + typeString;
402          addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api,
403            hash, currentClassFunSet, child);
404        });
405      }
406    });
407  } else if (param.type.typeName.escapedText === 'InnerEvent') {
408    let methodName = child.name.escapedText + '_' + param.type.typeName.escapedText;
409    addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api,
410      hash, currentClassFunSet, child);
411  } else {
412    let methodName = child.name.escapedText;
413    addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api,
414      hash, currentClassFunSet, child);
415  }
416}
417
418function collectTypeApi(child, packageName, className, faterApiType, api, exportApi, returnDeclarationArr,
419  hash, apiInfo) {
420  let typeObj = {
421    name: child.name.escapedText,
422    value: [],
423  };
424
425  if (child.type.types) {
426    child.type.types.forEach(type => {
427      if (type.literal && type.literal.text) {
428        typeObj.value.push(type.literal.text);
429        if (typeCollection) {
430          let faterApiInfo = JSON.parse(JSON.stringify(apiInfo));
431          addApi(packageName, child.name.escapedText, type.literal.text, child.getText(),
432            getApiInfo(child, faterApiInfo), 'Type', api, hash);
433        }
434      } else {
435        if (type.getText() !== '') {
436          typeObj.value.push(type.getText());
437          if (typeCollection) {
438            let faterApiInfo = JSON.parse(JSON.stringify(apiInfo));
439            addApi(packageName, child.name.escapedText, type.getText(), child.getText(),
440              getApiInfo(child, faterApiInfo), 'Type', api, hash);
441          }
442        }
443      }
444    });
445  } else if (child.type.members) {
446    child.type.members.forEach(member => {
447      member.type.types.forEach(type => {
448        collectMembersApi(type, packageName, child, api, hash, typeObj, apiInfo, className);
449      });
450    });
451  }
452  return typeObj;
453}
454
455function collectMembersApi(type, packageName, child, api, hash, typeObj, apiInfo, className) {
456  if (type.literal && type.literal.text) {
457    typeObj.value.push(type.literal.text);
458    if (typeCollection) {
459      let faterApiInfo = JSON.parse(JSON.stringify(apiInfo));
460      addApi(packageName, child.name.escapedText, type.literal.text, child.getText(),
461        getApiInfo(child, faterApiInfo), 'Type', api, hash);
462    }
463  } else {
464    if (type.getText() !== '') {
465      typeObj.value.push(type.getText());
466      if (typeCollection) {
467        let faterApiInfo = JSON.parse(JSON.stringify(apiInfo));
468        addApi(packageName, className, child.name.escapedText, child.getText(),
469          getApiInfo(child, faterApiInfo), 'Type', api, hash);
470      }
471    }
472  }
473}
474
475function addFunctionOnOffApi(packageName, className, methodName, apiInfo, apiType, api,
476  hash, currentClassFunSet, childNode) {
477  if (currentClassFunSet.has(methodName) && !isNotMerge) {
478    for (let i = 0; i < api.length; i++) {
479      const curApi = api[i];
480      if (curApi.packageName === packageName && curApi.className === className &&
481        curApi.methodName === methodName) {
482        if (curApi.methodText.indexOf(`${childNode.getText().replace('declare', '').trim()}`) < 0) {
483          curApi.methodText += `<br>${childNode.getText().replace('declare', '').trim()}`;
484          break;
485        }
486      }
487    }
488  } else {
489    if (!currentClassFunSet.has(methodName)) {
490      currentClassFunSet.add(methodName);
491      addApi(packageName, className, methodName, childNode.getText().replace('declare', '').trim(),
492        getApiInfo(childNode, apiInfo), apiType, api, hash);
493    } else {
494      if (childNode.getFullText().indexOf('\/**') >= 0) {
495        addApi(packageName, className, methodName, childNode.getText().replace('declare', '').trim(),
496          getApiInfo(childNode, apiInfo), apiType, api, hash);
497      } else {
498        let firstApiInfo = {};
499        for (let i = 0; i < api.length; i++) {
500          const curApi = api[i];
501          if (curApi.packageName === packageName && curApi.className === className &&
502            curApi.methodName === methodName) {
503            firstApiInfo.isSystemApi = curApi.isSystemApi;
504            firstApiInfo.version = curApi.version;
505            firstApiInfo.sysCap = curApi.sysCap;
506            firstApiInfo.permission = curApi.permission;
507            firstApiInfo.model = curApi.model;
508          }
509
510        }
511        addApi(packageName, className, methodName, childNode.getText().replace('declare', '').trim(),
512          firstApiInfo, apiType, api, hash);
513      }
514    }
515  }
516}
517
518function getApiInfo(node, apiInfo) {
519  const notesStr = node.getFullText().replace(node.getText(), '');
520
521  if (notesStr !== '') {
522    if (/\@[S|s][Y|y][S|s][T|t][E|e][M|m][A|a][P|p][I|i]/g.test(notesStr)) {
523      apiInfo.isSystemApi = '系统API';
524    }
525    if (/\@[S|s][I|i][N|n][C|c][E|e]\s*(\d+)/g.test(notesStr)) {
526      notesStr.replace(/\@[S|s][I|i][N|n][C|c][E|e]\s*(\d+)/g, (versionInfo) => {
527        apiInfo.version = versionInfo.replace(/\@[S|s][I|i][N|n][C|c][E|e]/g, '').trim();
528      });
529    }
530    if (/\@[D|d][E|e][P|p][R|r][E|e][C|c][A|a][T|t][E|e][D|d].*[S|s][I|i][N|n][C|c][E|e]\s*(\d+)/g.test(notesStr)) {
531      notesStr.replace(/\@[D|d][E|e][P|p][R|r][E|e][C|c][A|a][T|t][E|e][D|d].*[S|s][I|i][N|n][C|c][E|e]\s*(\d+)/g,
532        versionInfo => {
533          apiInfo.deprecated = versionInfo.replace(
534            /\@[D|d][E|e][P|p][R|r][E|e][C|c][A|a][T|t][E|e][D|d].*[S|s][I|i][N|n][C|c][E|e]\s*/g, '').trim();
535        });
536    }
537    if (/\@[F|f][A|a][M|m][O|o][D|d][E|e][L|l][O|o][N|n][L|l][Y|y]/g.test(notesStr)) {
538      notesStr.replace(/\@[F|f][A|a][M|m][O|o][D|d][E|e][L|l][O|o][N|n][L|l][Y|y]/g, modelInfo => {
539        apiInfo.model = modelInfo;
540      });
541    } else if (/\@[S|s][T|t][A|a][G|g][E|e][M|m][O|o][D|d][E|e][L|l][O|o][N|n][L|l][Y|y]/g.test(notesStr)) {
542      notesStr.replace(/\@[S|s][T|t][A|a][G|g][E|e][M|m][O|o][D|d][E|e][L|l][O|o][N|n][L|l][Y|y]/g, modelInfo => {
543        apiInfo.model = modelInfo;
544      });
545    }
546    if (/\@[S|s][Y|y][S|s][C|c][A|a][P|p]\s*((\w|\.|\/|\{|\@|\}|\s)+)/g.test(notesStr)) {
547      notesStr.replace(/\@[S|s][Y|y][S|s][C|c][A|a][P|p]\s*((\w|\.|\/|\{|\@|\}|\s)+)/g, sysCapInfo => {
548        apiInfo.sysCap = sysCapInfo.replace(/\@[S|s][Y|y][S|s][C|c][A|a][P|p]/g, '').trim();
549      });
550    }
551    if (/\@[P|p][E|e][R|r][M|m][I|i][S|s][S|s][I|i][O|o][N|n]\s*((\w|\.|\/|\{|\@|\}|\s)+)/g.test(notesStr)) {
552      notesStr.replace(/\@[P|p][E|e][R|r][M|m][I|i][S|s][S|s][I|i][O|o][N|n]\s*((\w|\.|\/|\{|\@|\}|\s)+)/g,
553        permissionInfo => {
554          apiInfo.permission = permissionInfo.
555            replace(/\@[P|p][E|e][R|r][M|m][I|i][S|s][S|s][I|i][O|o][N|n]/g, '').trim();
556        });
557    }
558  }
559  return apiInfo;
560}
561
562function addApi(packageName, className, methodName, methodText, apiInfo, apiType, api, hash) {
563  let recard = isNotMerge ? `${packageName}.${className}/${methodName}/${methodText}` :
564    `${packageName}.${className}/${methodName}`;
565
566  if (!hash.has(recard)) {
567    hash.add(recard);
568    api.push({
569      packageName: packageName,
570      className: className,
571      methodName: methodName,
572      methodText: methodText.replace(/export\s/g, ''),
573      isSystemApi: apiInfo.isSystemApi,
574      version: apiInfo.version,
575      deprecated: apiInfo.deprecated,
576      apiType: apiType,
577      sysCap: apiInfo.sysCap,
578      permission: apiInfo.permission,
579      model: apiInfo.model,
580      applicationFile: '',
581      pos: '',
582      functionType: '',
583      optionalArg: 0,
584      arguments: 0,
585    });
586  }
587}
588
589async function getExcelBuffer(api) {
590  const workbook = new ExcelJS.Workbook();
591  const sheet = workbook.addWorksheet('Js Api', { views: [{ xSplit: 1 }] });
592  sheet.getRow(1).values = ['模块名', '类名', '方法名', '函数', '文件位置', '类型', 'SysCap',
593    '权限', '支持起始版本', '访问级别'];
594  for (let i = 1; i <= api.length; i++) {
595    const apiData = api[i - 1];
596    sheet.getRow(i + 1).values = [apiData.packageName, apiData.className, apiData.methodName,
597      apiData.methodText, apiData.pos, apiData.apiType, apiData.sysCap, apiData.permission,
598      apiData.version, apiData.isSystemApi];
599  }
600  const buffer = await workbook.xlsx.writeBuffer();
601  return buffer;
602}
603
604exports.getExcelBuffer = getExcelBuffer;
605
606function readFile(dir, utFiles) {
607  try {
608    const files = fs.readdirSync(dir);
609    files.forEach((element) => {
610      const filePath = path.join(dir, element);
611      const status = fs.statSync(filePath);
612      if (status.isDirectory()) {
613        readFile(filePath, utFiles);
614      } else {
615        if (/\.d\.ts/.test(filePath)) {
616          utFiles.push(filePath);
617        }
618      }
619    });
620  } catch (e) {
621    console.error('ETS ERROR: ' + e);
622  }
623}
624
625exports.readFile = readFile;
626
627async function excel(api) {
628  let buffer = await getExcelBuffer(api);
629  fs.writeFile('../Js_Api.xlsx', buffer, function (err) {
630    if (err) {
631      console.error('WEITE FAILED: ', err);
632      return;
633    } else {
634      console.log('WRITE SUCCEED!');
635    }
636  });
637}
638
639exports.excel = excel;