1/* 2 * Copyright (c) 2023 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 fs = require('fs'); 17const ts = require('typescript'); 18const ExcelJS = require('exceljs'); 19const path = require('path'); 20const { sys } = require('typescript'); 21// 是否统计type类型API的开关,true表示统计 22const typeCollection = true; 23// 是否不合并同名函数的开关,true不合并 24const isNotMerge = true; 25 26// 解析文件 文本内容并将结果push到列表中并去重 27function parse(files) { 28 const api = []; 29 const exportApi = []; 30 const returnDeclarationArr = new Set([]); 31 const hash = new Set([]); 32 const fileContentList = []; 33 files.forEach(file => { 34 let fileContent = fs.readFileSync(file, 'utf-8'); 35 fileContentList.push({ 36 fileName: path.basename(file).replace(/.d.ts$/g, '.ts'), 37 fileContent: fileContent, 38 fileRoot: file, 39 }); 40 }); 41 fileContentList.forEach(item => { 42 const fileName = item.fileName.replace(/\.d.ts$/g, '.ts'); 43 let packageName = item.fileRoot.indexOf('component\\ets\\') >= 0 || 44 item.fileRoot.indexOf('component/ets/') >= 0 ? 'ArkUI' : fileName.replace((/\@|.ts$/g), '').replace(/D:\\/g, ''); 45 ts.transpileModule(item.fileContent, { 46 compilerOptions: { 47 'target': ts.ScriptTarget.ES2017, 48 }, 49 fileName: fileName, 50 transformers: { before: [getReturnDeclarationArr(packageName, exportApi, returnDeclarationArr)] }, 51 }); 52 }); 53 54 fileContentList.forEach(item => { 55 const fileName = item.fileName.replace(/\.d.ts$/g, '.ts'); 56 let packageName = item.fileRoot.indexOf('component\\ets\\') >= 0 || 57 item.fileRoot.indexOf('component/ets/') >= 0 ? 'ArkUI' : fileName.replace(/\@|.ts$/g, '').replace(/D:\\/g, ''); 58 ts.transpileModule(item.fileContent, { 59 compilerOptions: { 60 'target': ts.ScriptTarget.ES2017, 61 }, 62 fileName: fileName, 63 transformers: { before: [processDeclarationSourceFile(packageName, api, exportApi, returnDeclarationArr, hash, item.fileRoot)] }, 64 }); 65 }); 66 return api; 67} 68 69// 获取返回值类型 70function visitAllNode(node, returnDeclarationArr) { 71 if ((ts.isMethodDeclaration(node) || ts.isFunctionDeclaration(node)) && node && node.type && 72 ts.isTypeReferenceNode(node.type)) { 73 returnDeclarationArr.add(node.type.typeName.getText()); 74 } 75 node.getChildren().forEach(item => { 76 visitAllNode(item, returnDeclarationArr); 77 }); 78} 79 80// 获取导入Api的数组 81function getExportApi(node, packageName, exportApi) { 82 node.statements.forEach(stat => { 83 if (ts.isModuleDeclaration(stat)) { 84 if (stat.getText().indexOf('namespace') > 0) { 85 let apiInfo = { 86 isSystemApi: '公开API', 87 version: '', 88 deprecated: '', 89 permission: 'N/A', 90 sysCap: 'N/A', 91 model: '', 92 }; 93 exportApi.push({ 94 packageName: packageName, 95 className: stat.name.escapedText.toString(), 96 methodName: '', 97 apiInfo: getApiInfo(stat, apiInfo), 98 }); 99 } 100 } 101 }); 102} 103 104// 获取返回值类型和命名空间 105const getReturnDeclarationArr = (packageName, exportApi, returnDeclarationArr) => { 106 return (context) => { 107 return (node) => { 108 visitAllNode(node, returnDeclarationArr); 109 getExportApi(node, packageName, exportApi); 110 return node; 111 }; 112 }; 113}; 114 115 116// 搜集API接口并去重 117function processDeclarationSourceFile(packageName, api, exportApi, returnDeclarationArr, hash, dtsPath) { 118 return (context) => { 119 return (node) => { 120 const statements = node.statements; 121 const currentClassFuncSet = new Set([]); 122 const currentTypeList = new Array(); 123 getCurrentTypeList(statements, currentTypeList); 124 125 statements.forEach(stat => { 126 let apiInfo = { 127 isSystemApi: '公开API', 128 version: '', 129 deprecated: '', 130 permission: 'N/A', 131 sysCap: 'N/A', 132 model: '', 133 headimport: 'N/A', 134 endexport: 'N/A', 135 }; 136 collectApi(packageName, api, stat, apiInfo, exportApi, returnDeclarationArr, hash, dtsPath, 137 currentTypeList, currentClassFuncSet); 138 }); 139 return node; 140 }; 141 }; 142} 143 144function getCurrentTypeList(statements, currentTypeList) { 145 statements.forEach(stat => { 146 if (ts.isTypeAliasDeclaration(stat)) { 147 if (stat.type.types) { 148 let typeObj = { 149 name: stat.name.escapedText, 150 value: [], 151 }; 152 stat.type.types.forEach(type => { 153 if (type.literal && type.literal.text) { 154 typeObj.value.push(type.literal.text); 155 } 156 }); 157 if (typeObj.value.length > 0) { 158 currentTypeList.push(typeObj); 159 } 160 } 161 } 162 }); 163} 164 165function collectApi(packageName, api, stat, apiInfo, exportApi, returnDeclarationArr, hash, dtsPath, currentTypeList, 166 currentClassFuncSet) { 167 if (ts.isInterfaceDeclaration(stat)) { 168 collectInterfaceDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, 169 currentTypeList, dtsPath); 170 } else if (ts.isModuleDeclaration(stat)) { 171 collectModuleDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, 172 currentTypeList, dtsPath); 173 } else if (ts.isClassDeclaration(stat)) { 174 collectClassDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, 175 currentTypeList, dtsPath); 176 } else if (ts.isEnumDeclaration(stat)) { 177 collectEnumDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, 178 currentTypeList, dtsPath); 179 } else if (ts.isVariableStatement(stat)) { 180 const apiName = stat.declarationList.declarations[0].name.escapedText; 181 addApi(packageName, 'global', apiName, stat.getText().trim(), getApiInfo(stat, apiInfo), 182 'Decorator', api, hash, dtsPath, 8); 183 } else { 184 collectSpecialApi(stat, packageName, api, hash, currentClassFuncSet, dtsPath, exportApi, apiInfo); 185 } 186} 187 188function collectSpecialApi(stat, packageName, api, hash, currentClassFuncSet, dtsPath, exportApi, apiInfo) { 189 if (ts.isMethodDeclaration(stat) || ts.isMethodSignature(stat) || ts.isFunctionDeclaration(stat)) { 190 const methodName = stat.name.escapedText ? stat.name.escapedText.toString() : stat.name.text.toString(); 191 let className = ''; 192 exportApi.forEach(item => { 193 if (item.methodName === methodName && item.packageName === packageName) { 194 className = item.className; 195 if (item.apiInfo) { 196 apiInfo = item.apiInfo; 197 } 198 } 199 }); 200 addFunctionOnOffApi(packageName, className, methodName, getApiInfo(stat, apiInfo), 'Method', api, 201 hash, currentClassFuncSet, stat, dtsPath); 202 } 203} 204 205function collectInterfaceDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, currentTypeList, dtsPath) { 206 const className = stat.name.escapedText.toString(); 207 const interfaceChildren = stat.members; 208 let tmpApiInfo = getApiInfo(stat, apiInfo); 209 collectEachChildNode(interfaceChildren, packageName, className, 'Field', api, exportApi, returnDeclarationArr, hash, 210 tmpApiInfo, currentTypeList, dtsPath); 211} 212 213function collectClassDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, currentTypeList, dtsPath) { 214 const className = stat.name.escapedText.toString(); 215 const classChildren = stat.members; 216 let tmpApiInfo = getApiInfo(stat, apiInfo); 217 collectEachChildNode(classChildren, packageName, className, 'Field', api, exportApi, returnDeclarationArr, hash, 218 tmpApiInfo, currentTypeList, dtsPath); 219} 220 221function collectEnumDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, currentTypeList, dtsPath) { 222 const className = stat.name.escapedText.toString(); 223 const enumChildren = stat.members; 224 let tmpApiInfo = getApiInfo(stat, apiInfo); 225 collectEachChildNode(enumChildren, packageName, className, 'Enum', api, exportApi, returnDeclarationArr, hash, 226 tmpApiInfo, currentTypeList, dtsPath); 227} 228 229function collectModuleDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, currentTypeList, dtsPath) { 230 const className = stat.name.escapedText ? stat.name.escapedText.toString() : stat.name.text.toString(); 231 const moduleChildren = stat.body.statements; 232 let tmpApiInfo = getApiInfo(stat, apiInfo); 233 collectEachChildNode(moduleChildren, packageName, className, 'Field', api, exportApi, returnDeclarationArr, hash, 234 tmpApiInfo, currentTypeList, dtsPath); 235} 236 237function collectTypeApi(child, packageName, className, api, hash, apiInfo, dtsPath) { 238 let typeObj = { 239 name: child.name.escapedText, 240 value: [], 241 }; 242 if (child.type.types) { 243 child.type.types?.forEach(type => { 244 collectTypeApiInTypes(type, apiInfo, child, api, hash, dtsPath, typeObj, packageName); 245 }); 246 } else if (child.type.members) { 247 child.type.members?.forEach(member => { 248 collectTypeApiInMembers(member, apiInfo, child, api, hash, dtsPath, typeObj, packageName, className); 249 }); 250 } 251 return typeObj; 252} 253 254function collectTypeApiInTypes(type, apiInfo, child, api, hash, dtsPath, typeObj, packageName) { 255 if (type.literal && type.literal.text) { 256 typeObj.value.push(type.literal.text); 257 if (typeCollection && type.literal) { 258 let faterApiInfo = JSON.parse(JSON.stringify(apiInfo)); 259 addApi(packageName, child.name.escapedText, type.literal.text, child.getText(), 260 getApiInfo(child, faterApiInfo), 'Type', api, hash, dtsPath, 1); 261 } 262 } else { 263 if (type.getText() !== '') { 264 typeObj.value.push(type.getText()); 265 if (typeCollection && type.literal) { 266 let faterApiInfo = JSON.parse(JSON.stringify(apiInfo)); 267 addApi(packageName, child.name.escapedText, type.getText(), child.getText(), 268 getApiInfo(child, faterApiInfo), 'Type', api, hash, dtsPath, 2); 269 } 270 } 271 } 272} 273 274function collectTypeApiInMembers(member, apiInfo, child, api, hash, dtsPath, typeObj, packageName, className) { 275 member.type.types?.forEach(type => { 276 if (type.literal && type.literal.text) { 277 typeObj.value.push(type.literal.text); 278 if (typeCollection) { 279 let faterApiInfo = JSON.parse(JSON.stringify(apiInfo)); 280 addApi(packageName, child.name.escapedText, type.literal.text, child.getText(), 281 getApiInfo(child, faterApiInfo), 'Type', api, hash, dtsPath, 3); 282 } 283 } else { 284 if (type.getText() !== '') { 285 typeObj.value.push(type.getText()); 286 if (typeCollection) { 287 let faterApiInfo = JSON.parse(JSON.stringify(apiInfo)); 288 addApi(packageName, className, child.name.escapedText, child.getText(), 289 getApiInfo(child, faterApiInfo), 'Type', api, hash, dtsPath, 4); 290 } 291 } 292 } 293 }); 294} 295 296function collectEachChildNode(children, packageName, className, faterApiType, api, exportApi, returnDeclarationArr, 297 hash, apiInfo, currentTypeList, dtsPath) { 298 const currentClassFunSet = new Set([]); 299 children.forEach(child => { 300 if (ts.isTypeAliasDeclaration(child)) { 301 if (child.type) { 302 let typeObj = collectTypeApi(child, packageName, className, api, hash, apiInfo, dtsPath); 303 if (typeObj.value.length > 0) { 304 currentTypeList.push(typeObj); 305 } 306 } 307 } 308 }); 309 children.forEach(child => { 310 let faterApiInfo = JSON.parse(JSON.stringify(apiInfo)); 311 let apiType = new String(faterApiType); 312 if (/export.*\{.*\}/g.test(child.getText())) { 313 exportApi.push({ 314 packageName: packageName, 315 className: className, 316 methodName: child.getText().replace('export', '').replace('{', '').replace('}', '').replace(';', '').trim(), 317 apiInfo: faterApiInfo, 318 }); 319 return; 320 } 321 if (ts.isInterfaceDeclaration(child)) { 322 collectInterfaceDeclaration(child, packageName, api, exportApi, returnDeclarationArr, hash, faterApiInfo, currentTypeList, dtsPath); 323 } else if (ts.isModuleDeclaration(child)) { 324 collectModuleDeclaration(child, packageName, api, exportApi, returnDeclarationArr, hash, faterApiInfo, currentTypeList, dtsPath); 325 } else if (ts.isClassDeclaration(child)) { 326 collectClassDeclaration(child, packageName, api, exportApi, returnDeclarationArr, hash, faterApiInfo, currentTypeList, dtsPath); 327 } else if (ts.isEnumDeclaration(child)) { 328 collectEnumDeclaration(child, packageName, api, exportApi, returnDeclarationArr, hash, faterApiInfo, currentTypeList, dtsPath); 329 } else { 330 if ((ts.isMethodDeclaration(child) || ts.isMethodSignature(child) || ts.isFunctionDeclaration(child)) && 331 (child.name.escapedText === 'on' || child.name.escapedText === 'off') && child.parameters && child.parameters.length > 0) { 332 apiType = 'Method'; 333 collectSubscriptionTypeApi(child, apiType, packageName, className, faterApiType, api, currentTypeList, 334 hash, currentClassFunSet, dtsPath); 335 } else { 336 collectOtherApi(child, packageName, className, faterApiInfo, apiType, api, 337 hash, currentClassFunSet, child, dtsPath, returnDeclarationArr); 338 } 339 } 340 }); 341} 342 343function collectOtherApi(child, packageName, className, faterApiInfo, apiType, api, 344 hash, currentClassFunSet, child, dtsPath, returnDeclarationArr) { 345 let methodName = ''; 346 if (isSpecialMethod(child)) { 347 if (child.name) { 348 methodName = child.name.getText(); 349 } else { 350 methodName = className; 351 } 352 apiType = 'Method'; 353 } else if (ts.isPropertyDeclaration(child) || ts.isPropertySignature(child)) { 354 if (child.type && child.type.parameters) { 355 methodName = child.name.escapedText; 356 apiType = 'Method'; 357 } else { 358 methodName = child.name.escapedText; 359 apiType = 'Field'; 360 } 361 } else { 362 if (child.name) { 363 methodName = child.name.getText(); 364 } 365 } 366 if (methodName !== '') { 367 addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api, 368 hash, currentClassFunSet, child, dtsPath); 369 } else { 370 if (child.getText().indexOf('constructor') === 0) { 371 methodName = 'constructor'; 372 apiType = 'Method'; 373 } else if (child.getText().indexOf('const') === 0) { 374 const infoObj = collectFieleOrConstant(apiType, methodName, child, returnDeclarationArr); 375 methodName = infoObj.methodName; 376 apiType = infoObj.apiType; 377 } else if (/\w+:\s*\w+/g.test(child.getText())) { 378 apiType = 'Field'; 379 methodName = child.getText().split(':')[0].trim(); 380 } 381 if (methodName !== '') { 382 addApi(packageName, className, methodName, child.getText(), 383 getApiInfo(child, faterApiInfo), apiType, api, hash, dtsPath, 5); 384 } 385 } 386} 387 388function isSpecialMethod(child){ 389 return ts.isMethodDeclaration(child) || ts.isMethodSignature(child) || ts.isFunctionDeclaration(child) || 390 ts.isCallSignatureDeclaration(child) || ts.isConstructSignatureDeclaration(child) || 391 ts.isIndexSignatureDeclaration(child); 392} 393 394function collectFieleOrConstant(apiType, methodName, child, returnDeclarationArr) { 395 if (child.getText().replace('const', '').indexOf(':') > 0) { 396 if (returnDeclarationArr.has(child.getText().replace('const', '').split(':')[1].trim())) { 397 apiType = 'Field'; 398 } else { 399 apiType = 'Constant'; 400 } 401 methodName = child.getText().replace('const', '').split(':')[0].trim(); 402 } else if (child.getText().replace('const', '').indexOf('=') > 0) { 403 if (returnDeclarationArr.has(child.getText().replace('const', '').split('=')[1].trim())) { 404 apiType = 'Field'; 405 } else { 406 apiType = 'Constant'; 407 } 408 methodName = child.getText().replace('const', '').split('=')[0].trim(); 409 } 410 return { apiType, methodName }; 411} 412 413function collectSubscriptionTypeApi(child, apiType, packageName, className, faterApiInfo, api, currentTypeList, 414 hash, currentClassFunSet, dtsPath) { 415 for (let i = 0; i < child.parameters.length; i++) { 416 const param = child.parameters[i]; 417 if (isCommonSubscriptionType(param)) { 418 if (param.type && param.type.literal && param.type.literal.text) { 419 collectTypeOrEventApi(packageName, className, faterApiInfo, apiType, api, 420 hash, currentClassFunSet, child, dtsPath, param); 421 } else if (param.type && param.type.types && param.type.types.length > 0) { 422 collectSpecialSubscriptionTypeApi(param, packageName, className, faterApiInfo, apiType, api, 423 hash, currentClassFunSet, child, dtsPath); 424 } else if (param.type && param.type.typeName && param.type.typeName.escapedText) { 425 inCurrentTypeListApi(packageName, className, faterApiInfo, apiType, api, 426 hash, currentClassFunSet, child, dtsPath, currentTypeList, param); 427 } else if (param.type && param.type.typeName && param.type.typeName.left && 428 param.type.typeName.right) { 429 let methodName = child.name.escapedText + '_' + param.type.typeName.left.escapedText + '_' + 430 param.type.typeName.right.escapedText; 431 addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api, 432 hash, currentClassFunSet, child, dtsPath); 433 } else { 434 let methodName = child.name.escapedText; 435 addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api, 436 hash, currentClassFunSet, child, dtsPath); 437 } 438 break; 439 } else { 440 let methodName = child.name.escapedText; 441 addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api, 442 hash, currentClassFunSet, child, dtsPath); 443 } 444 } 445} 446 447function isCommonSubscriptionType(param) { 448 return param.name.escapedText === 'type' || param.name.escapedText === 'event' || 449 param.name.escapedText === 'eventType'; 450} 451 452function collectSpecialSubscriptionTypeApi(param, packageName, className, faterApiInfo, apiType, api, 453 hash, currentClassFunSet, child, dtsPath) { 454 param.type.types.forEach(type => { 455 if (type.literal && type.literal.text) { 456 const methodName = child.name.escapedText + '_' + type.literal.text; 457 addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api, 458 hash, currentClassFunSet, child, dtsPath); 459 } 460 }); 461} 462 463function inCurrentTypeListApi(packageName, className, faterApiInfo, apiType, api, hash, currentClassFunSet, child, 464 dtsPath, currentTypeList, param) { 465 if (currentTypeList && currentTypeList.length > 0) { 466 currentTypeList.forEach(type => { 467 if (type.name === param.type.typeName.escapedText) { 468 type.value.forEach(typeString => { 469 let methodName = child.name.escapedText + '_' + typeString; 470 addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api, 471 hash, currentClassFunSet, child, dtsPath); 472 }); 473 } 474 }); 475 } else { 476 let methodName = child.name.escapedText; 477 addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api, 478 hash, currentClassFunSet, child, dtsPath); 479 } 480} 481 482function collectTypeOrEventApi(packageName, className, faterApiInfo, apiType, api, 483 hash, currentClassFunSet, child, dtsPath, param) { 484 const typeTextArr = param.getText().replace(/\s*/g, '').split(':'); 485 if (typeTextArr[0] === 'type' || typeTextArr[0] === 'event') { 486 let methodName = child.name.escapedText + '_' + param.type.literal.text; 487 addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api, 488 hash, currentClassFunSet, child, dtsPath); 489 } else { 490 let methodName = child.name.escapedText + '_' + param.type.literal.text; 491 addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api, 492 hash, currentClassFunSet, child, dtsPath); 493 } 494} 495 496function addFunctionOnOffApi(packageName, className, methodName, apiInfo, apiType, api, 497 hash, currentClassFunSet, childNode, dtsPath) { 498 // 合并同名函数 499 if (currentClassFunSet.has(methodName) && !isNotMerge) { 500 collectSameNameApiText(api, packageName, className, methodName, childNode); 501 } else { 502 notMergeSameNameFun(packageName, className, methodName, apiInfo, apiType, api, 503 hash, currentClassFunSet, childNode, dtsPath); 504 } 505} 506 507function collectSameNameApiText(api, packageName, className, methodName, childNode) { 508 for (let i = 0; i < api.length; i++) { 509 const curApi = api[i]; 510 if (curApi.packageName === packageName && curApi.className === className && 511 curApi.methodName === methodName) { 512 if (curApi.methodText.indexOf(`${childNode.getText().replace('declare', '').trim()}`) < 0) { 513 curApi.methodText += `\n${childNode.getText().replace('declare', '').replace(/\r|\n/ig, '').trim()}`; 514 break; 515 } 516 } 517 } 518} 519 520function notMergeSameNameFun(packageName, className, methodName, apiInfo, apiType, api, 521 hash, currentClassFunSet, childNode, dtsPath) { 522 if (!currentClassFunSet.has(methodName)) { 523 currentClassFunSet.add(methodName); 524 addApi(packageName, className, methodName, childNode.getText().replace('declare', '').trim(), 525 getApiInfo(childNode, apiInfo), apiType, api, hash, dtsPath, 6); 526 } else { 527 if (childNode.getFullText().indexOf('\/**') >= 0) { 528 addApi(packageName, className, methodName, childNode.getText().replace('declare', '').trim(), 529 getApiInfo(childNode, apiInfo), apiType, api, hash, dtsPath, 7); 530 } else { 531 let firstApiInfo = {}; 532 handleSameNameApiJsDoc(api, firstApiInfo, packageName, className, methodName); 533 addApi(packageName, className, methodName, childNode.getText().replace('declare', '').trim(), 534 firstApiInfo, apiType, api, hash, dtsPath, 8); 535 } 536 } 537} 538 539function handleSameNameApiJsDoc(api, firstApiInfo, packageName, className, methodName) { 540 for (let i = 0; i < api.length; i++) { 541 const curApi = api[i]; 542 if (curApi.packageName === packageName && curApi.className === className && 543 curApi.methodName === methodName) { 544 firstApiInfo.isSystemApi = curApi.isSystemApi; 545 firstApiInfo.version = curApi.version; 546 firstApiInfo.sysCap = curApi.sysCap; 547 firstApiInfo.permission = curApi.permission; 548 firstApiInfo.model = curApi.model; 549 firstApiInfo.deprecated = curApi.deprecated; 550 } 551 } 552} 553 554function getApiInfo(node, apiInfo) { 555 const notesStr = node.getFullText().replace(node.getText(), ''); 556 apiInfo.model = getModelInfo(notesStr); 557 apiInfo.errorCode = getErrorCode(notesStr); 558 apiInfo.deprecated = getDeprecatedInfo(notesStr); 559 apiInfo.permission = getPermissionInfo(notesStr); 560 apiInfo.isSystemApi = getSystemApi(notesStr); 561 apiInfo.version = getSinceVersion(notesStr); 562 apiInfo.sysCap = getSyscap(notesStr); 563 apiInfo.formInfo = isForm(notesStr); 564 apiInfo.isCrossPlatform = isCrossPlatform(notesStr); 565 return apiInfo; 566} 567 568function getSystemApi(notesStr) { 569 let isSystemApi = ''; 570 if (/\@[S|s][Y|y][S|s][T|t][E|e][M|m][A|a][P|p][I|i]/g.test(notesStr)) { 571 isSystemApi = '系统API'; 572 } else { 573 isSystemApi = '公开API'; 574 } 575} 576 577function getSinceVersion(notesStr) { 578 let version; 579 if (/\@[S|s][I|i][N|n][C|c][E|e]\s*(\d+)/g.test(notesStr)) { 580 notesStr.replace(/\@[S|s][I|i][N|n][C|c][E|e]\s*(\d+)/g, (versionInfo) => { 581 version = versionInfo.replace(/\@[S|s][I|i][N|n][C|c][E|e]/g, '').trim(); 582 }); 583 } else { 584 version = 'N/A'; 585 } 586 return version; 587} 588 589function getSyscap(notesStr) { 590 let syscap = ''; 591 if (/\@[S|s][Y|y][S|s][C|c][A|a][P|p]\s*((\w|\.|\/|\{|\@|\}|\s)+)/g.test(notesStr)) { 592 notesStr.replace(/\@[S|s][Y|y][S|s][C|c][A|a][P|p]\s*((\w|\.|\/|\{|\@|\}|\s)+)/g, sysCapInfo => { 593 syscap = sysCapInfo.replace(/\@[S|s][Y|y][S|s][C|c][A|a][P|p]/g, '').trim(); 594 }); 595 } 596 return syscap; 597} 598 599function isForm(notesStr) { 600 let formInfo = ''; 601 if (/\@form/g.test(notesStr)) { 602 formInfo = '是'; 603 } else { 604 formInfo = '否'; 605 } 606 return formInfo; 607} 608 609function getPermissionInfo(notesStr) { 610 let permission = ''; 611 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)) { 612 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, 613 permissionInfo => { 614 permission = permissionInfo.replace( 615 /\@[P|p][E|e][R|r][M|m][I|i][S|s][S|s][I|i][O|o][N|n]/g, '').trim(); 616 return permission; 617 }); 618 } else { 619 permission = 'N/A'; 620 } 621 return permission; 622} 623 624function getDeprecatedInfo(notesStr) { 625 let deprecated = ''; 626 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)) { 627 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, 628 deprecatedInfo => { 629 deprecated = deprecatedInfo.replace( 630 /\@[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(); 631 632 }); 633 } else { 634 deprecated = 'N/A'; 635 } 636 return deprecated; 637} 638 639function getErrorCode(notesStr) { 640 let errorCode = ''; 641 if (/\@throws { BusinessError } \d{2,18}/g.test(notesStr)) { 642 notesStr.replace(/\@throws { BusinessError } \d{2,18}/g, (code) => { 643 if (errorCode === '') { 644 errorCode += `${code.replace(/\@throws { BusinessError } /, '')}`; 645 } else { 646 errorCode += `,${code.replace(/\@throws { BusinessError } /, '')}`; 647 } 648 }); 649 } else { 650 errorCode = 'N/A'; 651 } 652 return errorCode; 653} 654 655function getModelInfo(notesStr) { 656 let model = ''; 657 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)) { 658 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 => { 659 model = modelInfo; 660 }); 661 } 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)) { 662 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 => { 663 model = modelInfo; 664 }); 665 } else { 666 model = 'N/A'; 667 } 668 return model; 669} 670 671function isCrossPlatform(notesStr) { 672 let isCrossPlatform = ''; 673 if (/\@crossplatform/g.test(notesStr)) { 674 isCrossPlatform = '是'; 675 } else { 676 isCrossPlatform = '否'; 677 } 678 return isCrossPlatform; 679} 680 681function addApi(packageName, className, methodName, methodText, apiInfo, apiType, api, hash, dtsPath, type) { 682 let recard = isNotMerge ? `${packageName}.${className}/${methodName}/${methodText}` : 683 `${packageName}.${className}/${methodName}`; 684 if (!hash.has(recard)) { 685 hash.add(recard); 686 api.push({ 687 packageName: packageName, 688 className: className, 689 methodName: methodName, 690 methodText: methodText.replace(/export\s/g, ''), 691 isSystemApi: apiInfo.isSystemApi, 692 version: apiInfo.version, 693 deprecated: apiInfo.deprecated, 694 apiType: apiType, 695 sysCap: apiInfo.sysCap, 696 permission: apiInfo.permission, 697 model: apiInfo.model, 698 dtsPath: dtsPath, 699 errorCode: apiInfo.errorCode, 700 formInfo: apiInfo.formInfo, 701 isCrossPlatform: apiInfo.isCrossPlatform, 702 }); 703 } 704} 705 706function readFile(dir, utFiles) { 707 try { 708 const files = fs.readdirSync(dir); 709 files.forEach((element) => { 710 const filePath = path.join(dir, element); 711 const status = fs.statSync(filePath); 712 if (status.isDirectory()) { 713 readFile(filePath, utFiles); 714 } else { 715 if (/\.d\.ts/.test(filePath)) { 716 utFiles.push(filePath); 717 } 718 } 719 }); 720 } catch (e) { 721 console.error('ETS ERROR: ' + e); 722 } 723} 724 725function exportData() { 726 const dir = path.resolve(__dirname, './API'); 727 let fileList = []; 728 readFile(dir, fileList); 729 let api = parse(fileList); 730 excel(api); 731} 732 733async function excel(api) { 734 let buffer = await getExcelBuffer(api); 735 fs.writeFile('Js_Api.xlsx', buffer, function (err) { 736 if (err) { 737 console.error(err); 738 return; 739 } 740 }); 741} 742 743async function getExcelBuffer(api) { 744 const workbook = new ExcelJS.Workbook(); 745 const sheet = workbook.addWorksheet('Js Api', { views: [{ xSplit: 1 }] }); 746 sheet.getRow(1).values = ['模块名', '类名', '方法名', '函数', '类型', 'SysCap', 747 '权限', '支持起始版本', '访问级别', '是否为卡片', '是否支持跨平台']; 748 for (let i = 1; i <= api.length; i++) { 749 const apiData = api[i - 1]; 750 sheet.getRow(i + 1).values = [apiData.packageName, apiData.className, apiData.methodName, 751 apiData.methodText, apiData.apiType, apiData.sysCap, apiData.permission, 752 apiData.version, apiData.isSystemApi, apiData.formInfo, apiData.isCrossPlatform]; 753 } 754 const buffer = await workbook.xlsx.writeBuffer(); 755 return buffer; 756} 757 758exportData();