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