1/* 2 * Copyright (c) 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 16import { SourceFile, SyntaxKind } from 'typescript'; 17import { collectAllLegalImports, firstCharacterToUppercase, getAllFileNameList } from '../common/commonUtils'; 18import { ImportElementEntity } from '../declaration-node/importAndExportDeclaration'; 19import { getDefaultExportClassDeclaration, getSourceFileFunctions, getSourceFileVariableStatements, SourceFileEntity } from '../declaration-node/sourceFileElementsAssemply'; 20import { generateClassDeclaration } from './generateClassDeclaration'; 21import { generateCommonFunction } from './generateCommonFunction'; 22import { generateEnumDeclaration } from './generateEnumDeclaration'; 23import { addToIndexArray } from './generateIndex'; 24import { generateInterfaceDeclaration } from './generateInterfaceDeclaration'; 25import { generateModuleDeclaration } from './generateModuleDeclaration'; 26import { generateStaticFunction } from './generateStaticFunction'; 27import { addToSystemIndexArray } from './generateSystemIndex'; 28import { generateTypeAliasDeclaration } from './generateTypeAlias'; 29import { generateVariableStatementDelcatation } from './generateVariableStatementDeclaration'; 30 31/** 32 * generate mock file string 33 * @param rootName 34 * @param sourceFileEntity 35 * @param sourceFile 36 * @param fileName 37 * @returns 38 */ 39export function generateSourceFileElements(rootName: string, sourceFileEntity: SourceFileEntity, sourceFile: SourceFile, fileName: string): string { 40 let mockApi = ''; 41 const mockFunctionElements: Array<MockFunctionElementEntity> = []; 42 const heritageClausesArray = getCurrentApiHeritageArray(sourceFileEntity, sourceFile); 43 if (sourceFileEntity.importDeclarations.length > 0) { 44 sourceFileEntity.importDeclarations.forEach(value => { 45 mockApi += generateImportDeclaration(value, fileName, heritageClausesArray); 46 }); 47 } 48 49 if (sourceFileEntity.moduleDeclarations.length > 0) { 50 sourceFileEntity.moduleDeclarations.forEach(value => { 51 mockApi += generateModuleDeclaration('', value, sourceFile, fileName) + '\n'; 52 }); 53 } 54 55 if (sourceFileEntity.classDeclarations.length > 0) { 56 sourceFileEntity.classDeclarations.forEach(value => { 57 if (!fileName.startsWith('system_') && !value.exportModifiers.includes(SyntaxKind.DefaultKeyword)) { 58 mockApi += generateClassDeclaration('', value, false, '', fileName, sourceFile, false) + '\n'; 59 mockFunctionElements.push({ elementName: value.className, type: 'class' }); 60 } 61 }); 62 } 63 64 if (sourceFileEntity.interfaceDeclarations.length > 0) { 65 sourceFileEntity.interfaceDeclarations.forEach(value => { 66 mockApi += generateInterfaceDeclaration('', value, sourceFile, true, sourceFileEntity.interfaceDeclarations) + '\n'; 67 mockFunctionElements.push({ elementName: value.interfaceName, type: 'interface' }); 68 }); 69 } 70 71 if (sourceFileEntity.enumDeclarations.length > 0) { 72 sourceFileEntity.enumDeclarations.forEach(value => { 73 mockApi += generateEnumDeclaration('', value) + '\n'; 74 mockFunctionElements.push({ elementName: value.enumName, type: 'enum' }); 75 }); 76 } 77 78 if (sourceFileEntity.typeAliasDeclarations.length > 0) { 79 sourceFileEntity.typeAliasDeclarations.forEach(value => { 80 mockApi += generateTypeAliasDeclaration(value, false) + '\n'; 81 mockFunctionElements.push({ elementName: value.typeAliasName, type: 'typeAlias' }); 82 }); 83 } 84 85 if (sourceFileEntity.moduleDeclarations.length === 0 && (fileName.startsWith('ohos_') || fileName.startsWith('system_') || fileName.startsWith('webgl'))) { 86 const mockNameArr = fileName.split('_'); 87 const mockName = mockNameArr[mockNameArr.length - 1]; 88 const defaultExportClass = getDefaultExportClassDeclaration(sourceFile); 89 if (defaultExportClass.length > 0) { 90 defaultExportClass.forEach(value => { 91 mockApi += generateClassDeclaration(rootName, value, false, mockName, '', sourceFile, false) + '\n'; 92 mockFunctionElements.push({ elementName: value.className, type: 'class' }); 93 }); 94 } 95 mockApi += `export function mock${firstCharacterToUppercase(mockName)}() {\n`; 96 if (fileName.startsWith('system_')) { 97 addToSystemIndexArray({ 98 filename: fileName, 99 mockFunctionName: `mock${firstCharacterToUppercase(mockName)}` 100 }); 101 mockApi += `global.systemplugin.${mockName} = {`; 102 const defaultClass = getDefaultExportClassDeclaration(sourceFile); 103 let staticMethodBody = ''; 104 if (defaultClass.length > 0) { 105 defaultClass.forEach(value => { 106 value.staticMethods.forEach(val => { 107 staticMethodBody += generateStaticFunction(val, true, sourceFile); 108 }); 109 }); 110 } 111 mockApi += staticMethodBody; 112 mockApi += '}'; 113 } else { 114 if (!fileName.startsWith('webgl')) { 115 addToIndexArray({ fileName: fileName, mockFunctionName: `mock${firstCharacterToUppercase(mockName)}` }); 116 } 117 } 118 mockApi += `\nconst mockModule${firstCharacterToUppercase(mockName)} = {`; 119 mockFunctionElements.forEach(val => { 120 mockApi += `${val.elementName}: ${val.elementName},`; 121 }); 122 mockApi += '}\n'; 123 mockApi += `return mockModule${firstCharacterToUppercase(mockName)}.${firstCharacterToUppercase(mockName)}\n`; 124 mockApi += '}'; 125 } else { 126 const defaultExportClass = getDefaultExportClassDeclaration(sourceFile); 127 if (defaultExportClass.length > 0) { 128 const mockNameArr = fileName.split('_'); 129 const mockName = mockNameArr[mockNameArr.length - 1]; 130 defaultExportClass.forEach(value => { 131 mockApi += generateClassDeclaration(rootName, value, false, mockName, '', sourceFile, false) + '\n'; 132 }); 133 } 134 } 135 if (sourceFileEntity.exportDeclarations.length > 0) { 136 sourceFileEntity.exportDeclarations.forEach(value => { 137 if (!value.includes('export {')) { 138 mockApi += `${value}\n`; 139 } 140 }); 141 } 142 return mockApi; 143} 144 145/** 146 * generate import definition 147 * @param importEntity 148 * @param sourceFileName 149 * @returns 150 */ 151export function generateImportDeclaration(importEntity: ImportElementEntity, sourceFileName: string, heritageClausesArray: string[]): string { 152 let importPathName = ''; 153 const importPathSplit = importEntity.importPath.split('/'); 154 let fileName = importPathSplit[importPathSplit.length - 1]; 155 if (fileName.endsWith('.d.ts')) { 156 fileName = fileName.split('.d.')[0]; 157 } 158 if (fileName.includes('@')) { 159 importPathName = fileName.replace('@', '').replace(/\./g, '_'); 160 } else { 161 importPathName = fileName.replace(/\./g, '_'); 162 } 163 let importPath = ''; 164 for (let i = 0; i < importPathSplit.length - 1; i++) { 165 importPath += importPathSplit[i] + '/'; 166 } 167 importPath += importPathName; 168 let importElements = importEntity.importElements; 169 if (!importElements.includes('{') && !importElements.includes('* as') && !heritageClausesArray.includes(importElements)) { 170 if (importEntity.importPath.includes('@ohos')) { 171 const tmpArr = importEntity.importPath.split('.'); 172 importElements = `{ mock${firstCharacterToUppercase(tmpArr[tmpArr.length - 1].replace('"', '').replace('\'', ''))} }`; 173 } else { 174 importElements = `{ ${importElements} }`; 175 } 176 } 177 if (checIsDefaultExportClass(importEntity.importElements)) { 178 importElements = `{ ${importEntity.importElements} }`; 179 } 180 const testPath = importPath.replace(/"/g, '').replace(/'/g, '').split('/'); 181 if (getAllFileNameList().has(testPath[testPath.length - 1]) || testPath[testPath.length - 1] === 'ohos_application_want') { 182 const tmpImportPath = importPath.replace(/'/g, '').replace(/"/g, ''); 183 if (!tmpImportPath.startsWith('./') && !tmpImportPath.startsWith('../')) { 184 importPath = `'./${tmpImportPath}'`; 185 } 186 if (sourceFileName === 'tagSession' && importPath === `'./basic'` || sourceFileName === 'notificationContent' && importPath === `'./ohos_multimedia_image'`) { 187 importPath = `'.${importPath.replace(/'/g, '')}'`; 188 } 189 190 // adapt no rules .d.ts 191 if (importElements.trimRight().trimEnd() === 'AccessibilityExtensionContext, { AccessibilityElement }') { 192 importElements = '{ AccessibilityExtensionContext, AccessibilityElement }'; 193 } 194 if (importElements.trimRight().trimEnd() === '{ image }') { 195 importElements = '{ mockImage as image }'; 196 } 197 if (sourceFileName === 'AbilityContext' && importPath === `'../ohos_application_Ability'` || 198 sourceFileName === 'Context' && importPath === `"./ApplicationContext"`) { 199 return ''; 200 } 201 collectAllLegalImports(importElements); 202 return `import ${importElements} from ${importPath}\n`; 203 } else { 204 return ''; 205 } 206} 207 208/** 209 * adapter default export 210 * @param importName 211 * @returns 212 */ 213 function checIsDefaultExportClass(importName: string): boolean { 214 const defaultExportClass = ['Context', 'BaseContext', 'ExtensionContext', 'ApplicationContext', 'ExtensionAbility', 'Ability']; 215 return defaultExportClass.includes(importName); 216} 217 218/** 219 * get heritage elements 220 * @param sourceFileEntity 221 * @param sourceFile 222 * @returns 223 */ 224function getCurrentApiHeritageArray(sourceFileEntity: SourceFileEntity, sourceFile: SourceFile): string[] { 225 const heritageClausesArray = []; 226 const defaultClassArray = getDefaultExportClassDeclaration(sourceFile); 227 sourceFileEntity.classDeclarations.forEach(value => { 228 value.heritageClauses.forEach(val => { 229 val.types.forEach(v => { 230 heritageClausesArray.push(v); 231 }); 232 }); 233 }); 234 defaultClassArray.forEach(value => { 235 value.heritageClauses.forEach(val => { 236 val.types.forEach(v => { 237 heritageClausesArray.push(v); 238 }); 239 }); 240 }); 241 return heritageClausesArray; 242} 243 244interface MockFunctionElementEntity { 245 elementName: string, 246 type: string 247} 248