17c804472Sopenharmony_ci/*
27c804472Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
37c804472Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
47c804472Sopenharmony_ci * you may not use this file except in compliance with the License.
57c804472Sopenharmony_ci * You may obtain a copy of the License at
67c804472Sopenharmony_ci *
77c804472Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
87c804472Sopenharmony_ci *
97c804472Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
107c804472Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
117c804472Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
127c804472Sopenharmony_ci * See the License for the specific language governing permissions and
137c804472Sopenharmony_ci * limitations under the License.
147c804472Sopenharmony_ci */
157c804472Sopenharmony_ci
167c804472Sopenharmony_ciimport fs from 'fs';
177c804472Sopenharmony_ciimport path from 'path';
187c804472Sopenharmony_ciimport type { SourceFile } from 'typescript';
197c804472Sopenharmony_ciimport { SyntaxKind } from 'typescript';
207c804472Sopenharmony_ciimport type { InterfaceEntity } from '../declaration-node/interfaceDeclaration';
217c804472Sopenharmony_ciimport { generateCommonMethodSignature } from './generateCommonMethodSignature';
227c804472Sopenharmony_ciimport { generateIndexSignature } from './generateIndexSignature';
237c804472Sopenharmony_ciimport { generatePropertySignatureDeclaration } from './generatePropertySignatureDeclaration';
247c804472Sopenharmony_ciimport { dtsFileList, getApiInputPath, hasBeenImported, specialFiles } from '../common/commonUtils';
257c804472Sopenharmony_ciimport type { ImportElementEntity } from '../declaration-node/importAndExportDeclaration';
267c804472Sopenharmony_ciimport type { PropertySignatureEntity } from '../declaration-node/propertySignatureDeclaration';
277c804472Sopenharmony_ci
287c804472Sopenharmony_ci/**
297c804472Sopenharmony_ci * generate interface
307c804472Sopenharmony_ci * @param interfaceEntity
317c804472Sopenharmony_ci * @param sourceFile
327c804472Sopenharmony_ci * @param isSourceFile
337c804472Sopenharmony_ci * @returns
347c804472Sopenharmony_ci */
357c804472Sopenharmony_ciexport function generateInterfaceDeclaration(
367c804472Sopenharmony_ci  interfaceEntity: InterfaceEntity,
377c804472Sopenharmony_ci  sourceFile: SourceFile,
387c804472Sopenharmony_ci  isSourceFile: boolean,
397c804472Sopenharmony_ci  mockApi: string,
407c804472Sopenharmony_ci  currentSourceInterfaceArray: InterfaceEntity[],
417c804472Sopenharmony_ci  importDeclarations?: ImportElementEntity[],
427c804472Sopenharmony_ci  extraImport?: string[]
437c804472Sopenharmony_ci): string {
447c804472Sopenharmony_ci  const interfaceName = interfaceEntity.interfaceName;
457c804472Sopenharmony_ci  let interfaceBody = '';
467c804472Sopenharmony_ci  let interfaceElementSet = new Set<string>();
477c804472Sopenharmony_ci  if (interfaceEntity.exportModifiers.length > 0 || isSourceFile) {
487c804472Sopenharmony_ci    interfaceBody += `export const ${interfaceName} = { \n`;
497c804472Sopenharmony_ci  } else {
507c804472Sopenharmony_ci    interfaceBody += `const ${interfaceName} = { \n`;
517c804472Sopenharmony_ci  }
527c804472Sopenharmony_ci  if (interfaceEntity.interfacePropertySignatures.length > 0) {
537c804472Sopenharmony_ci    const isAddExtraImportReturn = isNeedAddExtraImport(interfaceEntity, interfaceBody, interfaceName, mockApi, sourceFile,
547c804472Sopenharmony_ci      interfaceElementSet, extraImport, importDeclarations);
557c804472Sopenharmony_ci    interfaceElementSet = isAddExtraImportReturn.interfaceElementSet;
567c804472Sopenharmony_ci    interfaceBody = isAddExtraImportReturn.interfaceBody;
577c804472Sopenharmony_ci  }
587c804472Sopenharmony_ci  if (interfaceEntity.interfaceMethodSignature.size > 0) {
597c804472Sopenharmony_ci    interfaceEntity.interfaceMethodSignature.forEach(value => {
607c804472Sopenharmony_ci      interfaceBody += generateCommonMethodSignature(interfaceName, value, sourceFile, mockApi) + '\n';
617c804472Sopenharmony_ci      interfaceElementSet.add(value[0].functionName);
627c804472Sopenharmony_ci    });
637c804472Sopenharmony_ci  }
647c804472Sopenharmony_ci  if (extraImport.length > 0) {
657c804472Sopenharmony_ci    for (let i = 0; i < extraImport.length; i++) {
667c804472Sopenharmony_ci      if (mockApi.includes(extraImport[i])) {
677c804472Sopenharmony_ci        extraImport.splice(i, 1);
687c804472Sopenharmony_ci      }
697c804472Sopenharmony_ci    }
707c804472Sopenharmony_ci  }
717c804472Sopenharmony_ci  if (interfaceEntity.indexSignature.length > 0) {
727c804472Sopenharmony_ci    interfaceEntity.indexSignature.forEach(value => {
737c804472Sopenharmony_ci      interfaceBody += generateIndexSignature(value) + '\n';
747c804472Sopenharmony_ci      interfaceElementSet.add(value.indexSignatureKey);
757c804472Sopenharmony_ci    });
767c804472Sopenharmony_ci  }
777c804472Sopenharmony_ci  interfaceBody = assemblyInterface(interfaceEntity, currentSourceInterfaceArray, interfaceBody,
787c804472Sopenharmony_ci    sourceFile, interfaceElementSet, mockApi, interfaceName);
797c804472Sopenharmony_ci  return interfaceBody;
807c804472Sopenharmony_ci}
817c804472Sopenharmony_ci
827c804472Sopenharmony_ci/**
837c804472Sopenharmony_ci * @param interfaceEntity
847c804472Sopenharmony_ci * @param interfaceBody
857c804472Sopenharmony_ci * @param interfaceName
867c804472Sopenharmony_ci * @param mockApi
877c804472Sopenharmony_ci * @param sourceFile
887c804472Sopenharmony_ci * @param interfaceElementSet
897c804472Sopenharmony_ci * @param extraImport
907c804472Sopenharmony_ci * @param importDeclarations
917c804472Sopenharmony_ci * @returns
927c804472Sopenharmony_ci */
937c804472Sopenharmony_cifunction isNeedAddExtraImport(
947c804472Sopenharmony_ci  interfaceEntity: InterfaceEntity,
957c804472Sopenharmony_ci  interfaceBody: string,
967c804472Sopenharmony_ci  interfaceName: string,
977c804472Sopenharmony_ci  mockApi: string,
987c804472Sopenharmony_ci  sourceFile: SourceFile,
997c804472Sopenharmony_ci  interfaceElementSet: Set<string>,
1007c804472Sopenharmony_ci  extraImport: string[],
1017c804472Sopenharmony_ci  importDeclarations: ImportElementEntity[]
1027c804472Sopenharmony_ci): { interfaceBody: string; interfaceElementSet: Set<string> } {
1037c804472Sopenharmony_ci  interfaceEntity.interfacePropertySignatures.forEach(value => {
1047c804472Sopenharmony_ci    interfaceBody += generatePropertySignatureDeclaration(interfaceName, value, sourceFile, mockApi) + '\n';
1057c804472Sopenharmony_ci    interfaceElementSet.add(value.propertyName);
1067c804472Sopenharmony_ci    if (!value.propertyTypeName.includes(' ')) {
1077c804472Sopenharmony_ci      // Find out whether the value.propertyTypeName was introduced through import.
1087c804472Sopenharmony_ci      const regex = new RegExp(`import[\\s\n]*?{?[\\s\n]*?${value.propertyTypeName}[,\\s\n]*?`);
1097c804472Sopenharmony_ci      const results = mockApi.match(regex);
1107c804472Sopenharmony_ci      if (results) {
1117c804472Sopenharmony_ci        return;
1127c804472Sopenharmony_ci      }
1137c804472Sopenharmony_ci      let temp = false;
1147c804472Sopenharmony_ci      importDeclarations.forEach(element => {
1157c804472Sopenharmony_ci        // Determine whether the external variable introduced by import contains value.propertyTypeName.
1167c804472Sopenharmony_ci        if (
1177c804472Sopenharmony_ci          element.importPath.startsWith('\'@ohos') &&
1187c804472Sopenharmony_ci          element.importElements.match(new RegExp(`[\\s\n]*${value.propertyTypeName}[,\\s\n]*`))
1197c804472Sopenharmony_ci        ) {
1207c804472Sopenharmony_ci          temp = true;
1217c804472Sopenharmony_ci        }
1227c804472Sopenharmony_ci      });
1237c804472Sopenharmony_ci      if (temp) {
1247c804472Sopenharmony_ci        return;
1257c804472Sopenharmony_ci      }
1267c804472Sopenharmony_ci    }
1277c804472Sopenharmony_ci    addExtraImport(extraImport, importDeclarations, sourceFile, value);
1287c804472Sopenharmony_ci  });
1297c804472Sopenharmony_ci  return {
1307c804472Sopenharmony_ci    interfaceBody,
1317c804472Sopenharmony_ci    interfaceElementSet
1327c804472Sopenharmony_ci  };
1337c804472Sopenharmony_ci}
1347c804472Sopenharmony_ci
1357c804472Sopenharmony_cifunction assemblyInterface(
1367c804472Sopenharmony_ci  interfaceEntity: InterfaceEntity,
1377c804472Sopenharmony_ci  currentSourceInterfaceArray: InterfaceEntity[],
1387c804472Sopenharmony_ci  interfaceBody: string,
1397c804472Sopenharmony_ci  sourceFile: SourceFile,
1407c804472Sopenharmony_ci  interfaceElementSet: Set<string>,
1417c804472Sopenharmony_ci  mockApi: string,
1427c804472Sopenharmony_ci  interfaceName: string
1437c804472Sopenharmony_ci): string {
1447c804472Sopenharmony_ci  if (interfaceEntity.heritageClauses.length > 0) {
1457c804472Sopenharmony_ci    interfaceEntity.heritageClauses.forEach(value => {
1467c804472Sopenharmony_ci      currentSourceInterfaceArray.forEach(currentInterface => {
1477c804472Sopenharmony_ci        if (value.types.includes(currentInterface.interfaceName)) {
1487c804472Sopenharmony_ci          interfaceBody += generateHeritageInterface(currentInterface, sourceFile, interfaceElementSet, mockApi);
1497c804472Sopenharmony_ci        }
1507c804472Sopenharmony_ci      });
1517c804472Sopenharmony_ci    });
1527c804472Sopenharmony_ci  }
1537c804472Sopenharmony_ci  interfaceBody += '}\n';
1547c804472Sopenharmony_ci  if (interfaceEntity.exportModifiers.includes(SyntaxKind.DeclareKeyword)) {
1557c804472Sopenharmony_ci    interfaceBody += `
1567c804472Sopenharmony_ci      if (!global.${interfaceName}) {
1577c804472Sopenharmony_ci        global.${interfaceName} = ${interfaceName};\n
1587c804472Sopenharmony_ci      }
1597c804472Sopenharmony_ci    `;
1607c804472Sopenharmony_ci  }
1617c804472Sopenharmony_ci  return interfaceBody;
1627c804472Sopenharmony_ci}
1637c804472Sopenharmony_ci
1647c804472Sopenharmony_cifunction generateHeritageInterface(
1657c804472Sopenharmony_ci  interfaceEntity: InterfaceEntity,
1667c804472Sopenharmony_ci  sourceFile: SourceFile,
1677c804472Sopenharmony_ci  elements: Set<string>,
1687c804472Sopenharmony_ci  mockApi: string
1697c804472Sopenharmony_ci): string {
1707c804472Sopenharmony_ci  const interfaceName = interfaceEntity.interfaceName;
1717c804472Sopenharmony_ci  let interfaceBody = '';
1727c804472Sopenharmony_ci  if (interfaceEntity.interfacePropertySignatures.length > 0) {
1737c804472Sopenharmony_ci    interfaceEntity.interfacePropertySignatures.forEach(value => {
1747c804472Sopenharmony_ci      if (!elements.has(value.propertyName)) {
1757c804472Sopenharmony_ci        interfaceBody += generatePropertySignatureDeclaration(interfaceName, value, sourceFile, mockApi) + '\n';
1767c804472Sopenharmony_ci      }
1777c804472Sopenharmony_ci    });
1787c804472Sopenharmony_ci  }
1797c804472Sopenharmony_ci
1807c804472Sopenharmony_ci  if (interfaceEntity.interfaceMethodSignature.size > 0) {
1817c804472Sopenharmony_ci    interfaceEntity.interfaceMethodSignature.forEach(value => {
1827c804472Sopenharmony_ci      if (!elements.has(value[0].functionName)) {
1837c804472Sopenharmony_ci        interfaceBody += generateCommonMethodSignature(interfaceName, value, sourceFile, mockApi) + '\n';
1847c804472Sopenharmony_ci      }
1857c804472Sopenharmony_ci    });
1867c804472Sopenharmony_ci  }
1877c804472Sopenharmony_ci
1887c804472Sopenharmony_ci  if (interfaceEntity.indexSignature.length > 0) {
1897c804472Sopenharmony_ci    interfaceEntity.indexSignature.forEach(value => {
1907c804472Sopenharmony_ci      if (elements.has(value.indexSignatureKey)) {
1917c804472Sopenharmony_ci        interfaceBody += generateIndexSignature(value) + '\n';
1927c804472Sopenharmony_ci      }
1937c804472Sopenharmony_ci    });
1947c804472Sopenharmony_ci  }
1957c804472Sopenharmony_ci  return interfaceBody;
1967c804472Sopenharmony_ci}
1977c804472Sopenharmony_ci
1987c804472Sopenharmony_ci/**
1997c804472Sopenharmony_ci * @param extraImport
2007c804472Sopenharmony_ci * @param importDeclarations
2017c804472Sopenharmony_ci * @param sourceFile
2027c804472Sopenharmony_ci * @param value
2037c804472Sopenharmony_ci * @returns
2047c804472Sopenharmony_ci */
2057c804472Sopenharmony_ciexport function addExtraImport(
2067c804472Sopenharmony_ci  extraImport: string[],
2077c804472Sopenharmony_ci  importDeclarations: ImportElementEntity[],
2087c804472Sopenharmony_ci  sourceFile: SourceFile,
2097c804472Sopenharmony_ci  value: PropertySignatureEntity
2107c804472Sopenharmony_ci): void {
2117c804472Sopenharmony_ci  if (extraImport && importDeclarations) {
2127c804472Sopenharmony_ci    const propertyTypeName = value.propertyTypeName.split('.')[0].split('|')[0].split('&')[0].replace(/"'/g, '').trim();
2137c804472Sopenharmony_ci    if (propertyTypeName.includes('/')) {
2147c804472Sopenharmony_ci      return;
2157c804472Sopenharmony_ci    }
2167c804472Sopenharmony_ci    if (hasBeenImported(importDeclarations, propertyTypeName)) {
2177c804472Sopenharmony_ci      return;
2187c804472Sopenharmony_ci    }
2197c804472Sopenharmony_ci    const specialFilesList = [
2207c804472Sopenharmony_ci      ...specialFiles.map(specialFile => path.join(getApiInputPath(), ...specialFile.split('/')))
2217c804472Sopenharmony_ci    ];
2227c804472Sopenharmony_ci    if (!specialFilesList.includes(sourceFile.fileName)) {
2237c804472Sopenharmony_ci      specialFilesList.unshift(sourceFile.fileName);
2247c804472Sopenharmony_ci    }
2257c804472Sopenharmony_ci    searchHasExtraImport(specialFilesList, propertyTypeName, sourceFile, extraImport);
2267c804472Sopenharmony_ci  }
2277c804472Sopenharmony_ci}
2287c804472Sopenharmony_ci
2297c804472Sopenharmony_ci/**
2307c804472Sopenharmony_ci * @param specialFilesList
2317c804472Sopenharmony_ci * @param propertyTypeName
2327c804472Sopenharmony_ci * @param sourceFile
2337c804472Sopenharmony_ci * @param extraImport
2347c804472Sopenharmony_ci * @returns
2357c804472Sopenharmony_ci */
2367c804472Sopenharmony_cifunction searchHasExtraImport(
2377c804472Sopenharmony_ci  specialFilesList: string[],
2387c804472Sopenharmony_ci  propertyTypeName: string,
2397c804472Sopenharmony_ci  sourceFile: SourceFile,
2407c804472Sopenharmony_ci  extraImport: string[]
2417c804472Sopenharmony_ci): void {
2427c804472Sopenharmony_ci  for (let i = 0; i < specialFilesList.length; i++) {
2437c804472Sopenharmony_ci    const specialFilePath = specialFilesList[i];
2447c804472Sopenharmony_ci    if (!fs.existsSync(specialFilePath)) {
2457c804472Sopenharmony_ci      continue;
2467c804472Sopenharmony_ci    }
2477c804472Sopenharmony_ci    let specialFileContent = fs.readFileSync(specialFilePath, 'utf-8');
2487c804472Sopenharmony_ci    const removeNoteRegx = /\/\*[\s\S]*?\*\//g;
2497c804472Sopenharmony_ci    specialFileContent = specialFileContent.replace(removeNoteRegx, '');
2507c804472Sopenharmony_ci    const regex = new RegExp(`\\s${propertyTypeName}\\s*(<|{|=|extends)`);
2517c804472Sopenharmony_ci    const results = specialFileContent.match(regex);
2527c804472Sopenharmony_ci    if (!results) {
2537c804472Sopenharmony_ci      continue;
2547c804472Sopenharmony_ci    }
2557c804472Sopenharmony_ci    if (sourceFile.fileName === specialFilePath) {
2567c804472Sopenharmony_ci      return;
2577c804472Sopenharmony_ci    }
2587c804472Sopenharmony_ci    let specialFileRelatePath = path.relative(path.dirname(sourceFile.fileName), path.dirname(specialFilePath));
2597c804472Sopenharmony_ci    if (!specialFileRelatePath.startsWith('./') && !specialFileRelatePath.startsWith('../')) {
2607c804472Sopenharmony_ci      specialFileRelatePath = './' + specialFileRelatePath;
2617c804472Sopenharmony_ci    }
2627c804472Sopenharmony_ci    if (!dtsFileList.includes(specialFilePath)) {
2637c804472Sopenharmony_ci      dtsFileList.push(specialFilePath);
2647c804472Sopenharmony_ci    }
2657c804472Sopenharmony_ci    specialFileRelatePath = specialFileRelatePath.split(path.sep).join('/');
2667c804472Sopenharmony_ci    const importStr = `import { ${propertyTypeName} } from '${specialFileRelatePath}${
2677c804472Sopenharmony_ci      specialFileRelatePath.endsWith('/') ? '' : '/'
2687c804472Sopenharmony_ci    }${path.basename(specialFilePath).replace('.d.ts', '').replace('.d.ets', '')}'\n`;
2697c804472Sopenharmony_ci    if (extraImport.includes(importStr)) {
2707c804472Sopenharmony_ci      return;
2717c804472Sopenharmony_ci    }
2727c804472Sopenharmony_ci    extraImport.push(importStr);
2737c804472Sopenharmony_ci    return;
2747c804472Sopenharmony_ci  }
2757c804472Sopenharmony_ci  if (propertyTypeName.includes('<') || propertyTypeName.includes('[')) {
2767c804472Sopenharmony_ci    return;
2777c804472Sopenharmony_ci  }
2787c804472Sopenharmony_ci  console.log(sourceFile.fileName, 'propertyTypeName', propertyTypeName);
2797c804472Sopenharmony_ci  return;
2807c804472Sopenharmony_ci}
281