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 { readFile, parseFiles } = require('./collectApi'); 17const path = require('path'); 18const fs = require('fs'); 19const ts = require('typescript'); 20 21let exportClass = ''; 22 23function collectBaseApi(importFiles, applicationApis) { 24 const SDK_API_FILES = []; 25 const APP_API_FILES = []; 26 getAllApiFiles(SDK_API_FILES); 27 28 importFiles.forEach(importData => { 29 for (let i = 0; i < SDK_API_FILES.length; i++) { 30 const filePath = SDK_API_FILES[i]; 31 if (path.basename(filePath).replace(/\.d\.ts/, '') === importData.importFile) { 32 APP_API_FILES.push(filePath); 33 break; 34 } 35 } 36 }); 37 38 let noRepeatImportFiles = [...new Set(APP_API_FILES)]; 39 const baseApis = parseFiles(noRepeatImportFiles); 40 return compareApis(baseApis, applicationApis, SDK_API_FILES); 41} 42 43function compareApis(baseApis, applicationApis, sdkFiles) { 44 let callApisInApp = []; 45 let componentApiIndexSet = new Set(); 46 applicationApis = deleteUndefinedApi(applicationApis); 47 48 applicationApis.forEach(applicationApi => { 49 sdkFiles.forEach(sdkFile => { 50 if (applicationApi.notes !== '实例化对象方式调用' && 51 path.basename(sdkFile).replace(/\.d\.ts/, '') === applicationApi.packageName) { 52 applicationApi.moduleName = handleImportClass(sdkFile); 53 } 54 }); 55 }); 56 57 for (let i = 0; i < applicationApis.length; i++) { 58 for (let j = 0; j < baseApis.length; j++) { 59 if (applicationApis[i].type === 'ArkUI' && baseApis[j].packageName === 'ArkUI') { 60 compareComponentApi(applicationApis[i], baseApis[j], callApisInApp, componentApiIndexSet, i); 61 } else if (!applicationApis[i].value && applicationApis[i].type === 'API') { 62 compareApisWithoutValue(applicationApis[i], baseApis[j], callApisInApp); 63 } else if (applicationApis[i].value && applicationApis[i].type === 'API') { 64 compareValuableApis(applicationApis[i], baseApis[j], callApisInApp); 65 } 66 } 67 } 68 return callApisInApp; 69} 70 71exports.collectBaseApi = collectBaseApi; 72 73function deleteUndefinedApi(applicationApis) { 74 for (let i = 0; i < applicationApis.length; i++) { 75 if (applicationApis[i] === undefined) { 76 applicationApis.splice(i, 1); 77 } 78 } 79 return applicationApis; 80} 81 82function compareApisWithoutValue(applicationApi, baseApi, callApisInApp) { 83 if (typeof (applicationApi.moduleName) === 'string' && 84 baseApi.className.toLowerCase() === applicationApi.moduleName.toLowerCase() && 85 applicationApi.apiName === baseApi.methodName && 86 applicationApi.packageName.replace('@', '') === baseApi.packageName) { 87 let applyApi = JSON.parse(JSON.stringify(baseApi)); 88 applyApi.pos = applicationApi.callLocation; 89 applyApi.notes = applicationApi.notes ? applicationApi.notes : ''; 90 callApisInApp.push(applyApi); 91 } 92} 93 94function compareValuableApis(applicationApi, baseApi, callApisInApp) { 95 if (applicationApi.apiName === baseApi.className && applicationApi.value === baseApi.methodName && 96 applicationApi.packageName.replace('@', '') === baseApi.packageName) { 97 let applyApi = JSON.parse(JSON.stringify(baseApi)); 98 applyApi.pos = applicationApi.callLocation; 99 callApisInApp.push(applyApi); 100 } 101} 102 103function handleImportClass(filePath) { 104 const fileContent = fs.readFileSync(filePath, 'utf-8'); 105 ts.transpileModule(fileContent, { 106 compilerOptions: { 107 'target': ts.ScriptTarget.ES2017, 108 }, 109 fileName: filePath.replace(/\.d\.ts/, '.ts'), 110 transformers: { before: [isExportClass()] }, 111 }); 112 return exportClass; 113} 114 115function isExportClass() { 116 return (context) => { 117 return (sourcefile) => { 118 const statements = sourcefile.statements; 119 statements.forEach(statement => { 120 if (ts.isClassDeclaration(statement)) { 121 exportClass = statement.name.escapedText; 122 } else if (ts.isExportAssignment(statement)) { 123 exportClass = statement.expression.escapedText; 124 } 125 }); 126 return sourcefile; 127 }; 128 }; 129} 130 131function compareComponentApi(applicationApi, baseApi, callApisInApp, componentApiIndexSet, index) { 132 let applyApi = JSON.parse(JSON.stringify(baseApi)); 133 applyApi.pos = applicationApi.callLocation; 134 if (applicationApi.moduleName.match(new RegExp(baseApi.className.replace(/Attribute|Interface/, ''), 'i')) && 135 applicationApi.apiName === baseApi.methodName && !componentApiIndexSet.has(index)) { 136 applyApi.className = applicationApi.moduleName; 137 callApisInApp.push(applyApi); 138 componentApiIndexSet.add(index); 139 } else if (applicationApi.apiName === baseApi.methodName && baseApi.className === 'CommonMethod' && 140 applicationApi.notes !== '比较API' && !componentApiIndexSet.has(index)) { 141 applyApi.className = applicationApi.moduleName; 142 applyApi.notes = 'CommonMethod'; 143 callApisInApp.push(applyApi); 144 componentApiIndexSet.add(index); 145 } else if (applicationApi.notes === '比较API' && applicationApi.apiName === baseApi.methodName && 146 baseApi.className.match(new RegExp(applicationApi.moduleName, 'i')) && 147 baseApi.className !== 'CommonMethod' && !componentApiIndexSet.has(index)) { 148 callApisInApp.push(applyApi); 149 componentApiIndexSet.add(index); 150 } 151} 152 153function getAllApiFiles(files) { 154 readFile(path.resolve(__dirname, '../sdk'), files); 155}