• 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 {
19  ScriptTarget,
20  SyntaxKind,
21  createSourceFile
22} from 'typescript';
23import type { SourceFile } from 'typescript';
24import {
25  collectAllLegalImports,
26  dtsFileList,
27  firstCharacterToUppercase,
28  getAllFileNameList,
29  getApiInputPath
30} from '../common/commonUtils';
31import type { ImportElementEntity } from '../declaration-node/importAndExportDeclaration';
32import { getDefaultExportClassDeclaration } from '../declaration-node/sourceFileElementsAssemply';
33import type { SourceFileEntity } from '../declaration-node/sourceFileElementsAssemply';
34import { generateClassDeclaration } from './generateClassDeclaration';
35import { generateEnumDeclaration } from './generateEnumDeclaration';
36import { addToIndexArray } from './generateIndex';
37
38import { generateInterfaceDeclaration } from './generateInterfaceDeclaration';
39import { generateModuleDeclaration } from './generateModuleDeclaration';
40import { generateStaticFunction } from './generateStaticFunction';
41import { addToSystemIndexArray } from './generateSystemIndex';
42import { generateTypeAliasDeclaration } from './generateTypeAlias';
43import { generateCommonFunction } from './generateCommonFunction';
44import {
45  needToAddBrace,
46  hasExportDefaultKeyword,
47  MockFunctionElementEntity,
48  ReturnDataParams,
49  needAddExtraClass
50} from './generateCommonUtil';
51
52/**
53 * generate mock file string
54 * @param rootName absolute path to the mock file to be generated
55 * @param sourceFileEntity all node information in the file
56 * @param sourceFile file Text Information
57 * @param fileName file name
58 * @returns file mock text
59 */
60export function generateSourceFileElements(
61  rootName: string,
62  sourceFileEntity: SourceFileEntity,
63  sourceFile: SourceFile,
64  fileName: string
65): string {
66  let mockApi = '';
67  let mockFunctionElements: Array<MockFunctionElementEntity> = [];
68  const dependsSourceFileList = collectReferenceFiles(sourceFile);
69  const heritageClausesArray = getCurrentApiHeritageArray(sourceFileEntity, sourceFile);
70  const extraImport = [];
71
72  mockApi += importDeclarationsGenerate(sourceFileEntity, sourceFile, fileName, heritageClausesArray, dependsSourceFileList);
73  const enumDeclarationsData = enumDeclarationsGenerate(sourceFileEntity, mockFunctionElements);
74  mockApi += enumDeclarationsData.mockData;
75  mockFunctionElements = enumDeclarationsData.mockFunctionElements;
76
77  const typeAliasDeclarationsData = typeAliasDeclarationsGenerate(sourceFileEntity, mockFunctionElements, sourceFile, extraImport, mockApi);
78  mockApi += typeAliasDeclarationsData.mockData;
79  mockFunctionElements = typeAliasDeclarationsData.mockFunctionElements;
80
81  const interfaceDeclarationsData = interfaceDeclarationsGenerate(sourceFileEntity, mockFunctionElements, sourceFile, extraImport, mockApi);
82  mockApi += interfaceDeclarationsData.mockData;
83  mockFunctionElements = interfaceDeclarationsData.mockFunctionElements;
84
85  const classDeclarationsData = classDeclarationsGenerate(sourceFileEntity, mockFunctionElements, sourceFile, mockApi, fileName);
86  mockApi += classDeclarationsData.mockData;
87  mockFunctionElements = classDeclarationsData.mockFunctionElements;
88
89  mockApi += moduleDeclarationsGenerate(sourceFileEntity, sourceFile, mockApi, fileName, extraImport);
90
91  mockApi += functionDeclarationsGenerate(sourceFileEntity, sourceFile, mockApi);
92
93  mockApi += otherDeclarationsGenerate(rootName, sourceFileEntity, mockFunctionElements, sourceFile, mockApi, fileName).mockData;
94
95  mockApi += handleExportDeclarations(sourceFileEntity);
96
97  mockApi = extraImport.join('') + mockApi;
98
99  mockApi = addExportDefaultExpression(mockApi);
100
101  return mockApi;
102}
103
104/**
105 * get import declarations generate
106 * @param sourceFileEntity all node information in the file
107 * @param sourceFile file Text Information
108 * @param fileName file name
109 * @param heritageClausesArray  heritage elements array data
110 * @param dependsSourceFileList reference Files data
111 * @returns string
112 */
113function importDeclarationsGenerate(
114  sourceFileEntity: SourceFileEntity,
115  sourceFile: SourceFile,
116  fileName: string,
117  heritageClausesArray: string[],
118  dependsSourceFileList: SourceFile[]
119): string {
120  let mockData = '';
121  if (needAddExtraClass.includes(`${fileName}.d.ts`)) {
122    mockData += 'import { CommonMethod } from \'./common\';\n';
123  }
124  if (sourceFileEntity.importDeclarations.length > 0) {
125    sourceFileEntity.importDeclarations.forEach(value => {
126      if (
127        sourceFile.fileName.endsWith('@ohos.arkui.UIContext.d.ts') &&
128        ['\'DatePickerDialogParam\'', '\'TimePickerDialogParam\'', '\'textPickerDialogParam\''].includes(value.importPath)
129      ) {
130        mockData += '';
131      } else {
132        mockData += generateImportDeclaration(value, fileName, heritageClausesArray, sourceFile.fileName, dependsSourceFileList);
133      }
134    });
135  }
136  return mockData;
137}
138
139/**
140 * get enum declarations generate
141 * @param sourceFileEntity all node information in the file
142 * @param mockFunctionElements all function element entity
143 * @returns ReturnDataParams
144 */
145function enumDeclarationsGenerate(
146  sourceFileEntity: SourceFileEntity,
147  mockFunctionElements: Array<MockFunctionElementEntity>
148): ReturnDataParams {
149  const data: ReturnDataParams = {
150    mockData: '',
151    mockFunctionElements: mockFunctionElements
152  };
153  if (sourceFileEntity.enumDeclarations.length > 0) {
154    sourceFileEntity.enumDeclarations.forEach(value => {
155      data.mockData += generateEnumDeclaration('', value) + '\n';
156      data.mockFunctionElements.push({ elementName: value.enumName, type: 'enum' });
157    });
158  }
159  return data;
160}
161
162/**
163 * get typeAlias declarations generate
164 * @param sourceFileEntity all node information in the file
165 * @param mockFunctionElements all function element entity
166 * @param sourceFile file Text Information
167 * @param extraImport extra import data
168 * @param mockApi file mock text
169 * @returns ReturnDataParams
170 */
171function typeAliasDeclarationsGenerate(
172  sourceFileEntity: SourceFileEntity,
173  mockFunctionElements: Array<MockFunctionElementEntity>,
174  sourceFile: SourceFile,
175  extraImport: string[],
176  mockApi: string
177): ReturnDataParams {
178  const data: ReturnDataParams = {
179    mockData: '',
180    mockFunctionElements: mockFunctionElements
181  };
182  if (sourceFileEntity.typeAliasDeclarations.length > 0) {
183    sourceFileEntity.typeAliasDeclarations.forEach(value => {
184      data.mockData += generateTypeAliasDeclaration(value, false, sourceFile, extraImport, mockApi) + '\n';
185      data.mockFunctionElements.push({ elementName: value.typeAliasName, type: 'typeAlias' });
186    });
187  }
188  return data;
189}
190
191/**
192 * get interface declarations generate
193 * @param sourceFileEntity all node information in the file
194 * @param mockFunctionElements all function element entity
195 * @param sourceFile file Text Information
196 * @param extraImport extra import data
197 * @param mockApi file mock text
198 * @returns ReturnDataParams
199 */
200function interfaceDeclarationsGenerate(
201  sourceFileEntity: SourceFileEntity,
202  mockFunctionElements: Array<MockFunctionElementEntity>,
203  sourceFile: SourceFile,
204  extraImport: string[],
205  mockApi: string
206): ReturnDataParams {
207  const data: ReturnDataParams = {
208    mockData: '',
209    mockFunctionElements: mockFunctionElements
210  };
211  if (sourceFileEntity.interfaceDeclarations.length > 0) {
212    sourceFileEntity.interfaceDeclarations.forEach(value => {
213      data.mockData += generateInterfaceDeclaration(
214        value, sourceFile, true, mockApi, sourceFileEntity.interfaceDeclarations,
215        sourceFileEntity.importDeclarations, extraImport
216      ) + '\n';
217      data.mockFunctionElements.push({ elementName: value.interfaceName, type: 'interface' });
218    });
219  }
220  return data;
221}
222
223/**
224 * get class declarations generate
225 * @param sourceFileEntity all node information in the file
226 * @param mockFunctionElements all function element entity
227 * @param sourceFile file Text Information
228 * @param mockApi file mock text
229 * @param fileName file name
230 * @returns ReturnDataParams
231 */
232function classDeclarationsGenerate(
233  sourceFileEntity: SourceFileEntity,
234  mockFunctionElements: Array<MockFunctionElementEntity>,
235  sourceFile: SourceFile,
236  mockApi: string,
237  fileName: string
238): ReturnDataParams {
239  const data: ReturnDataParams = {
240    mockData: '',
241    mockFunctionElements: mockFunctionElements
242  };
243  if (sourceFileEntity.classDeclarations.length > 0) {
244    sourceFileEntity.classDeclarations.forEach(value => {
245      if (!fileName.startsWith('system_') && !value.exportModifiers.includes(SyntaxKind.DefaultKeyword)) {
246        data.mockData += generateClassDeclaration('', value, false, '', fileName, sourceFile, false, mockApi) + '\n';
247        data.mockFunctionElements.push({ elementName: value.className, type: 'class' });
248      }
249    });
250  }
251  return data;
252}
253
254/**
255 * get module declarations generate
256 * @param sourceFileEntity all node information in the file
257 * @param sourceFile file Text Information
258 * @param mockApi file mock text
259 * @param fileName  file name
260 * @param extraImport  extra import data
261 * @returns string
262 */
263function moduleDeclarationsGenerate(
264  sourceFileEntity: SourceFileEntity,
265  sourceFile: SourceFile,
266  mockApi: string,
267  fileName: string,
268  extraImport: string[]
269): string {
270  let mockData = '';
271  if (sourceFileEntity.moduleDeclarations.length > 0) {
272    sourceFileEntity.moduleDeclarations.forEach(value => {
273      mockData += generateModuleDeclaration(value, sourceFile, fileName, mockApi, extraImport, sourceFileEntity.importDeclarations) + '\n';
274    });
275  }
276  return mockData;
277}
278
279/**
280 * get function declarations generate
281 * @param sourceFileEntity  all node information in the file
282 * @param sourceFile file Text Information
283 * @param mockApi file mock text
284 * @returns string
285 */
286function functionDeclarationsGenerate(
287  sourceFileEntity: SourceFileEntity,
288  sourceFile: SourceFile,
289  mockApi: string
290): string {
291  let mockData = '';
292  if (sourceFileEntity.functionDeclarations.size > 0) {
293    Array.from(sourceFileEntity.functionDeclarations.keys()).forEach(key => {
294      mockData += generateCommonFunction(key, sourceFileEntity.functionDeclarations.get(key), sourceFile, mockApi, true) + '\n';
295    });
296  }
297  return mockData;
298}
299
300/**
301 * get other declarations generate
302 * @param rootName  absolute path to the mock file to be generated
303 * @param sourceFileEntity  all node information in the file
304 * @param mockFunctionElements  all function element entity
305 * @param sourceFile  file Text Information
306 * @param mockApi  file mock text
307 * @param fileName file name
308 * @returns ReturnDataParams
309 */
310function otherDeclarationsGenerate(
311  rootName: string,
312  sourceFileEntity: SourceFileEntity,
313  mockFunctionElements: Array<MockFunctionElementEntity>,
314  sourceFile: SourceFile,
315  mockApi: string,
316  fileName: string
317): ReturnDataParams {
318  const data: ReturnDataParams = {
319    mockData: '',
320    mockFunctionElements: []
321  };
322  if (
323    sourceFileEntity.moduleDeclarations.length === 0 &&
324    (fileName.startsWith('ohos_') || fileName.startsWith('system_') || fileName.startsWith('webgl'))
325  ) {
326    const moduleDeclarationsData = handleModuleDeclarationsNotExist(rootName, fileName, sourceFile, mockApi, mockFunctionElements);
327    data.mockData = moduleDeclarationsData.mockData;
328    data.mockFunctionElements = moduleDeclarationsData.mockFunctionElements;
329  } else {
330    const defaultExportClass = getDefaultExportClassDeclaration(sourceFile);
331    if (defaultExportClass.length > 0) {
332      const mockNameArr = fileName.split('_');
333      const mockName = mockNameArr[mockNameArr.length - 1];
334      defaultExportClass.forEach(value => {
335        data.mockData += generateClassDeclaration(rootName, value, false, mockName, '', sourceFile, false, mockApi) + '\n';
336      });
337    }
338  }
339  return data;
340}
341
342/**
343 * handle Export Declarations
344 * @param sourceFileEntity all node information in the file
345 * @returns export text info
346 */
347function handleExportDeclarations(sourceFileEntity: SourceFileEntity): string {
348  let mockApi = '';
349  if (sourceFileEntity.exportDeclarations.length > 0) {
350    sourceFileEntity.exportDeclarations.forEach(value => {
351      if (value.includes('export type {')) {
352        return;
353      }
354      if (!value.includes('export {')) {
355        mockApi += `${value}\n`;
356      }
357    });
358  }
359  return mockApi;
360}
361
362/**
363 * add extra export default expression
364 * @param mockApi file mock text
365 * @returns export text info
366 */
367function addExportDefaultExpression(mockApi: string): string {
368  const paramIndex = 2;
369  const reg = /export\sconst\s.*\s=/g;
370  const regDefault = /export\sdefault\s/g;
371  const regFunc = /export\sfunction\s/g;
372  const results = mockApi.match(reg);
373  const resultDefaults = mockApi.match(regDefault);
374  const resultFuncs = mockApi.match(regFunc);
375  if (results && results.length === 1 && !resultDefaults && !resultFuncs) {
376    const arr = results[0].split(' ');
377    const moduleName = arr[arr.length - paramIndex];
378    mockApi += `\nexport default ${moduleName};`;
379  }
380  return mockApi;
381}
382
383/**
384 * generate import definition
385 * @param importEntity import entity data
386 * @param sourceFileName file name
387 * @param heritageClausesArray heritage elements array data
388 * @param currentFilePath current file path
389 * @param dependsSourceFileList reference Files data
390 * @returns string
391 */
392export function generateImportDeclaration(
393  importEntity: ImportElementEntity,
394  sourceFileName: string,
395  heritageClausesArray: string[],
396  currentFilePath: string,
397  dependsSourceFileList: SourceFile[]
398): string {
399  const importDeclaration = referenctImport2ModuleImport(importEntity, currentFilePath, dependsSourceFileList);
400  if (importDeclaration) {
401    return importDeclaration;
402  }
403
404  const importPathSplit = importEntity.importPath.split('/');
405
406  let importPath = importPathSplit.slice(0, -1).join('/') + '/';
407  importPath += getImportPathName(importPathSplit);
408
409  let importElements = generateImportElements(importEntity, heritageClausesArray);
410  if (importElements === '{ mockWantAgent }' && importPath.includes('ohos_app_ability_wantAgent')) {
411    importElements = '{ mockWantAgent as mockAbilityWantAgent }';
412  }
413  const testPath = importPath.replace(/"/g, '').replace(/'/g, '').split('/');
414  if (!getAllFileNameList().has(testPath[testPath.length - 1]) && testPath[testPath.length - 1] !== 'ohos_application_want') {
415    return '';
416  }
417
418  let tmpImportPath = importPath.replace(/'/g, '').replace(/"/g, '');
419  if (!tmpImportPath.startsWith('./') && !tmpImportPath.startsWith('../')) {
420    importPath = `'./${tmpImportPath}'`;
421  }
422  if (sourceFileName === 'tagSession' && tmpImportPath === './basic' || sourceFileName === 'notificationContent' &&
423    tmpImportPath === './ohos_multimedia_image') {
424    importPath = `'.${importPath.replace(/'/g, '')}'`;
425  }
426
427  if (sourceFileName === 'AbilityContext' && tmpImportPath === '../ohos_application_Ability' ||
428    sourceFileName === 'Context' && tmpImportPath === './ApplicationContext') {
429    return '';
430  }
431  if (!importElements.includes('{') && !importElements.includes('}') && needToAddBrace.includes(importElements)) {
432    importElements = `{ ${importElements} }`;
433  }
434  collectAllLegalImports(importElements);
435  return `import ${importElements} from ${importPath}\n`;
436}
437
438/**
439 * handle module declarations does it exist
440 * @param rootName absolute path to the mock file to be generated
441 * @param fileName file name
442 * @param sourceFile file Text Information
443 * @param mockApi file mock text
444 * @param mockFunctionElements all function element entity
445 * @returns ReturnDataParams
446 */
447function handleModuleDeclarationsNotExist(
448  rootName: string, fileName: string, sourceFile: SourceFile, mockApi: string, mockFunctionElements: Array<MockFunctionElementEntity>
449): ReturnDataParams {
450  const data: ReturnDataParams = {
451    mockData: '',
452    mockFunctionElements: mockFunctionElements
453  };
454  const mockNameArr = fileName.split('_');
455  const mockName = mockNameArr[mockNameArr.length - 1];
456  const defaultExportClass = getDefaultExportClassDeclaration(sourceFile);
457  defaultExportClass.forEach(value => {
458    data.mockData += generateClassDeclaration(rootName, value, false, mockName, '', sourceFile, false, mockApi) + '\n';
459    data.mockFunctionElements.push({ elementName: value.className, type: 'class' });
460  });
461  data.mockData += `export function mock${firstCharacterToUppercase(mockName)}() {\n`;
462  if (fileName.startsWith('system_')) {
463    addToSystemIndexArray({
464      filename: fileName,
465      mockFunctionName: `mock${firstCharacterToUppercase(mockName)}`
466    });
467    data.mockData += `global.systemplugin.${mockName} = {`;
468    const defaultClass = getDefaultExportClassDeclaration(sourceFile);
469    let staticMethodBody = '';
470    defaultClass.forEach(value => {
471      value.staticMethods.forEach(val => {
472        staticMethodBody += generateStaticFunction(val, true, sourceFile, mockApi);
473      });
474    });
475    data.mockData += staticMethodBody;
476    data.mockData += '}';
477  } else {
478    if (!fileName.startsWith('webgl')) {
479      addToIndexArray({ fileName: fileName, mockFunctionName: `mock${firstCharacterToUppercase(mockName)}` });
480    }
481  }
482  data.mockData += `\nconst mockModule${firstCharacterToUppercase(mockName)} = {`;
483  data.mockFunctionElements.forEach(val => {
484    data.mockData += `${val.elementName}: ${val.elementName},`;
485  });
486  data.mockData += '}\n';
487  const isHaveExportDefault = hasExportDefaultKeyword(mockName, sourceFile);
488  const mockNameUppercase = firstCharacterToUppercase(mockName);
489  data.mockData +=
490    isHaveExportDefault ? `return mockModule${mockNameUppercase}\n` : `return mockModule${mockNameUppercase}.${mockNameUppercase}\n`;
491  data.mockData += '}';
492  return data;
493}
494
495/**
496 * adapter default export
497 * @param importName
498 * @returns boolean
499 */
500function checIsDefaultExportClass(importName: string): boolean {
501  const defaultExportClass = ['Context', 'BaseContext', 'ExtensionContext', 'ApplicationContext',
502    'ExtensionAbility', 'Ability', 'UIExtensionAbility', 'UIExtensionContext'];
503  return defaultExportClass.includes(importName);
504}
505
506/**
507 * get heritage elements
508 * @param sourceFileEntity all node information in the file
509 * @param sourceFile file Text Information
510 * @returns string[]
511 */
512function getCurrentApiHeritageArray(sourceFileEntity: SourceFileEntity, sourceFile: SourceFile): string[] {
513  const heritageClausesArray = [];
514  const defaultClassArray = getDefaultExportClassDeclaration(sourceFile);
515  sourceFileEntity.classDeclarations.forEach(value => {
516    value.heritageClauses.forEach(val => {
517      val.types.forEach(v => {
518        heritageClausesArray.push(v);
519      });
520    });
521  });
522  defaultClassArray.forEach(value => {
523    value.heritageClauses.forEach(val => {
524      val.types.forEach(v => {
525        heritageClausesArray.push(v);
526      });
527    });
528  });
529  return heritageClausesArray;
530}
531
532/**
533 * collect reference Files
534 * @param sourceFile file Text Information
535 * @returns SourceFile[]
536 */
537function collectReferenceFiles(sourceFile: SourceFile): SourceFile[] {
538  const referenceElementTemplate = /\/\/\/\s*<reference\s+path="[^'"\[\]]+/g;
539  const referenceFiles: SourceFile[] = [];
540  const text = sourceFile.text;
541  const referenceElement = text.match(referenceElementTemplate);
542
543  referenceElement && referenceElement.forEach(element => {
544    const referenceRelatePath = element.split(/path=["']/g)[1];
545    const realReferenceFilePath = contentRelatePath2RealRelatePath(sourceFile.fileName, referenceRelatePath);
546    if (!realReferenceFilePath) {
547      return;
548    }
549
550    if (!fs.existsSync(realReferenceFilePath)) {
551      console.error(`Can not resolve file: ${realReferenceFilePath}`);
552      return;
553    }
554    const code = fs.readFileSync(realReferenceFilePath);
555    referenceFiles.push(createSourceFile(realReferenceFilePath, code.toString(), ScriptTarget.Latest));
556    !dtsFileList.includes(realReferenceFilePath) && dtsFileList.push(realReferenceFilePath);
557  });
558  return referenceFiles;
559}
560
561/**
562 * content relatePath to real relatePath
563 * @param currentFilePath file name
564 * @param contentReferenceRelatePath reference relate Path
565 * @returns string
566 */
567function contentRelatePath2RealRelatePath(currentFilePath: string, contentReferenceRelatePath: string): string {
568  const conmponentSourceFileTemplate = /component\/[^'"\/]+\.d\.ts/;
569  const currentFolderSourceFileTemplate = /\.\/[^\/]+\.d\.ts/;
570  const baseFileNameTemplate = /[^\/]+\.d\.ts/;
571
572  let realReferenceFilePath: string;
573  if (conmponentSourceFileTemplate.test(contentReferenceRelatePath)) {
574    const newRelateReferencePath = contentReferenceRelatePath.match(conmponentSourceFileTemplate)[0];
575    const referenceFileName = path.basename(newRelateReferencePath);
576    realReferenceFilePath = path.join(getApiInputPath(), '@internal', 'component', 'ets', referenceFileName);
577  } else if (currentFolderSourceFileTemplate.test(contentReferenceRelatePath)) {
578    const referenceFileName = path.basename(contentReferenceRelatePath);
579    realReferenceFilePath = currentFilePath.replace(baseFileNameTemplate, referenceFileName).replace(/\//g, path.sep);
580  } else {
581    console.error(`Can not find reference ${contentReferenceRelatePath} from ${currentFilePath}`);
582    return '';
583  }
584  return realReferenceFilePath;
585}
586
587/**
588 * referenct import to module import
589 * @param importEntity import entity data
590 * @param currentFilePath current file path data
591 * @param dependsSourceFileList reference Files data
592 * @returns string
593 */
594export function referenctImport2ModuleImport(
595  importEntity: ImportElementEntity,
596  currentFilePath: string,
597  dependsSourceFileList: SourceFile[]
598): string {
599  if (dependsSourceFileList.length && !importEntity.importPath.includes('.')) {
600    for (let i = 0; i < dependsSourceFileList.length; i++) {
601      if (dependsSourceFileList[i].text.includes(`declare module ${importEntity.importPath.replace(/'/g, '"')}`)) {
602        let relatePath = path.relative(path.dirname(currentFilePath), dependsSourceFileList[i].fileName)
603          .replace(/\\/g, '/')
604          .replace(/.d.ts/g, '')
605          .replace(/.d.es/g, '');
606        relatePath = (relatePath.startsWith('@internal/component') ? './' : '') + relatePath;
607        return `import ${importEntity.importElements} from "${relatePath}"\n`;
608      }
609    }
610  }
611  return '';
612}
613
614/**
615 * get import pathName
616 * @param importPathSplit import path split to array data
617 * @returns string
618 */
619function getImportPathName(importPathSplit: string[]): string {
620  let importPathName: string;
621  let fileName = importPathSplit[importPathSplit.length - 1];
622  if (fileName.endsWith('.d.ts') || fileName.endsWith('.d.ets')) {
623    fileName = fileName.split(/\.d\.e?ts/)[0];
624  }
625  if (fileName.includes('@')) {
626    importPathName = fileName.replace('@', '').replace(/\./g, '_');
627  } else {
628    importPathName = fileName.replace(/\./g, '_');
629  }
630  return importPathName;
631}
632
633/**
634 * get import pathName
635 * @param importEntity import entity data
636 * @param heritageClausesArray heritage elements array data
637 * @returns string
638 */
639function generateImportElements(importEntity: ImportElementEntity, heritageClausesArray: string[]): string {
640  let importElements = importEntity.importElements;
641  if (
642    !importElements.includes('{') &&
643    !importElements.includes('* as') &&
644    !heritageClausesArray.includes(importElements) &&
645    importEntity.importPath.includes('@ohos')
646  ) {
647    const tmpArr = importEntity.importPath.split('.');
648    const mockModuleName = firstCharacterToUppercase(tmpArr[tmpArr.length - 1].replace('"', '').replace('\'', ''));
649    if (importElements === 'observer' && importEntity.importPath.includes('@ohos.arkui.observer')) {
650      return `{ mockUiObserver as ${importElements}}`;
651    }
652    importElements = `{ mock${mockModuleName} }`;
653  } else {
654    // adapt no rules .d.ts
655    if (importElements.trim() === 'AccessibilityExtensionContext, { AccessibilityElement }') {
656      importElements = '{ AccessibilityExtensionContext, AccessibilityElement }';
657    } else if (importElements.trim() === '{ image }') {
658      importElements = '{ mockImage as image }';
659    }
660  }
661  return importElements;
662}
663