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 path from 'path';
177c804472Sopenharmony_ciimport type { SourceFile } from 'typescript';
187c804472Sopenharmony_ciimport { SyntaxKind } from 'typescript';
197c804472Sopenharmony_ciimport { firstCharacterToUppercase } from '../common/commonUtils';
207c804472Sopenharmony_ciimport type { ClassEntity } from '../declaration-node/classDeclaration';
217c804472Sopenharmony_ciimport { generateCommonMethod } from './generateCommonMethod';
227c804472Sopenharmony_ciimport { getWarnConsole } from './generateCommonUtil';
237c804472Sopenharmony_ciimport { generatePropertyDeclaration } from './generatePropertyDeclaration';
247c804472Sopenharmony_ciimport { generateStaticFunction } from './generateStaticFunction';
257c804472Sopenharmony_ciimport { ImportElementEntity } from '../declaration-node/importAndExportDeclaration';
267c804472Sopenharmony_ciimport { HeritageClauseEntity } from '../declaration-node/heritageClauseDeclaration';
277c804472Sopenharmony_ci
287c804472Sopenharmony_ciinterface AssemblyClassParams {
297c804472Sopenharmony_ci  isSystem: boolean;
307c804472Sopenharmony_ci  classEntity: ClassEntity;
317c804472Sopenharmony_ci  classBody: string;
327c804472Sopenharmony_ci  sourceFile: SourceFile;
337c804472Sopenharmony_ci  mockApi: string;
347c804472Sopenharmony_ci  isInnerMockFunction: boolean;
357c804472Sopenharmony_ci  filename: string;
367c804472Sopenharmony_ci  isExtend: boolean;
377c804472Sopenharmony_ci  className: string;
387c804472Sopenharmony_ci  extraImport?: string[];
397c804472Sopenharmony_ci  importDeclarations?: ImportElementEntity[];
407c804472Sopenharmony_ci}
417c804472Sopenharmony_ci
427c804472Sopenharmony_ci/**
437c804472Sopenharmony_ci * generate class
447c804472Sopenharmony_ci * @param rootName
457c804472Sopenharmony_ci * @param classEntity
467c804472Sopenharmony_ci * @param isSystem
477c804472Sopenharmony_ci * @param globalName
487c804472Sopenharmony_ci * @param filename
497c804472Sopenharmony_ci * @param sourceFile
507c804472Sopenharmony_ci * @param isInnerMockFunction
517c804472Sopenharmony_ci * @returns
527c804472Sopenharmony_ci */
537c804472Sopenharmony_ciexport function generateClassDeclaration(
547c804472Sopenharmony_ci  rootName: string,
557c804472Sopenharmony_ci  classEntity: ClassEntity,
567c804472Sopenharmony_ci  isSystem: boolean,
577c804472Sopenharmony_ci  globalName: string,
587c804472Sopenharmony_ci  filename: string,
597c804472Sopenharmony_ci  sourceFile: SourceFile,
607c804472Sopenharmony_ci  isInnerMockFunction: boolean,
617c804472Sopenharmony_ci  mockApi: string,
627c804472Sopenharmony_ci  extraImport?: string[],
637c804472Sopenharmony_ci  importDeclarations?: ImportElementEntity[]
647c804472Sopenharmony_ci): string {
657c804472Sopenharmony_ci  if (isSystem) {
667c804472Sopenharmony_ci    return '';
677c804472Sopenharmony_ci  }
687c804472Sopenharmony_ci
697c804472Sopenharmony_ci  const className = firstCharacterToUppercase(classEntity.className);
707c804472Sopenharmony_ci  let classBody = '';
717c804472Sopenharmony_ci  if (
727c804472Sopenharmony_ci    (classEntity.exportModifiers.includes(SyntaxKind.ExportKeyword) ||
737c804472Sopenharmony_ci      classEntity.exportModifiers.includes(SyntaxKind.DeclareKeyword)) &&
747c804472Sopenharmony_ci    !isInnerMockFunction
757c804472Sopenharmony_ci  ) {
767c804472Sopenharmony_ci    classBody += `export const ${className} = class ${className} `;
777c804472Sopenharmony_ci  } else {
787c804472Sopenharmony_ci    classBody += `const ${className} = class ${className} `;
797c804472Sopenharmony_ci  }
807c804472Sopenharmony_ci
817c804472Sopenharmony_ci  const heritageClausesData = handleClassEntityHeritageClauses(rootName, classEntity, mockApi, sourceFile);
827c804472Sopenharmony_ci  const isExtend = heritageClausesData.isExtend;
837c804472Sopenharmony_ci  classBody = addCustomeClass(heritageClausesData, sourceFile, importDeclarations) + classBody;
847c804472Sopenharmony_ci  classBody += heritageClausesData.classBody;
857c804472Sopenharmony_ci  classBody = assemblyClassBody({
867c804472Sopenharmony_ci    isSystem,
877c804472Sopenharmony_ci    classEntity,
887c804472Sopenharmony_ci    classBody,
897c804472Sopenharmony_ci    className,
907c804472Sopenharmony_ci    isExtend,
917c804472Sopenharmony_ci    sourceFile,
927c804472Sopenharmony_ci    mockApi,
937c804472Sopenharmony_ci    isInnerMockFunction,
947c804472Sopenharmony_ci    filename,
957c804472Sopenharmony_ci    extraImport,
967c804472Sopenharmony_ci    importDeclarations
977c804472Sopenharmony_ci  });
987c804472Sopenharmony_ci  return classBody;
997c804472Sopenharmony_ci}
1007c804472Sopenharmony_ci
1017c804472Sopenharmony_ci/**
1027c804472Sopenharmony_ci * generate some class
1037c804472Sopenharmony_ci * @param porps
1047c804472Sopenharmony_ci * @returns
1057c804472Sopenharmony_ci */
1067c804472Sopenharmony_cifunction assemblyClassBody(porps: AssemblyClassParams): string {
1077c804472Sopenharmony_ci  if (!porps.isSystem) {
1087c804472Sopenharmony_ci    porps.classBody += '{';
1097c804472Sopenharmony_ci    if (porps.classEntity.classConstructor.length > 1) {
1107c804472Sopenharmony_ci      porps.classBody += 'constructor(...arg) { ';
1117c804472Sopenharmony_ci    } else {
1127c804472Sopenharmony_ci      porps.classBody += 'constructor() { ';
1137c804472Sopenharmony_ci    }
1147c804472Sopenharmony_ci    if (porps.isExtend) {
1157c804472Sopenharmony_ci      porps.classBody += 'super();\n';
1167c804472Sopenharmony_ci    }
1177c804472Sopenharmony_ci    const warnCon = getWarnConsole(porps.className, 'constructor');
1187c804472Sopenharmony_ci    porps.classBody += porps.sourceFile.fileName.endsWith('PermissionRequestResult.d.ts') ? '' : warnCon;
1197c804472Sopenharmony_ci  }
1207c804472Sopenharmony_ci  if (porps.classEntity.classProperty.length > 0) {
1217c804472Sopenharmony_ci    porps.classEntity.classProperty.forEach(value => {
1227c804472Sopenharmony_ci      porps.classBody +=
1237c804472Sopenharmony_ci        generatePropertyDeclaration(
1247c804472Sopenharmony_ci          porps.className,
1257c804472Sopenharmony_ci          value,
1267c804472Sopenharmony_ci          porps.sourceFile,
1277c804472Sopenharmony_ci          porps.extraImport,
1287c804472Sopenharmony_ci          porps.importDeclarations
1297c804472Sopenharmony_ci        ) + '\n';
1307c804472Sopenharmony_ci    });
1317c804472Sopenharmony_ci  }
1327c804472Sopenharmony_ci
1337c804472Sopenharmony_ci  if (porps.classEntity.classMethod.size > 0) {
1347c804472Sopenharmony_ci    porps.classEntity.classMethod.forEach(value => {
1357c804472Sopenharmony_ci      porps.classBody += generateCommonMethod(porps.className, value, porps.sourceFile, porps.mockApi);
1367c804472Sopenharmony_ci    });
1377c804472Sopenharmony_ci  }
1387c804472Sopenharmony_ci
1397c804472Sopenharmony_ci  porps.classBody += '}\n};';
1407c804472Sopenharmony_ci  porps.classBody = assemblyGlobal(porps);
1417c804472Sopenharmony_ci
1427c804472Sopenharmony_ci  if (!porps.filename.startsWith('system_')) {
1437c804472Sopenharmony_ci    if (porps.classEntity.staticMethods.length > 0) {
1447c804472Sopenharmony_ci      let staticMethodBody = '';
1457c804472Sopenharmony_ci      porps.classEntity.staticMethods.forEach(value => {
1467c804472Sopenharmony_ci        staticMethodBody += generateStaticFunction(value, false, porps.sourceFile, porps.mockApi) + '\n';
1477c804472Sopenharmony_ci      });
1487c804472Sopenharmony_ci      porps.classBody += staticMethodBody;
1497c804472Sopenharmony_ci    }
1507c804472Sopenharmony_ci  }
1517c804472Sopenharmony_ci  if (porps.classEntity.exportModifiers.includes(SyntaxKind.DefaultKeyword)) {
1527c804472Sopenharmony_ci    porps.classBody += `\nexport default ${porps.className};`;
1537c804472Sopenharmony_ci  }
1547c804472Sopenharmony_ci  return porps.classBody;
1557c804472Sopenharmony_ci}
1567c804472Sopenharmony_ci
1577c804472Sopenharmony_ci/**
1587c804472Sopenharmony_ci * generate some class
1597c804472Sopenharmony_ci * @param porps
1607c804472Sopenharmony_ci * @returns
1617c804472Sopenharmony_ci */
1627c804472Sopenharmony_cifunction assemblyGlobal(porps: AssemblyClassParams): string {
1637c804472Sopenharmony_ci  if (
1647c804472Sopenharmony_ci    (porps.classEntity.exportModifiers.includes(SyntaxKind.ExportKeyword) ||
1657c804472Sopenharmony_ci      porps.classEntity.exportModifiers.includes(SyntaxKind.DeclareKeyword)) &&
1667c804472Sopenharmony_ci    !porps.isInnerMockFunction
1677c804472Sopenharmony_ci  ) {
1687c804472Sopenharmony_ci    porps.classBody += `
1697c804472Sopenharmony_ci      if (!global.${porps.className}) {
1707c804472Sopenharmony_ci        global.${porps.className} = ${porps.className};\n
1717c804472Sopenharmony_ci      }
1727c804472Sopenharmony_ci    `;
1737c804472Sopenharmony_ci  }
1747c804472Sopenharmony_ci  return porps.classBody;
1757c804472Sopenharmony_ci}
1767c804472Sopenharmony_ci
1777c804472Sopenharmony_ci/**
1787c804472Sopenharmony_ci * generate class
1797c804472Sopenharmony_ci * @param rootName
1807c804472Sopenharmony_ci * @param classEntity
1817c804472Sopenharmony_ci * @returns
1827c804472Sopenharmony_ci */
1837c804472Sopenharmony_cifunction handleClassEntityHeritageClauses(
1847c804472Sopenharmony_ci  rootName: string,
1857c804472Sopenharmony_ci  classEntity: ClassEntity,
1867c804472Sopenharmony_ci  mockApi: string,
1877c804472Sopenharmony_ci  sourceFile: SourceFile
1887c804472Sopenharmony_ci): { isExtend: boolean; classBody: string } {
1897c804472Sopenharmony_ci  let isExtend = false;
1907c804472Sopenharmony_ci  let classBody = '';
1917c804472Sopenharmony_ci  if (classEntity.heritageClauses.length > 0) {
1927c804472Sopenharmony_ci    classEntity.heritageClauses.forEach(value => {
1937c804472Sopenharmony_ci      if (value.clauseToken === 'extends') {
1947c804472Sopenharmony_ci        isExtend = true;
1957c804472Sopenharmony_ci        classBody += `${value.clauseToken} `;
1967c804472Sopenharmony_ci        classBody = generateClassEntityHeritageClauses(classEntity, value, classBody, rootName, mockApi, sourceFile);
1977c804472Sopenharmony_ci      }
1987c804472Sopenharmony_ci    });
1997c804472Sopenharmony_ci  }
2007c804472Sopenharmony_ci  return {
2017c804472Sopenharmony_ci    isExtend,
2027c804472Sopenharmony_ci    classBody
2037c804472Sopenharmony_ci  };
2047c804472Sopenharmony_ci}
2057c804472Sopenharmony_ci
2067c804472Sopenharmony_ci/**
2077c804472Sopenharmony_ci * generate classEntity heritageClauses
2087c804472Sopenharmony_ci * @param classEntity
2097c804472Sopenharmony_ci * @param value
2107c804472Sopenharmony_ci * @param classBody
2117c804472Sopenharmony_ci * @param rootName
2127c804472Sopenharmony_ci * @param mockApi
2137c804472Sopenharmony_ci * @param sourceFile
2147c804472Sopenharmony_ci * @returns
2157c804472Sopenharmony_ci */
2167c804472Sopenharmony_cifunction generateClassEntityHeritageClauses(
2177c804472Sopenharmony_ci  classEntity: ClassEntity,
2187c804472Sopenharmony_ci  value: HeritageClauseEntity,
2197c804472Sopenharmony_ci  classBody: string,
2207c804472Sopenharmony_ci  rootName: string,
2217c804472Sopenharmony_ci  mockApi: string,
2227c804472Sopenharmony_ci  sourceFile: SourceFile
2237c804472Sopenharmony_ci): string {
2247c804472Sopenharmony_ci  value.types.forEach((val, index) => {
2257c804472Sopenharmony_ci    const extendClassName = val.trim().split('<')[0];
2267c804472Sopenharmony_ci    const moduleName = firstCharacterToUppercase(rootName);
2277c804472Sopenharmony_ci    if (val.startsWith('Array<')) {
2287c804472Sopenharmony_ci      val = 'Array';
2297c804472Sopenharmony_ci    } else {
2307c804472Sopenharmony_ci      if (classEntity.exportModifiers.includes(SyntaxKind.ExportKeyword) && rootName !== '') {
2317c804472Sopenharmony_ci        val = `mock${moduleName}().${val}`;
2327c804472Sopenharmony_ci      }
2337c804472Sopenharmony_ci    }
2347c804472Sopenharmony_ci    if (index !== value.types.length - 1) {
2357c804472Sopenharmony_ci      classBody += `${extendClassName},`;
2367c804472Sopenharmony_ci    } else if (val.includes('.')) {
2377c804472Sopenharmony_ci      const name = val.split('.')[0];
2387c804472Sopenharmony_ci      if (
2397c804472Sopenharmony_ci        mockApi.includes(`import { mock${firstCharacterToUppercase(name)} }`) &&
2407c804472Sopenharmony_ci        path.basename(sourceFile.fileName).startsWith('@ohos.')
2417c804472Sopenharmony_ci      ) {
2427c804472Sopenharmony_ci        classBody += val.replace(name, `mock${firstCharacterToUppercase(name)}()`);
2437c804472Sopenharmony_ci      } else {
2447c804472Sopenharmony_ci        classBody += `${extendClassName}`;
2457c804472Sopenharmony_ci      }
2467c804472Sopenharmony_ci    } else {
2477c804472Sopenharmony_ci      classBody += `${extendClassName}`;
2487c804472Sopenharmony_ci    }
2497c804472Sopenharmony_ci  });
2507c804472Sopenharmony_ci  return classBody;
2517c804472Sopenharmony_ci}
2527c804472Sopenharmony_ci
2537c804472Sopenharmony_ci/**
2547c804472Sopenharmony_ci * add custome class
2557c804472Sopenharmony_ci * @param heritageClausesData
2567c804472Sopenharmony_ci * @param sourceFile
2577c804472Sopenharmony_ci * @returns
2587c804472Sopenharmony_ci */
2597c804472Sopenharmony_cifunction addCustomeClass(
2607c804472Sopenharmony_ci  heritageClausesData: { isExtend: boolean; classBody: string },
2617c804472Sopenharmony_ci  sourceFile: SourceFile,
2627c804472Sopenharmony_ci  importDeclarations?: ImportElementEntity[]
2637c804472Sopenharmony_ci): string {
2647c804472Sopenharmony_ci  if (!heritageClausesData.isExtend) {
2657c804472Sopenharmony_ci    return '';
2667c804472Sopenharmony_ci  }
2677c804472Sopenharmony_ci  if (
2687c804472Sopenharmony_ci    !path.resolve(sourceFile.fileName).includes(path.join('@internal', 'component', 'ets')) &&
2697c804472Sopenharmony_ci    path.basename(sourceFile.fileName).startsWith('@ohos.')
2707c804472Sopenharmony_ci  ) {
2717c804472Sopenharmony_ci    return '';
2727c804472Sopenharmony_ci  }
2737c804472Sopenharmony_ci  let mockClassBody = '';
2747c804472Sopenharmony_ci  if (!heritageClausesData.classBody.startsWith('extends ')) {
2757c804472Sopenharmony_ci    return mockClassBody;
2767c804472Sopenharmony_ci  }
2777c804472Sopenharmony_ci  const classArr = heritageClausesData.classBody.split('extends');
2787c804472Sopenharmony_ci  const className = classArr[classArr.length - 1].trim();
2797c804472Sopenharmony_ci  if (className === 'extends') {
2807c804472Sopenharmony_ci    return mockClassBody;
2817c804472Sopenharmony_ci  }
2827c804472Sopenharmony_ci  const removeNoteRegx = /\/\*[\s\S]*?\*\//g;
2837c804472Sopenharmony_ci  const fileContent = sourceFile.getText().replace(removeNoteRegx, '');
2847c804472Sopenharmony_ci  let hasImportType = false;
2857c804472Sopenharmony_ci  if (importDeclarations) {
2867c804472Sopenharmony_ci    importDeclarations.forEach(element => {
2877c804472Sopenharmony_ci      if (element.importElements.includes(className)) {
2887c804472Sopenharmony_ci        hasImportType = true;
2897c804472Sopenharmony_ci      }
2907c804472Sopenharmony_ci    });
2917c804472Sopenharmony_ci  }
2927c804472Sopenharmony_ci  const regex = new RegExp(`\\sclass\\s*${className}\\s*(<|{|extends|implements)`);
2937c804472Sopenharmony_ci  const results = fileContent.match(regex);
2947c804472Sopenharmony_ci  if (!results && !hasImportType) {
2957c804472Sopenharmony_ci    mockClassBody = `export class ${className} {};\n`;
2967c804472Sopenharmony_ci  }
2977c804472Sopenharmony_ci  return mockClassBody;
2987c804472Sopenharmony_ci}
299