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 { firstCharacterToUppercase, getClassNameSet, ReturnTypeEntity } from '../common/commonUtils'; 18import { getImportDeclarationArray, ImportElementEntity } from '../declaration-node/importAndExportDeclaration'; 19import { MethodEntity } from '../declaration-node/methodDeclaration'; 20 21/** 22 * get warn console template 23 * @param interfaceNameOrClassName 24 * @param functionNameOrPropertyName 25 * @returns 26 */ 27export function getWarnConsole(interfaceNameOrClassName: string, functionNameOrPropertyName: string): string { 28 return `console.warn('${interfaceNameOrClassName}.${functionNameOrPropertyName} interface mocked in the Previewer. How this interface works on the Previewer may be different from that on a real device.');\n`; 29} 30 31/** 32 * generate return statement; 33 * @param returnType 34 * @param sourceFile 35 * @returns 36 */ 37export function getReturnStatement(returnType: ReturnTypeEntity, sourceFile: SourceFile): string { 38 if (returnType.returnKind === SyntaxKind.TypeReference) { 39 if (returnType.returnKindName.startsWith('Promise')) { 40 return `return new Promise((resolve, reject) => { 41 resolve('[PC Preview] unkonwn type'); 42 })`; 43 } else if (returnType.returnKindName === 'T') { 44 return `return '[PC Preview] unkonwn type'`; 45 } else if (returnType.returnKindName === 'String') { 46 return `return ${returnType.returnKindName}(...args)`; 47 } else if (returnType.returnKindName === 'ArrayBuffer') { 48 return `return new ${returnType.returnKindName}(0)`; 49 } else if (returnType.returnKindName.startsWith('Array')) { 50 if (returnType.returnKindName.includes('<') && returnType.returnKindName.includes('>')) { 51 return `return [${generateGenericTypeToMockValue(returnType.returnKindName)}]`; 52 } else { 53 return `return new ${returnType.returnKindName}()`; 54 } 55 } else if (returnType.returnKindName.startsWith('Readonly')) { 56 return `return ${returnType.returnKindName.split('<')[1].split('>')[0]}`; 57 } else if (checkIsGenericSymbol(returnType.returnKindName)) { 58 return `return '[PC Preview] unkonwn iterableiterator_${returnType.returnKindName}'`; 59 } else if (returnType.returnKindName.startsWith('Uint8Array')) { 60 return `return new ${returnType.returnKindName}()`; 61 } else if (returnType.returnKindName.startsWith('IterableIterator')) { 62 if (returnType.returnKindName.includes(',')) { 63 return `let index = 0; 64 const IteratorEntriesMock = { 65 *[Symbol.iterator]() { 66 yield ['[PC Preview] unkonwn paramIterMock_K', '[PC Preview] unkonwn paramIterMock_V']; 67 }, 68 next: () => { 69 if (index < 1) { 70 const returnValue = ['[PC Previwe] unkonwn paramIterMock_K', '[PC Previwe] unkonwn paramIterMock_V']; 71 index++; 72 return { 73 value: returnValue, 74 done: false 75 }; 76 } else { 77 return { 78 done: true 79 }; 80 } 81 } 82 }; 83 return IteratorEntriesMock;`; 84 } else { 85 return `let index = 0; 86 const IteratorStringMock = { 87 *[Symbol.iterator]() { 88 yield '[PC Preview] unkonwn string'; 89 }, 90 next: () => { 91 if (index < 1) { 92 const returnValue = '[PC Previwe] unkonwn string'; 93 index++; 94 return { 95 value: returnValue, 96 done: false 97 }; 98 } else { 99 return { 100 done: true 101 }; 102 } 103 } 104 }; 105 return IteratorStringMock;`; 106 } 107 } else if (returnType.returnKindName.includes('<T>')) { 108 const tmpReturn = returnType.returnKindName.split('<')[0]; 109 if (tmpReturn.startsWith('Array')) { 110 return `return []`; 111 } else { 112 `return new ${tmpReturn}()`; 113 } 114 } else if (returnType.returnKindName.includes('<')) { 115 return `return new ${returnType.returnKindName.split('<')[0]}()`; 116 } else { 117 if (getClassNameSet().has(returnType.returnKindName)) { 118 if (returnType.returnKindName === 'Want') { 119 return `return mockWant().Want`; 120 } else { 121 return `return new ${returnType.returnKindName}()`; 122 } 123 } else if (propertyTypeWhiteList(returnType.returnKindName) === returnType.returnKindName) { 124 return `return ${getTheRealReferenceFromImport(sourceFile, returnType.returnKindName)}`; 125 } else { 126 return `return ${propertyTypeWhiteList(returnType.returnKindName)}`; 127 } 128 } 129 } else if (returnType.returnKind === SyntaxKind.UnionType) { 130 const returnNames = returnType.returnKindName.split('|'); 131 let returnName = returnNames[0]; 132 for (let i = 0; i < returnNames.length; i++) { 133 if (!returnNames[i].includes('[]') && !returnNames[i].includes('<')) { 134 returnName = returnNames[i]; 135 break; 136 } 137 } 138 if (returnName.trimStart().trimEnd() === 'void') { 139 return ``; 140 } 141 if (getClassNameSet().has(returnName)) { 142 return `return new ${returnName}()`; 143 } else { 144 return `return ${getBaseReturnValue(returnName.trimStart().trimEnd())}`; 145 } 146 } else { 147 return `return '[PC Preview] unkonwn type'`; 148 } 149 return `return '[PC Preview] unkonwn type'`; 150} 151 152/** 153 * special property whitelist 154 * @param propertyTypeName 155 * @returns 156 */ 157export function propertyTypeWhiteList(propertyTypeName: string): any { 158 const whiteList = ['GLboolean', 'GLuint', 'GLenum', 'GLint', 'NotificationFlags']; 159 if (whiteList.includes(propertyTypeName)) { 160 if (propertyTypeName === 'NotificationFlags' || propertyTypeName === 'GLenum') { 161 return `'[PC Preview] unkonwn ${propertyTypeName}'`; 162 } else if (propertyTypeName === 'GLboolean') { 163 return true; 164 } else { 165 return 0; 166 } 167 } else { 168 return propertyTypeName; 169 } 170} 171 172/** 173 * get basic return value 174 * @param value 175 * @returns 176 */ 177export function getBaseReturnValue(value: string): string | number | boolean { 178 if (value === 'string') { 179 return `''`; 180 } else if (value === 'number') { 181 return 0; 182 } else if (value === 'boolean') { 183 return true; 184 } else if (value === 'Object' || value === 'object') { 185 return `{}`; 186 } else if (checkIsGenericSymbol(value)) { 187 return `'[PC Preview] unkonwn type'`; 188 } else if (value === 'WebGLActiveInfo') { 189 return `{size: '[PC Preview] unkonwn GLint', type: 0, name: '[PC Preview] unkonwn name'}`; 190 } else { 191 return value; 192 } 193} 194 195/** 196 * get current sourceFile import data 197 * @param sourceFile 198 * @param typeName 199 * @returns 200 */ 201export function getTheRealReferenceFromImport(sourceFile: SourceFile, typeName: string): string { 202 const importArray = getImportDeclarationArray(sourceFile); 203 let returnName = ''; 204 let isFromImport = false; 205 let isOhos = false; 206 let mockMockName = ''; 207 importArray.forEach(value => { 208 if (typeName.includes('.') && typeName.split('.')[0] === value.importElements) { 209 isFromImport = true; 210 if (value.importPath.includes('@ohos')) { 211 isOhos = true; 212 } 213 if (value.importElements.trimStart().trimEnd() === typeName.split('.')[0]) { 214 const tmpArr = value.importPath.split('.'); 215 mockMockName = tmpArr[tmpArr.length - 1].replace(/'/g, '').replace(/"/g, ''); 216 } 217 } 218 }); 219 if (isFromImport) { 220 const splitReturnKindName = typeName.split('.'); 221 let left = ''; 222 for (let i = 1; i < splitReturnKindName.length; i++) { 223 left += `.${splitReturnKindName[i]}`; 224 } 225 if (isOhos) { 226 returnName = `mock${firstCharacterToUppercase(mockMockName)}()${left}`; 227 } 228 } else { 229 returnName = getImportTypeAliasNameFromImportElements(importArray, typeName); 230 } 231 return returnName; 232} 233 234/** 235 * get return type alias, for example: {Context as _Context} return _Context 236 * @param importElementEntity 237 * @param typeName 238 * @returns 239 */ 240 function getImportTypeAliasNameFromImportElements(importElementEntity: ImportElementEntity[], typeName: string): string { 241 for (let i = 0; i < importElementEntity.length; i++) { 242 if (importElementEntity[i].importElements.includes('_')) { 243 const importElements = importElementEntity[i].importElements.replace('{', '').replace('}', '').split(','); 244 for (let j = 0; j < importElements.length; j++) { 245 const element = importElements[j].trimStart().trimEnd(); 246 if (`_${typeName}` === element.split('as')[1].trimStart().trimEnd()) { 247 return `_${typeName}`; 248 } 249 } 250 } 251 } 252 if (typeName === 'Want') { 253 typeName = `mockWant().Want`; 254 } else if (typeName === 'InputMethodExtensionContext') { 255 typeName = `mockInputmethodextensioncontext().InputMethodExtensionContext`; 256 } 257 return typeName; 258} 259 260/** 261 * check is generic symbol 262 * @param type 263 * @returns 264 */ 265export function checkIsGenericSymbol(type: string): boolean { 266 const words = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']; 267 return words.includes(type); 268} 269 270/** 271 * generate basic type default value 272 * @param kindName 273 * @returns 274 */ 275export function generateGenericTypeToMockValue(kindName: string): any { 276 const genericTypeName = kindName.split('<')[1].split('>')[0]; 277 if (genericTypeName === 'string') { 278 return `''`; 279 } else if (genericTypeName === 'number') { 280 return 0; 281 } else if (genericTypeName === 'boolean') { 282 return true; 283 } else if (genericTypeName === 'Object' || genericTypeName === 'object') { 284 return '{}'; 285 } else { 286 return ``; 287 } 288} 289 290/** 291 * get callback statement 292 * @returns 293 */ 294export function getCallbackStatement(): string { 295 return `const len = args.length; 296 if (typeof args[len - 1] === 'function') { 297 args[len - 1].call(this, null, '[PC Preview] unkonwn type') 298 }`; 299} 300 301/** 302 * get iterator template string 303 * @param methodEntity 304 * @returns 305 */ 306export function generateSymbolIterator(methodEntity: MethodEntity): string { 307 let iteratorMethod = ''; 308 if (methodEntity.returnType.returnKindName.includes('<[')) { 309 iteratorMethod += `let index = 0; 310 const IteratorMock = { 311 next: () => { 312 if (index < 1) { 313 const returnValue = ['[PC Previwe] unkonwn iterableiterator_k', '[PC Previwe] unkonwn iterableiterator_v']; 314 index++; 315 return { 316 value: returnValue, 317 done: false 318 }; 319 } else { 320 return { 321 done: true 322 }; 323 } 324 } 325 }; 326 return IteratorMock;`; 327 } else { 328 iteratorMethod += `let index = 0; 329 const IteratorMock = { 330 next: () => { 331 if (index < 1) { 332 index++; 333 return { 334 value: '[PC Preview] unkonwn any', 335 done: false 336 }; 337 } else { 338 return { 339 done: true 340 }; 341 } 342 } 343 }; 344 return IteratorMock;`; 345 } 346 347 return iteratorMethod; 348} 349