• 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 type { MethodEntity } from '../declaration-node/methodDeclaration';
19import type { FunctionEntity } from '../declaration-node/functionDeclaration';
20import type { MethodSignatureEntity } from '../declaration-node/methodSignatureDeclaration';
21import {
22  generateSymbolIterator,
23  getCallbackStatement,
24  getReturnStatement,
25  getWarnConsole,
26  getReturnData,
27  getOverloadedFunctionCallbackStatement,
28  overloadedFunctionArr
29} from './generateCommonUtil';
30
31interface MethodArrayProps {
32  methodArray: Array<MethodEntity>,
33  methodEntity: MethodEntity,
34  sourceFile: SourceFile,
35  mockApi: string,
36  methodBody: string
37}
38
39interface MethodArrayItemForEachProps {
40  returnSet: Set<string>,
41  value: MethodEntity | FunctionEntity | MethodSignatureEntity,
42  argSet: Set<string>,
43  isCallBack: boolean,
44  argParamsSet: string,
45  needOverloaded: boolean
46}
47
48interface MethodArrayBack {
49  returnSet: Set<string>,
50  methodBody: string,
51  isCallBack: boolean
52}
53
54/**
55 * generate class method
56 * @param rootName
57 * @param methodArray
58 * @param sourceFile
59 * @returns
60 */
61export function generateCommonMethod(
62  rootName: string,
63  methodArray: Array<MethodEntity>,
64  sourceFile: SourceFile,
65  mockApi: string
66): string {
67  let methodBody = '';
68  const methodEntity = methodArray[0];
69  if (methodEntity.functionName.name === 'Symbol.iterator') {
70    methodBody += `this[${methodEntity.functionName.name}] = function(...args) {`;
71    methodBody += getWarnConsole(rootName, methodEntity.functionName.name);
72    methodBody += generateSymbolIterator(methodEntity);
73    methodBody += '};\n';
74    return methodBody;
75  } else {
76    methodBody += `this.${methodEntity.functionName.name} = function(...args) {`;
77    methodBody += getWarnConsole(rootName, methodEntity.functionName.name);
78  }
79
80  if (methodArray.length === 1) {
81    const args = methodEntity.args;
82    const len = args.length;
83    if (args.length > 0 && args[len - 1].paramName.toLowerCase().includes('callback')) {
84      methodBody += getCallbackStatement(mockApi, args[len - 1]?.paramTypeString);
85    }
86    if (methodEntity.returnType.returnKind !== SyntaxKind.VoidKeyword) {
87      if (methodEntity.functionName.name === 'getApplicationContext') {
88        methodBody += getApplicationContextValue(methodEntity.functionName.name);
89      } else {
90        methodBody += getReturnStatement(methodEntity.returnType, sourceFile);
91      }
92    }
93  } else {
94    const methodArrayBack = methodArrayForEach({ methodArray, methodEntity, sourceFile, mockApi, methodBody });
95    methodBody = returnSetForEach(methodArrayBack, methodArray, sourceFile, mockApi);
96  }
97  methodBody += '};\n';
98  return methodBody;
99}
100
101function getApplicationContextValue(name: string): string {
102  return `
103const mockData = {
104  on: function (...args) {
105    console.warn(
106      'The ${name}.on interface in the Previewer is a mocked implementation and may behave differently than on a real device.'
107    );
108    if (args && ['environment'].includes(args[0])) {
109      if (args && typeof args[args.length - 1] === 'function') {
110        const EnvironmentCallback = mockEnvironmentCallback();
111        args[args.length - 1].call(this, new EnvironmentCallback());
112      }
113    }
114    return 0;
115  },
116  off: function (...args) {
117    console.warn(
118      'The ${name}.off interface in the Previewer is a mocked implementation and may behave differently than on a real device.'
119    );
120    if (args && ['environment'].includes(args[0])) {
121      if (args && typeof args[args.length - 1] === 'function') {
122        args[args.length - 1].call(
123          this,
124          { 'code': '', 'data': '', 'name': '', 'message': '', 'stack': '' },
125          '[PC Preview] unknown type'
126        );
127      }
128    }
129    return new Promise((resolve, reject) => {
130        resolve('[PC Preview] unknown type');
131    });
132  }
133};
134return mockData;
135  `;
136}
137
138/**
139 * method Array ForEach
140 * @param props
141 * @returns
142 */
143function methodArrayForEach(props: MethodArrayProps): MethodArrayBack {
144  let argSet: Set<string> = new Set<string>();
145  let argParamsSet: string = '';
146  let returnSet: Set<string> = new Set<string>();
147  let isCallBack = false;
148  let needOverloaded = false;
149  props.methodArray.forEach(value => {
150    ({ returnSet, argSet, isCallBack, argParamsSet, needOverloaded} =
151      methodArrayItemForEach({returnSet, value, argSet, isCallBack, argParamsSet, needOverloaded}));
152  });
153  if (isCallBack) {
154    if (overloadedFunctionArr.includes(props.methodEntity.functionName.name) && needOverloaded) {
155      props.methodBody += getOverloadedFunctionCallbackStatement(props.methodArray, props.sourceFile, props.mockApi);
156    } else {
157      props.methodBody += getCallbackStatement(props.mockApi, argParamsSet);
158    }
159  }
160  return {
161    returnSet,
162    methodBody: props.methodBody,
163    isCallBack
164  };
165}
166
167/**
168 * method ArrayItem ForEach
169 * @param props
170 * @returns
171 */
172export function methodArrayItemForEach(
173  props: MethodArrayItemForEachProps
174): MethodArrayItemForEachProps {
175  props.returnSet.add(props.value.returnType.returnKindName);
176  props.value.args.forEach(arg => {
177    props.argSet.add(arg.paramName);
178    if (arg.paramName.toLowerCase().includes('callback')) {
179      props.isCallBack = true;
180      if (arg.paramTypeString) {
181        props.argParamsSet = arg.paramTypeString;
182      }
183    }
184    if (
185      arg.paramTypeString.startsWith("'") && arg.paramTypeString.endsWith("'") ||
186      arg.paramTypeString.startsWith('"') && arg.paramTypeString.endsWith('"')
187    ) {
188      props.needOverloaded = true;
189    }
190  });
191  return props;
192}
193
194/**
195 * returnSet ForEach
196 * @param props
197 * @param methodArray
198 * @param sourceFile
199 * @param mockApi
200 * @returns
201 */
202function returnSetForEach(
203  props: MethodArrayBack,
204  methodArray: Array<MethodEntity>,
205  sourceFile: SourceFile,
206  mockApi: string
207): string {
208  let isReturnPromise = false;
209  let promiseReturnValue = '';
210  let methodOtherReturnValue = '';
211  props.returnSet.forEach(value => {
212    if (value.includes('Promise<')) {
213      isReturnPromise = true;
214      promiseReturnValue = value;
215    } else {
216      if (!methodOtherReturnValue) {
217        methodOtherReturnValue = value;
218      }
219    }
220  });
221  if (isReturnPromise) {
222    if (promiseReturnValue) {
223      let returnType = null;
224      methodArray.forEach(value => {
225        if (value.returnType.returnKindName === promiseReturnValue) {
226          returnType = value.returnType;
227        }
228      });
229      props.methodBody += getReturnData(props.isCallBack, isReturnPromise, returnType, sourceFile, mockApi);
230    } else {
231      props.methodBody += `
232            return new Promise((resolve, reject) => {
233              resolve('[PC Preview] unknow boolean');
234            })
235          `;
236    }
237  } else if (methodOtherReturnValue) {
238    let returnType = null;
239    methodArray.forEach(value => {
240      if (value.returnType.returnKindName === methodOtherReturnValue) {
241        returnType = value.returnType;
242      }
243    });
244    props.methodBody += getReturnData(props.isCallBack, isReturnPromise, returnType, sourceFile, mockApi);
245  }
246  return props.methodBody;
247}
248