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