• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
16import type { SourceFile } from 'typescript';
17import { SyntaxKind } from 'typescript';
18import { firstCharacterToUppercase, getClassNameSet } from '../common/commonUtils';
19import type { ReturnTypeEntity } from '../common/commonUtils';
20import { getImportDeclarationArray } from '../declaration-node/importAndExportDeclaration';
21import type { ImportElementEntity } from '../declaration-node/importAndExportDeclaration';
22import type { MethodEntity } from '../declaration-node/methodDeclaration';
23import type { FunctionEntity } from '../declaration-node/functionDeclaration';
24import type { MethodSignatureEntity } from '../declaration-node/methodSignatureDeclaration';
25
26const iteratorEntriesMock = `
27  let index = 0;
28  const IteratorEntriesMock = {
29    *[Symbol.iterator]() {
30      yield ['[PC Preview] unknown paramIterMock_K', '[PC Preview] unknown paramIterMock_V'];
31    },
32    next: () => {
33      if (index < 1) {
34        const returnValue = ['[PC Previwe] unknown paramIterMock_K', '[PC Previwe] unknown paramIterMock_V'];
35        index++;
36        return {
37          value: returnValue,
38          done: false
39        };
40      } else {
41        return {
42          done: true
43        };
44      }
45    }
46  };
47  return IteratorEntriesMock;
48`;
49
50const iteratorStringMock = `
51  let index = 0;
52  const IteratorStringMock = {
53    *[Symbol.iterator]() {
54      yield '[PC Preview] unknown string';
55    },
56    next: () => {
57      if (index < 1) {
58        const returnValue = '[PC Previwe] unknown string';
59        index++;
60        return {
61          value: returnValue,
62          done: false
63        };
64      } else {
65        return {
66          done: true
67        };
68      }
69    }
70  };
71  return IteratorStringMock;
72`;
73
74/**
75 * get warn console template
76 * @param interfaceNameOrClassName
77 * @param functionNameOrPropertyName
78 * @returns
79 */
80export function getWarnConsole(interfaceNameOrClassName: string, functionNameOrPropertyName: string): string {
81  return `console.warn('The ${interfaceNameOrClassName}.${functionNameOrPropertyName} interface in the Previewer is a mocked implementation and may behave differently than on a real device.');\n`;
82}
83
84function handlePromiseParams(returnType: ReturnTypeEntity): string {
85  const returnKindName = returnType.returnKindName.slice(0, returnType.returnKindName.length - 1).slice(8).trim();
86  let returnName = `return new Promise((resolve, reject) => {
87    resolve('[PC Preview] unknown type');
88  })`;
89  Object.keys(paramsTypeStart).forEach(key => {
90    if (returnKindName.startsWith(key)) {
91      const data = paramsTypeStart[key] === '[PC Preview] unknown type' ? `'${paramsTypeStart[key]}'` : `${paramsTypeStart[key]}`;
92      returnName = `return new Promise((resolve, reject) => {
93        resolve(${data});
94      })`;
95    }
96  });
97  return returnName;
98}
99
100/**
101 * generate return statement;
102 * @param returnType
103 * @param sourceFile
104 * @returns
105 */
106export function getReturnStatement(returnType: ReturnTypeEntity, sourceFile: SourceFile): string {
107  if (returnType.returnKind === SyntaxKind.TypeReference) {
108    return handleTypeReferenceReturnBody(returnType, sourceFile);
109  } else if (returnType.returnKind === SyntaxKind.UnionType) {
110    return handleUnionTypeReturnBody(returnType);
111  }
112  let returnName = returnType.returnKindName.trim();
113  let temp = true;
114  if (returnName.endsWith(']')) {
115    returnName = '[]';
116    temp = false;
117  } else {
118    Object.keys(paramsTypeStart).forEach(key => {
119      if (returnType.returnKindName.startsWith(key)) {
120        returnName = paramsTypeStart[key];
121        temp = false;
122      }
123    });
124  }
125  if (temp) {
126    return 'return \'[PC Preview] unknown type\'';
127  }
128  return `return ${returnName};`;
129}
130
131/**
132 * TypeReference return statement;
133 * @param returnType
134 * @param sourceFile
135 * @returns
136 */
137function handleTypeReferenceReturnBody(returnType: ReturnTypeEntity, sourceFile: SourceFile): string {
138  if (returnType.returnKindName.startsWith('Promise')) {
139    return handlePromiseParams(returnType);
140  } else if (returnType.returnKindName === 'T') {
141    return 'return \'[PC Preview] unknown type\'';
142  } else if (returnType.returnKindName === 'object' || returnType.returnKindName === 'Object') {
143    return 'return {}';
144  } else if (returnType.returnKindName === 'Function') {
145    return 'return \'[PC Preview] unknown type\'';
146  } else if (returnType.returnKindName === 'String' || returnType.returnKindName === 'string') {
147    return `return ${returnType.returnKindName}(...args)`;
148  } else if (returnType.returnKindName === 'number' || returnType.returnKindName === 'Number') {
149    return 'return 0';
150  } else if (returnType.returnKindName === 'boolean' || returnType.returnKindName === 'Boolean') {
151    return 'return false';
152  } else if (returnType.returnKindName === 'ArrayBuffer') {
153    return `return new ${returnType.returnKindName}(0)`;
154  } else if (returnType.returnKindName.startsWith('Array')) {
155    if (returnType.returnKindName.includes('<') && returnType.returnKindName.includes('>')) {
156      return `return [${generateGenericTypeToMockValue(returnType.returnKindName)}]`;
157    } else {
158      return `return new ${returnType.returnKindName}()`;
159    }
160  } else if (returnType.returnKindName.startsWith('Readonly')) {
161    return `return ${returnType.returnKindName.split('<')[1].split('>')[0]}`;
162  } else if (checkIsGenericSymbol(returnType.returnKindName)) {
163    return `return '[PC Preview] unknown iterableiterator_${returnType.returnKindName}'`;
164  } else if (returnType.returnKindName.startsWith('Uint8Array')) {
165    return `return new ${returnType.returnKindName}()`;
166  } else if (returnType.returnKindName.startsWith('IterableIterator')) {
167    return returnType.returnKindName.includes(',') ? iteratorEntriesMock : iteratorStringMock;
168  } else if (returnType.returnKindName.includes('<T>')) {
169    const tmpReturn = returnType.returnKindName.split('<')[0];
170    return tmpReturn.startsWith('Array') ? 'return []' : 'return {}';
171  } else if (returnType.returnKindName.includes('<')) {
172    return returnType.returnKindName.includes(',') ? 'return {};' : `return new ${returnType.returnKindName.split('<')[0]}()`;
173  } else {
174    if (getClassNameSet().has(returnType.returnKindName)) {
175      return returnType.returnKindName === 'Want' ? 'return mockWant().Want' : `return new ${returnType.returnKindName}()`;
176    } else if (propertyTypeWhiteList(returnType.returnKindName) === returnType.returnKindName) {
177      return `return ${getTheRealReferenceFromImport(sourceFile, returnType.returnKindName)}`;
178    } else {
179      return `return ${propertyTypeWhiteList(returnType.returnKindName)}`;
180    }
181  }
182}
183
184/**
185 * UnionType return statement;
186 * @param returnType
187 * @returns
188 */
189function handleUnionTypeReturnBody(returnType: ReturnTypeEntity): string {
190  const returnNames = returnType.returnKindName.split('|');
191  let returnName = returnNames[0];
192  for (let i = 0; i < returnNames.length; i++) {
193    if (!returnNames[i].includes('[]') && !returnNames[i].includes('<')) {
194      returnName = returnNames[i];
195      break;
196    }
197  }
198  if (returnName.trimStart().trimEnd() === 'void') {
199    return '';
200  }
201  if (getClassNameSet().has(returnName)) {
202    return `return new ${returnName}()`;
203  } else {
204    return `return ${getBaseReturnValue(returnName.trimStart().trimEnd())}`;
205  }
206}
207
208/**
209 * special property whitelist
210 * @param propertyTypeName
211 * @returns
212 */
213export function propertyTypeWhiteList(propertyTypeName: string): boolean | number | string {
214  const whiteList = ['GLboolean', 'GLuint', 'GLenum', 'GLint', 'NotificationFlags'];
215  if (whiteList.includes(propertyTypeName)) {
216    if (propertyTypeName === 'NotificationFlags' || propertyTypeName === 'GLenum') {
217      return `'[PC Preview] unknown ${propertyTypeName}'`;
218    } else if (propertyTypeName === 'GLboolean') {
219      return true;
220    } else {
221      return 0;
222    }
223  } else {
224    return propertyTypeName;
225  }
226}
227
228/**
229 * get basic return value
230 * @param value
231 * @returns
232 */
233export function getBaseReturnValue(value: string): string | number | boolean {
234  if (value === 'string') {
235    return '\'\'';
236  } else if (value === 'number') {
237    return 0;
238  } else if (value === 'boolean') {
239    return true;
240  } else if (value === 'Object' || value === 'object') {
241    return '{}';
242  } else if (checkIsGenericSymbol(value)) {
243    return '\'[PC Preview] unknown type\'';
244  } else if (value === 'WebGLActiveInfo') {
245    return '{size: \'[PC Preview] unknown GLint\', type: 0, name: \'[PC Preview] unknown name\'}';
246  } else {
247    return value;
248  }
249}
250
251/**
252 * get current sourceFile import data
253 * @param sourceFile
254 * @param typeName
255 * @returns
256 */
257export function getTheRealReferenceFromImport(sourceFile: SourceFile, typeName: string): string {
258  const importArray = getImportDeclarationArray(sourceFile);
259  let returnName = '';
260  let isFromImport = false;
261  let isOhos = false;
262  let mockMockName = '';
263  importArray.forEach(value => {
264    if (typeName.includes('.') && typeName.split('.')[0] === value.importElements) {
265      isFromImport = true;
266      if (value.importPath.includes('@ohos')) {
267        isOhos = true;
268      }
269      if (value.importElements.trimStart().trimEnd() === typeName.split('.')[0]) {
270        const tmpArr = value.importPath.split('.');
271        mockMockName = tmpArr[tmpArr.length - 1].replace(/'/g, '').replace(/"/g, '');
272      }
273    }
274  });
275  if (isFromImport) {
276    const splitReturnKindName = typeName.split('.');
277    let left = '';
278    for (let i = 1; i < splitReturnKindName.length; i++) {
279      left += `.${splitReturnKindName[i]}`;
280    }
281    if (isOhos) {
282      returnName = `mock${firstCharacterToUppercase(mockMockName)}()${left}`;
283    }
284  } else {
285    returnName = getImportTypeAliasNameFromImportElements(importArray, typeName);
286  }
287  return returnName.split('<')[0];
288}
289
290/**
291 * get return type alias, for example: {Context as _Context} return _Context
292 * @param importElementEntity
293 * @param typeName
294 * @returns
295 */
296function getImportTypeAliasNameFromImportElements(importElementEntity: ImportElementEntity[], typeName: string): string {
297  for (let i = 0; i < importElementEntity.length; i++) {
298    if (importElementEntity[i].importElements.includes('_')) {
299      const importElements = importElementEntity[i].importElements.replace('{', '').replace('}', '').split(',');
300      for (let j = 0; j < importElements.length; j++) {
301        const element = importElements[j].trimStart().trimEnd();
302        if (!element) {
303          continue;
304        }
305        if (`_${typeName}` === element.trim()) {
306          return `_${typeName}`;
307        }
308        if (element.includes(' as ') && `_${typeName}` === element.split('as')[1].trim()) {
309          return `_${typeName}`;
310        }
311      }
312    }
313  }
314  if (typeName === 'Want') {
315    typeName = 'mockWant().Want';
316  } else if (typeName === 'InputMethodExtensionContext') {
317    typeName = 'mockInputMethodExtensionContext().InputMethodExtensionContext';
318  } else if (typeName.includes('<') && typeName.includes(',')) {
319    typeName = '{}';
320  }
321  return typeName;
322}
323
324/**
325 * check is generic symbol
326 * @param type
327 * @returns
328 */
329export function checkIsGenericSymbol(type: string): boolean {
330  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'];
331  return words.includes(type);
332}
333
334/**
335 * generate basic type default value
336 * @param kindName
337 * @returns
338 */
339export function generateGenericTypeToMockValue(kindName: string): string | number | boolean {
340  const genericTypeName = kindName.split('<')[1].split('>')[0];
341  if (genericTypeName === 'string') {
342    return '\'\'';
343  } else if (genericTypeName === 'number') {
344    return 0;
345  } else if (genericTypeName === 'boolean') {
346    return true;
347  } else if (genericTypeName === 'Object' || genericTypeName === 'object') {
348    return '{}';
349  } else {
350    return '';
351  }
352}
353
354export const paramsTypeStart = {
355  'void': '\'[PC Preview] unknown type\'',
356  'Array': '[]',
357  'Object': '{}',
358  'object': '{}',
359  '{': '{}',
360  'string': '""',
361  'String': '""',
362  'number': 0,
363  'Number': 0,
364  'boolean': false,
365  'Boolean': false,
366  'ArrayBuffer': 'new ArrayBuffer(0)',
367  'Uint8Array': 'new Uint8Array()',
368  'unknown': '\'[PC Preview] unknown type\''
369};
370
371const removeCallback = (str: string): { type: string, value: string } => {
372  const callbackParams = {
373    type: 'Callback',
374    value: ''
375  };
376  if (str.startsWith('Callback')) {
377    callbackParams.value = str.slice(0, str.length - 1).slice(9).trim();
378    callbackParams.type = 'Callback';
379  } else if (str.startsWith('AsyncCallback')) {
380    callbackParams.value = str.slice(0, str.length - 1).slice(14).trim();
381    callbackParams.type = 'AsyncCallback';
382  }
383  let isHaveAnglebrackets = false;
384  if (callbackParams.value.includes('<') && callbackParams.value.includes(',')) {
385    isHaveAnglebrackets = true;
386  }
387  if (callbackParams.value.includes(',') && !isHaveAnglebrackets) {
388    callbackParams.value = callbackParams.value.split(',')[0].trim();
389  }
390  return callbackParams;
391};
392
393const isInImportType = (mockApi: string, value: string): string => {
394  let hasDotFirstWorld = '';
395  if (value.includes('.')) {
396    hasDotFirstWorld = value.split('.')[0].trim();
397  }
398  if (hasDotFirstWorld && mockApi.includes(`import { mock${firstLetterWord(hasDotFirstWorld)} `)) {
399    return 'isHasDotImportMock';
400  }
401  if (hasDotFirstWorld && mockApi.includes(`import { ${firstLetterWord(hasDotFirstWorld)} `)) {
402    return 'isNoHasDotImportMock';
403  }
404  if (mockApi.includes(`import { mock${firstLetterWord(value)} `)) {
405    return 'isImportMock';
406  }
407  if (mockApi.includes(`import { ${value} `)) {
408    return 'isImport';
409  }
410  return 'noImport';
411};
412
413const firstLetterWord = (word: string): string => {
414  return word.slice(0, 1).toUpperCase() + word.slice(1);
415};
416
417const hasDotFirstWord = (str: string): string => {
418  return str.includes('.') ? str.split('.')[0] : str;
419};
420
421function callbackHasNoImportType(callbackParams: { type: string, value: string }): string {
422  let callbackData = '';
423  let paramsTypeHasType = true;
424  if (callbackParams.value.endsWith(']')) {
425    callbackData = '[]';
426  } else {
427    Object.keys(paramsTypeStart).forEach(item => {
428      if (callbackParams.value.startsWith(item)) {
429        callbackData = paramsTypeStart[item];
430        paramsTypeHasType = false;
431      }
432    });
433    if (paramsTypeHasType) {
434      callbackData = callbackParams.value;
435      if (callbackParams.value.includes('<')) {
436        callbackData = `${callbackParams.value.split('<')[0]}`;
437      }
438      if (callbackParams.value.includes('<') && callbackParams.value.includes(',')) {
439        callbackData = '{}';
440      }
441    }
442    if (callbackParams.value === 'Date') {
443      callbackData = 'new Date()';
444    }
445    if (callbackParams.value === 'Uint8Array') {
446      callbackData = 'new Uint8Array()';
447    }
448    if (callbackParams.value === 'T') {
449      callbackData = '[PC Preview] unknown type';
450    }
451  }
452  return callbackData;
453}
454
455/**
456 * get callback parameters data
457 * @returns data: parameters data: type: AsyncCallback or Callback
458 */
459const setCallbackData = (mockApi: string, paramTypeString: string): { data: string, type: string } => {
460  const callbackParams = removeCallback(paramTypeString);
461  let callbackData = '';
462  let importType = '';
463  if (callbackParams.value) {
464    importType = isInImportType(mockApi, callbackParams.value);
465  }
466  if (importType === 'isHasDotImportMock') {
467    const upperWord = firstLetterWord(callbackParams.value); // Image.PixelMap
468    const firstWord = hasDotFirstWord(upperWord); // Image
469    callbackData = `mock${firstWord}()${upperWord.slice(firstWord.length)}`;
470  } else if (importType === 'isNoHasDotImportMock') {
471    callbackData = callbackParams.value;
472  } else if (importType === 'isImportMock') {
473    callbackData = `mock${firstLetterWord(callbackParams.value)}()`;
474  } else if (importType === 'isImport') {
475    callbackData = callbackParams.value;
476  } else if (importType === 'noImport') {
477    callbackData = callbackHasNoImportType(callbackParams);
478  } else {
479    callbackData = '[PC Preview] unknown type';
480  }
481  return {
482    data: callbackData,
483    type: callbackParams.type
484  };
485};
486
487/**
488 * get callback statement
489 * @returns callback statement
490 */
491export function getCallbackStatement(mockApi: string, paramTypeString?: string): string {
492  let outPut = `if (args && typeof args[args.length - 1] === 'function') {
493    args[args.length - 1].call(this,`;
494  const callbackError = "{'code': '','data': '','name': '','message': '','stack': ''}";
495  let callbackDataParams = {
496    type: '',
497    data: '[PC Preview] unknown type'
498  };
499  if (paramTypeString) {
500    callbackDataParams = setCallbackData(mockApi, paramTypeString);
501  }
502  if (callbackDataParams?.type === 'AsyncCallback') {
503    outPut += ` ${callbackError},`;
504  }
505  outPut += callbackDataParams.data === '[PC Preview] unknown type' ? ` '${callbackDataParams.data}');\n}` : ` ${callbackDataParams.data});\n}`;
506  return outPut;
507}
508
509/**
510 * get callback statement
511 * @returns callback statement
512 */
513export function getOverloadedFunctionCallbackStatement(
514  entityArray: Array<FunctionEntity> | Array<MethodEntity> | Array<MethodSignatureEntity>,
515  sourceFile: SourceFile,
516  mockApi: string
517): string {
518  let overloadedCallbackBody = '';
519  entityArray.forEach(functionBody => {
520    let content = '';
521    let firstParamContent = '';
522    let callbackParamContent = '';
523    functionBody.args.forEach(arg => {
524      if (
525        arg.paramTypeString.startsWith("'") && arg.paramTypeString.endsWith("'") ||
526        arg.paramTypeString.startsWith('"') && arg.paramTypeString.endsWith('"')
527      ) {
528        const paramTypeStringArr = arg.paramTypeString.split('|');
529        firstParamContent += `if (args && [${paramTypeStringArr}].includes(args[0])) {\n`;
530      }
531      if (['callback', 'observercallback', 'listener', 'synccallback'].includes(arg.paramName.toLowerCase())) {
532        callbackParamContent += getCallbackBody(mockApi, arg.paramTypeString);
533      }
534    });
535    if (firstParamContent) {
536      content = `${firstParamContent}${callbackParamContent}\n}` + content;
537    } else {
538      content += callbackParamContent;
539    }
540    overloadedCallbackBody += content;
541  });
542  overloadedCallbackBody += '\n';
543  return overloadedCallbackBody;
544}
545
546/**
547 * get callback statement
548 * @returns callback statement
549 */
550function getCallbackBody(mockApi: string, paramString: string): string {
551  let bodyInfo = `if (args && typeof args[args.length - 1] === 'function') {
552    args[args.length - 1].call(this,`;
553  const callbackError = "{'code': '','data': '','name': '','message': '','stack': ''}";
554  if (paramString === 'ErrorCallback') {
555    bodyInfo += callbackError + ');\n}';
556    return bodyInfo;
557  }
558  let callbackDataParams = {
559    type: '',
560    data: '[PC Preview] unknown type'
561  };
562  if (paramString) {
563    callbackDataParams = setCallbackData(mockApi, paramString);
564  }
565  if (callbackDataParams?.type === 'AsyncCallback') {
566    bodyInfo += ` ${callbackError},`;
567  }
568  bodyInfo += callbackDataParams.data === '[PC Preview] unknown type' ? ` '${callbackDataParams.data}');\n` : ` ${callbackDataParams.data});\n`;
569  bodyInfo += '}';
570  return bodyInfo;
571}
572
573/**
574 * get iterator template string
575 * @param methodEntity
576 * @returns
577 */
578export function generateSymbolIterator(methodEntity: MethodEntity): string {
579  let iteratorMethod = '';
580  if (methodEntity.returnType.returnKindName.includes('<[')) {
581    iteratorMethod += `let index = 0;
582    const IteratorMock = {
583      next: () => {
584        if (index < 1) {
585          const returnValue = ['[PC Previwe] unknown iterableiterator_k', '[PC Previwe] unknown iterableiterator_v'];
586          index++;
587          return {
588            value: returnValue,
589            done: false
590          };
591        } else {
592          return {
593            done: true
594          };
595        }
596      }
597    };
598    return IteratorMock;`;
599  } else {
600    iteratorMethod += `let index = 0;
601    const IteratorMock = {
602      next: () => {
603        if (index < 1) {
604          index++;
605          return {
606            value: '[PC Preview] unknown any',
607            done: false
608          };
609        } else {
610          return {
611            done: true
612          };
613        }
614      }
615    };
616    return IteratorMock;`;
617  }
618
619  return iteratorMethod;
620}
621
622function handleReturnDataNoImportType(returnPromiseParams: string, returnType: ReturnTypeEntity): string {
623  let returnData = '';
624  if (returnPromiseParams.startsWith('[') || returnPromiseParams.endsWith(']')) {
625    returnData = '[]';
626  } else {
627    let paramsTypeHasType = true;
628    Object.keys(paramsTypeStart).forEach(item => {
629      if (returnPromiseParams.startsWith(item)) {
630        returnData = paramsTypeStart[item];
631        paramsTypeHasType = false;
632      }
633    });
634    if (paramsTypeHasType) {
635      returnData = returnPromiseParams;
636      if (returnPromiseParams.includes('<')) {
637        returnData = `${returnPromiseParams.split('<')[0]}`;
638      }
639      if (returnPromiseParams.includes('<') && returnPromiseParams.includes(',')) {
640        returnData = '{}';
641      }
642    }
643    if (returnPromiseParams === 'Date') {
644      returnData = 'new Date()';
645    }
646    if (returnPromiseParams === 'T') {
647      returnData = '"[PC Preview] unknown type"';
648    }
649    if (returnType.returnKindName.startsWith('Readonly')) {
650      returnData = `${returnType.returnKindName.split('<')[1].split('>')[0]}`;
651    }
652    if (checkIsGenericSymbol(returnType.returnKindName)) {
653      returnData = `'[PC Preview] unknown iterableiterator_${returnType.returnKindName}'`;
654    }
655  }
656  return returnData;
657}
658
659/**
660 * generate more function name return statement;
661 * @param isReturnPromise
662 * @param returnType
663 * @param sourceFile
664 * @param mockApi
665 * @returns
666 */
667export function getReturnData(isCallBack: boolean, isReturnPromise: boolean, returnType: ReturnTypeEntity, sourceFile: SourceFile, mockApi: string): string {
668  // If the return value is an iterator IterableIterator, then iteratorEntriesMock is directly returned
669  if (returnType.returnKindName.startsWith('IterableIterator')) {
670    return returnType.returnKindName.includes(',') ? iteratorEntriesMock : iteratorStringMock;
671  }
672  // If it is a promise, intercept the content of x in promise<x>, which may have the following formats:
673  // fun(): y | Promise<y>、 fun(): Promise<x | y | z>、 fun(): Promise<x>、 fun(): Promise<x.y>
674  // If it is not a promise, the returned type may be x, x | y | z, x.y
675  let returnPromiseParams = returnType.returnKindName;
676  if (isReturnPromise) {
677    if (returnType.returnKind === SyntaxKind.UnionType) {
678      // fun(): y | Promise<y>
679      const returnNames = returnPromiseParams.split('|');
680      for (let i = 0; i < returnNames.length; i++) {
681        if (returnNames[i].trim().startsWith('Promise<')) {
682          // Promise<y>
683          returnPromiseParams = returnNames[i].trim();
684          break;
685        }
686      }
687    }
688    // At this point, obtain the values in these formats: Promise<x | y | z>, Promise<y>, Promise<x.y>, Promise<x>
689    const kindName = returnPromiseParams;
690    returnPromiseParams = kindName.slice(0, kindName.length - 1).slice(8).trim();
691  }
692  // At this point, the value type of param in promise<param>may be x, x | y | z, x.y
693  if (returnPromiseParams.includes('|')) {
694    returnPromiseParams = getSeparatorParam(returnPromiseParams);
695  }
696
697  // At this point, the possible types of promiseParam are x, x.y x [] Array<x>
698  // Check if it was imported
699  let returnData = '"[PC Preview] unknown type"';
700  const importType = isInImportType(mockApi, returnPromiseParams);
701  if (importType === 'isHasDotImportMock') {
702    const upperWord = firstLetterWord(returnPromiseParams); // Image.PixelMap
703    const firstWord = hasDotFirstWord(upperWord); // Image
704    returnData = `mock${firstWord}()${upperWord.slice(firstWord.length)}`;
705  } else if (importType === 'isNoHasDotImportMock') {
706    returnData = returnPromiseParams;
707  } else if (importType === 'isImportMock') {
708    returnData = `mock${firstLetterWord(returnPromiseParams)}()`;
709  } else if (importType === 'isImport') {
710    returnData = returnPromiseParams;
711  } else if (importType === 'noImport') {
712    returnData = handleReturnDataNoImportType(returnPromiseParams, returnType);
713  } else {
714    returnData = '"[PC Preview] unknown type"';
715  }
716  const data = typeof returnData === 'string' && returnData.startsWith('[PC Preview] unknown') ? `'${returnData}'` : `${returnData}`;
717  if (isReturnPromise) {
718    return `
719        return new Promise((resolve, reject) => {
720          resolve(${data});
721        })
722      `;
723  } else {
724    return `return ${data}`;
725  }
726}
727
728/**
729 *
730 * @param returnPromiseParams
731 * @returns
732 */
733function getSeparatorParam(returnPromiseParams: string): string {
734  let hasObj = '';
735  let hasArr = '';
736  let hasUint8Array = '';
737  let hasArrayBuffer = '';
738  let otherValue = '';
739  const paramsArr = returnPromiseParams.split('|');
740  for (let i = 0; i < paramsArr.length; i++) {
741    const param = paramsArr[i].trim();
742    if (param.startsWith('{') || param.startsWith('Object')) {
743      hasObj = '{}';
744    } else if (param.endsWith(']') || param.startsWith('[') || param.startsWith('Array<')) {
745      hasArr = '[]';
746    } else if (param.startsWith('Uint8Array')) {
747      hasUint8Array = 'Uint8Array';
748    } else if (param.startsWith('ArrayBuffer')) {
749      hasArrayBuffer = 'ArrayBuffer';
750    } else {
751      if (param !== null) {
752        otherValue = param;
753      }
754    }
755  }
756  if (hasObj) {
757    return hasObj;
758  }
759  if (hasArr) {
760    return hasArr;
761  }
762  if (hasUint8Array) {
763    return hasUint8Array;
764  }
765  if (hasArrayBuffer) {
766    return hasArrayBuffer;
767  }
768  return otherValue;
769}
770
771/**
772 *
773 * @param mockName string
774 * @param sourceFile SourceFile
775 * @returns boolean
776 */
777export function hasExportDefaultKeyword(mockName: string, sourceFile: SourceFile): boolean {
778  let fileContent = sourceFile.getText();
779  const removeNoteRegx = /\/\*[\s\S]*?\*\//g;
780  fileContent = fileContent.replace(removeNoteRegx, '');
781  if (
782    fileContent.includes(`export default class ${firstCharacterToUppercase(mockName)} `) ||
783    fileContent.includes(`export default interface ${firstCharacterToUppercase(mockName)} `) ||
784    fileContent.includes(`export default ${firstCharacterToUppercase(mockName)}`)
785  ) {
786    return false;
787  }
788  return true;
789}
790
791export const overloadedFunctionArr = ['on', 'off'];
792
793export const needToAddBrace = ['ViewData', 'AutoFillType'];
794
795export const needAddExtraClass = ['date_picker.d.ts', 'rich_editor.d.ts', 'text_picker.d.ts', 'text_timer.d.ts'];
796
797export interface MockFunctionElementEntity {
798  elementName: string;
799  type: string
800}
801export interface ReturnDataParams {
802  mockData: string;
803  mockFunctionElements: Array<MockFunctionElementEntity>
804}
805