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