• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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