• 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 fs from 'fs';
17import path from 'path';
18import type { SourceFile } from 'typescript';
19import { SyntaxKind } from 'typescript';
20import type { InterfaceEntity } from '../declaration-node/interfaceDeclaration';
21import { generateCommonMethodSignature } from './generateCommonMethodSignature';
22import { generateIndexSignature } from './generateIndexSignature';
23import { generatePropertySignatureDeclaration } from './generatePropertySignatureDeclaration';
24import { dtsFileList, getApiInputPath, hasBeenImported, specialFiles } from '../common/commonUtils';
25import type { ImportElementEntity } from '../declaration-node/importAndExportDeclaration';
26import type { PropertySignatureEntity } from '../declaration-node/propertySignatureDeclaration';
27
28/**
29 * generate interface
30 * @param rootName
31 * @param interfaceEntity
32 * @param sourceFile
33 * @param isSourceFile
34 * @returns
35 */
36export function generateInterfaceDeclaration(rootName: string, interfaceEntity: InterfaceEntity, sourceFile: SourceFile, isSourceFile: boolean,
37  mockApi: string, currentSourceInterfaceArray: InterfaceEntity[], importDeclarations?: ImportElementEntity[], extraImport?: string[]): string {
38  const interfaceName = interfaceEntity.interfaceName;
39  let interfaceBody = '';
40  const interfaceElementSet = new Set<string>();
41  if (interfaceEntity.exportModifiers.length > 0 || isSourceFile) {
42    interfaceBody += `export const ${interfaceName} = { \n`;
43  } else {
44    interfaceBody += `const ${interfaceName} = { \n`;
45  }
46
47  if (interfaceEntity.interfacePropertySignatures.length > 0) {
48    interfaceEntity.interfacePropertySignatures.forEach(value => {
49      interfaceBody += generatePropertySignatureDeclaration(interfaceName, value, sourceFile, mockApi) + '\n';
50      interfaceElementSet.add(value.propertyName);
51      addExtraImport(extraImport, importDeclarations, sourceFile, value);
52    });
53  }
54
55  if (interfaceEntity.interfaceMethodSignature.size > 0) {
56    interfaceEntity.interfaceMethodSignature.forEach(value => {
57      interfaceBody += generateCommonMethodSignature(interfaceName, value, sourceFile, mockApi) + '\n';
58      interfaceElementSet.add(value[0].functionName);
59    });
60  }
61
62  if (interfaceEntity.indexSignature.length > 0) {
63    interfaceEntity.indexSignature.forEach(value => {
64      interfaceBody += generateIndexSignature(value) + '\n';
65      interfaceElementSet.add(value.indexSignatureKey);
66    });
67  }
68
69  if (interfaceEntity.heritageClauses.length > 0) {
70    interfaceEntity.heritageClauses.forEach(value => {
71      currentSourceInterfaceArray.forEach(currentInterface => {
72        if (value.types.includes(currentInterface.interfaceName)) {
73          interfaceBody += generateHeritageInterface(currentInterface, sourceFile, interfaceElementSet, mockApi);
74        }
75      });
76    });
77  }
78
79  interfaceBody += '}\n';
80  if (interfaceEntity.exportModifiers.includes(SyntaxKind.DeclareKeyword)) {
81    interfaceBody += `
82      if (!global.${interfaceName}) {
83        global.${interfaceName} = ${interfaceName};\n
84      }
85    `;
86  }
87  return interfaceBody;
88}
89
90function generateHeritageInterface(interfaceEntity: InterfaceEntity, sourceFile: SourceFile, elements: Set<string>, mockApi: string): string {
91  const interfaceName = interfaceEntity.interfaceName;
92  let interfaceBody = '';
93  if (interfaceEntity.interfacePropertySignatures.length > 0) {
94    interfaceEntity.interfacePropertySignatures.forEach(value => {
95      if (!elements.has(value.propertyName)) {
96        interfaceBody += generatePropertySignatureDeclaration(interfaceName, value, sourceFile, mockApi) + '\n';
97      }
98    });
99  }
100
101  if (interfaceEntity.interfaceMethodSignature.size > 0) {
102    interfaceEntity.interfaceMethodSignature.forEach(value => {
103      if (!elements.has(value[0].functionName)) {
104        interfaceBody += generateCommonMethodSignature(interfaceName, value, sourceFile, mockApi) + '\n';
105      }
106    });
107  }
108
109  if (interfaceEntity.indexSignature.length > 0) {
110    interfaceEntity.indexSignature.forEach(value => {
111      if (elements.has(value.indexSignatureKey)) {
112        interfaceBody += generateIndexSignature(value) + '\n';
113      }
114    });
115  }
116  return interfaceBody;
117}
118
119/**
120 *
121 * @param extraImport
122 * @param importDeclarations
123 * @param sourceFile
124 * @param value
125 * @returns
126 */
127function addExtraImport(
128  extraImport: string[],
129  importDeclarations: ImportElementEntity[],
130  sourceFile: SourceFile,
131  value: PropertySignatureEntity): void {
132  if (extraImport && importDeclarations) {
133    const propertyTypeName = value.propertyTypeName.split('.')[0].split('|')[0].split('&')[0].replace(/"'/g, '').trim();
134    if (propertyTypeName.includes('/')) {
135      return;
136    }
137    if (hasBeenImported(importDeclarations, propertyTypeName)) {
138      return;
139    }
140    const specialFilesList = [...specialFiles.map(specialFile => path.join(getApiInputPath(), ...specialFile.split('/')))];
141    if (!specialFilesList.includes(sourceFile.fileName)) {
142      specialFilesList.unshift(sourceFile.fileName);
143    }
144    for (let i = 0; i < specialFilesList.length; i++) {
145      const specialFilePath = specialFilesList[i];
146      let specialFileContent = fs.readFileSync(specialFilePath, 'utf-8');
147      const removeNoteRegx = /\/\*[\s\S]*?\*\//g;
148      specialFileContent = specialFileContent.replace(removeNoteRegx, '');
149      const regex = new RegExp(`\\s${propertyTypeName}\\s({|=|extends)`);
150      const results = specialFileContent.match(regex);
151      if (!results) {
152        continue;
153      }
154      if (sourceFile.fileName === specialFilePath) {
155        return;
156      }
157      let specialFileRelatePath = path.relative(path.dirname(sourceFile.fileName), path.dirname(specialFilePath));
158      if (!specialFileRelatePath.startsWith('./') && !specialFileRelatePath.startsWith('../')) {
159        specialFileRelatePath = './' + specialFileRelatePath;
160      }
161      if (!dtsFileList.includes(specialFilePath)) {
162        dtsFileList.push(specialFilePath);
163      }
164      specialFileRelatePath = specialFileRelatePath.split(path.sep).join('/');
165      const importStr = `import {${propertyTypeName}} from '${
166        specialFileRelatePath}${
167        specialFileRelatePath.endsWith('/') ? '' : '/'}${
168        path.basename(specialFilePath).replace('.d.ts', '').replace('.d.ets', '')}'\n`;
169      if (extraImport.includes(importStr)) {
170        return;
171      }
172      extraImport.push(importStr);
173      return;
174    }
175    if (propertyTypeName.includes('<') || propertyTypeName.includes('[')) {
176      return;
177    }
178    console.log(sourceFile.fileName, 'propertyTypeName', propertyTypeName);
179    return;
180  }
181}
182