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 { MethodSignatureEntity } from '../declaration-node/methodSignatureDeclaration';
19import {
20  getCallbackStatement,
21  getReturnStatement,
22  getWarnConsole,
23  getReturnData,
24  getOverloadedFunctionCallbackStatement,
25  overloadedFunctionArr
26} from './generateCommonUtil';
27import { methodArrayItemForEach } from './generateCommonMethod';
28
29interface MethodSignatureArrayProps {
30  methodSignatureArray: Array<MethodSignatureEntity>;
31  methodEntity: MethodSignatureEntity;
32  methodSignatureBody: string;
33  sourceFile: SourceFile;
34  mockApi: string;
35}
36
37interface MethodSignatureArrayBack {
38  methodSignatureArray: Array<MethodSignatureEntity>;
39  returnSet: Set<string>;
40  isCallBack: boolean;
41  methodSignatureBody: string;
42}
43
44/**
45 * generate interface signature method
46 * @param rootName
47 * @param methodSignatureArray
48 * @param sourceFile
49 * @returns
50 */
51export function generateCommonMethodSignature(
52  rootName: string,
53  methodSignatureArray: Array<MethodSignatureEntity>,
54  sourceFile: SourceFile,
55  mockApi: string
56): string {
57  let methodSignatureBody = '';
58  const methodEntity = methodSignatureArray[0];
59  methodSignatureBody += `${methodEntity.functionName}: function(...args) {`;
60  methodSignatureBody += getWarnConsole(rootName, methodEntity.functionName);
61  if (methodSignatureArray.length === 1) {
62    const args = methodEntity.args;
63    const len = args.length;
64    if (len && args[len - 1].paramName.toLowerCase().includes('callback')) {
65      methodSignatureBody += getCallbackStatement(mockApi, args[len - 1]?.paramTypeString);
66    }
67    if (methodEntity.returnType.returnKind !== SyntaxKind.VoidKeyword) {
68      if (rootName === 'Context' && methodEntity.returnType.returnKindName === 'Context') {
69        methodSignatureBody += 'return Context;';
70      } else {
71        methodSignatureBody += getReturnStatement(methodEntity.returnType, sourceFile);
72      }
73    }
74  } else {
75    const methodSignatureArrayBack = methodSignatureArrayForEach({
76      methodSignatureArray,
77      methodEntity,
78      methodSignatureBody,
79      sourceFile,
80      mockApi
81    });
82    methodSignatureBody = returnSetForEach(methodSignatureArrayBack, sourceFile, mockApi);
83  }
84  methodSignatureBody += '},\n';
85  return methodSignatureBody;
86}
87
88/**
89 * returnSet ForEach
90 * @param porps
91 * @param sourceFile
92 * @param mockApi
93 * @returns
94 */
95function returnSetForEach(porps: MethodSignatureArrayBack, sourceFile: SourceFile, mockApi: string): string {
96  let isReturnPromise = false;
97  let promiseReturnValue = '';
98  let methodSignatureOtherReturnValue = '';
99  porps.returnSet.forEach(value => {
100    if (value.includes('Promise<')) {
101      isReturnPromise = true;
102      promiseReturnValue = value;
103    } else {
104      if (!methodSignatureOtherReturnValue) {
105        methodSignatureOtherReturnValue = value;
106      }
107    }
108  });
109  if (isReturnPromise) {
110    if (promiseReturnValue) {
111      let returnType = null;
112      porps.methodSignatureArray.forEach(value => {
113        if (value.returnType.returnKindName === promiseReturnValue) {
114          returnType = value.returnType;
115        }
116      });
117      porps.methodSignatureBody += getReturnData(porps.isCallBack, isReturnPromise, returnType, sourceFile, mockApi);
118    } else {
119      porps.methodSignatureBody += `
120          return new Promise((resolve, reject) => {
121            resolve('[PC Preview] unknow boolean');
122          })
123        `;
124    }
125  } else if (methodSignatureOtherReturnValue) {
126    let returnType = null;
127    porps.methodSignatureArray.forEach(value => {
128      if (value.returnType.returnKindName === methodSignatureOtherReturnValue) {
129        returnType = value.returnType;
130      }
131    });
132    porps.methodSignatureBody += getReturnData(porps.isCallBack, isReturnPromise, returnType, sourceFile, mockApi);
133  }
134  return porps.methodSignatureBody;
135}
136
137/**
138 * methodSignatureArray ForEach
139 * @param porps
140 * @returns
141 */
142function methodSignatureArrayForEach(porps: MethodSignatureArrayProps): MethodSignatureArrayBack {
143  let argSet: Set<string> = new Set<string>();
144  let argParamsSet: string = '';
145  let returnSet: Set<string> = new Set<string>();
146  let isCallBack = false;
147  let needOverloaded = false;
148  const methodSignatureArray = porps.methodSignatureArray;
149  const sourceFile = porps.sourceFile;
150  const mockApi = porps.mockApi;
151  porps.methodSignatureArray.forEach(value => {
152    ({ returnSet, argSet, isCallBack, argParamsSet, needOverloaded} =
153      methodArrayItemForEach({returnSet, value, argSet, isCallBack, argParamsSet, needOverloaded}));
154  });
155  if (isCallBack) {
156    if (overloadedFunctionArr.includes(porps.methodEntity.functionName) && needOverloaded) {
157      porps.methodSignatureBody += getOverloadedFunctionCallbackStatement(methodSignatureArray, sourceFile, mockApi);
158    } else {
159      porps.methodSignatureBody += getCallbackStatement(porps.mockApi, argParamsSet);
160    }
161  }
162  return {
163    returnSet,
164    isCallBack,
165    methodSignatureBody: porps.methodSignatureBody,
166    methodSignatureArray: porps.methodSignatureArray
167  };
168}
169