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