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 { ScriptTarget, SyntaxKind, createSourceFile } from 'typescript'; 19import type { SourceFile } from 'typescript'; 20import { 21 collectAllLegalImports, 22 dtsFileList, 23 firstCharacterToUppercase, 24 getAllFileNameList, 25 getApiInputPath 26} from '../common/commonUtils'; 27import type { ImportElementEntity } from '../declaration-node/importAndExportDeclaration'; 28import { getDefaultExportClassDeclaration } from '../declaration-node/sourceFileElementsAssemply'; 29import type { SourceFileEntity } from '../declaration-node/sourceFileElementsAssemply'; 30import { generateClassDeclaration } from './generateClassDeclaration'; 31import { generateEnumDeclaration } from './generateEnumDeclaration'; 32import { addToIndexArray } from './generateIndex'; 33 34import { generateInterfaceDeclaration } from './generateInterfaceDeclaration'; 35import { generateModuleDeclaration } from './generateModuleDeclaration'; 36import { generateStaticFunction } from './generateStaticFunction'; 37import { addToSystemIndexArray } from './generateSystemIndex'; 38import { generateTypeAliasDeclaration } from './generateTypeAlias'; 39import { generateCommonFunction } from './generateCommonFunction'; 40import { 41 needToAddBrace, 42 hasExportDefaultKeyword, 43 MockFunctionElementEntity, 44 ReturnDataParams 45} from './generateCommonUtil'; 46import { handleImportKit } from '../common/kitUtils'; 47 48/** 49 * generate mock file string 50 * @param rootName absolute path to the mock file to be generated 51 * @param sourceFileEntity all node information in the file 52 * @param sourceFile file Text Information 53 * @param fileName file name 54 * @returns file mock text 55 */ 56export function generateSourceFileElements( 57 rootName: string, 58 sourceFileEntity: SourceFileEntity, 59 sourceFile: SourceFile, 60 fileName: string 61): string { 62 let mockApi = ''; 63 let mockFunctionElements: Array<MockFunctionElementEntity> = []; 64 const dependsSourceFileList = collectReferenceFiles(sourceFile); 65 const heritageClausesArray = getCurrentApiHeritageArray(sourceFileEntity, sourceFile); 66 const extraImport = []; 67 68 mockApi += importDeclarationsGenerate(sourceFileEntity, sourceFile, fileName, heritageClausesArray, dependsSourceFileList); 69 const enumDeclarationsData = enumDeclarationsGenerate(sourceFileEntity, mockFunctionElements); 70 mockApi += enumDeclarationsData.mockData; 71 mockFunctionElements = enumDeclarationsData.mockFunctionElements; 72 73 const typeAliasDeclarationsData = typeAliasDeclarationsGenerate(sourceFileEntity, mockFunctionElements, sourceFile, extraImport, mockApi); 74 mockApi += typeAliasDeclarationsData.mockData; 75 mockFunctionElements = typeAliasDeclarationsData.mockFunctionElements; 76 77 const interfaceDeclarationsData = interfaceDeclarationsGenerate(sourceFileEntity, mockFunctionElements, sourceFile, extraImport, mockApi); 78 mockApi += interfaceDeclarationsData.mockData; 79 mockFunctionElements = interfaceDeclarationsData.mockFunctionElements; 80 81 const classDeclarationsData = classDeclarationsGenerate(sourceFileEntity, mockFunctionElements, sourceFile, mockApi, fileName); 82 mockApi += classDeclarationsData.mockData; 83 mockFunctionElements = classDeclarationsData.mockFunctionElements; 84 85 mockApi += moduleDeclarationsGenerate(sourceFileEntity, sourceFile, mockApi, fileName, extraImport); 86 87 mockApi += functionDeclarationsGenerate(sourceFileEntity, sourceFile, mockApi); 88 89 mockApi += otherDeclarationsGenerate(rootName, sourceFileEntity, mockFunctionElements, sourceFile, mockApi, fileName, extraImport).mockData; 90 91 mockApi += handleExportDeclarations(sourceFileEntity); 92 93 mockApi = extraImport.join('') + mockApi; 94 95 mockApi = addExportDefaultExpression(mockApi); 96 97 return mockApi; 98} 99 100/** 101 * get import declarations generate 102 * @param sourceFileEntity all node information in the file 103 * @param sourceFile file Text Information 104 * @param fileName file name 105 * @param heritageClausesArray heritage elements array data 106 * @param dependsSourceFileList reference Files data 107 * @returns string 108 */ 109function importDeclarationsGenerate( 110 sourceFileEntity: SourceFileEntity, 111 sourceFile: SourceFile, 112 fileName: string, 113 heritageClausesArray: string[], 114 dependsSourceFileList: SourceFile[] 115): string { 116 let mockData = ''; 117 if (sourceFileEntity.importDeclarations.length > 0) { 118 sourceFileEntity.importDeclarations.forEach(value => { 119 if ( 120 sourceFile.fileName.endsWith('@ohos.arkui.UIContext.d.ts') && 121 ['\'DatePickerDialogParam\'', '\'TimePickerDialogParam\'', 122 '\'textPickerDialogParam\'', '\'./@ohos.app.ability.common\''].includes(value.importPath) 123 ) { 124 mockData += ''; 125 } else { 126 mockData += generateImportDeclaration(value, fileName, heritageClausesArray, sourceFile.fileName, dependsSourceFileList); 127 } 128 }); 129 } 130 if (fileName === 'ohos_arkui_observer') { 131 mockData += 'const NavigationOperation = { PUSH: 1, POP: 2, REPLACE: 3 }\n'; 132 } 133 if (fileName === 'navigation') { 134 mockData += 'const TextModifier = {}\n'; 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 Additional exported data 197 * @param mockApi file mock into text 198 * @returns ReturnDataParams 199 */ 200function interfaceDeclarationsGenerate( 201 entity: 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 (entity.interfaceDeclarations.length > 0) { 212 entity.interfaceDeclarations.forEach(value => { 213 data.mockData += generateInterfaceDeclaration( 214 value, sourceFile, true, mockApi, entity.interfaceDeclarations, 215 entity.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 += 274 generateModuleDeclaration( 275 value, 276 sourceFile, 277 fileName, 278 mockApi, 279 extraImport, 280 sourceFileEntity.importDeclarations 281 ) + '\n'; 282 }); 283 } 284 return mockData; 285} 286 287/** 288 * get function declarations generate 289 * @param sourceFileEntity all node information in the file 290 * @param sourceFile file Text Information 291 * @param mockApi file mock text 292 * @returns string 293 */ 294function functionDeclarationsGenerate( 295 sourceFileEntity: SourceFileEntity, 296 sourceFile: SourceFile, 297 mockApi: string 298): string { 299 let mockData = ''; 300 if (sourceFileEntity.functionDeclarations.size > 0) { 301 Array.from(sourceFileEntity.functionDeclarations.keys()).forEach(key => { 302 mockData += generateCommonFunction(key, sourceFileEntity.functionDeclarations.get(key), sourceFile, mockApi, true) + '\n'; 303 }); 304 } 305 return mockData; 306} 307 308/** 309 * get other declarations generate 310 * @param rootName absolute path to the mock file to be generated 311 * @param sourceFileEntity all node information in the file 312 * @param mockFunctionElements all function element entity 313 * @param sourceFile file Text Information 314 * @param mockApi file mock text 315 * @param fileName file name 316 * @returns ReturnDataParams 317 */ 318function otherDeclarationsGenerate( 319 rootName: string, 320 sourceFileEntity: SourceFileEntity, 321 mockFunctionElements: Array<MockFunctionElementEntity>, 322 sourceFile: SourceFile, 323 mockApi: string, 324 fileName: string, 325 extraImport: string[] 326): ReturnDataParams { 327 const data: ReturnDataParams = { 328 mockData: '', 329 mockFunctionElements: [] 330 }; 331 if ( 332 sourceFileEntity.moduleDeclarations.length === 0 && 333 (fileName.startsWith('ohos_') || fileName.startsWith('system_') || fileName.startsWith('webgl')) 334 ) { 335 const moduleDeclarationsData = handleModuleDeclarationsNotExist( 336 rootName, 337 fileName, 338 sourceFile, 339 mockApi, 340 mockFunctionElements 341 ); 342 data.mockData = moduleDeclarationsData.mockData; 343 data.mockFunctionElements = moduleDeclarationsData.mockFunctionElements; 344 } else { 345 const defaultExportClass = getDefaultExportClassDeclaration(sourceFile); 346 if (defaultExportClass.length > 0) { 347 const mockNameArr = fileName.split('_'); 348 const mockName = mockNameArr[mockNameArr.length - 1]; 349 defaultExportClass.forEach(value => { 350 data.mockData += 351 generateClassDeclaration( 352 rootName, 353 value, 354 false, 355 mockName, 356 '', 357 sourceFile, 358 false, 359 mockApi, 360 extraImport, 361 sourceFileEntity.importDeclarations 362 ) + '\n'; 363 }); 364 } 365 } 366 return data; 367} 368 369/** 370 * handle Export Declarations 371 * @param sourceFileEntity all node information in the file 372 * @returns export text info 373 */ 374function handleExportDeclarations(sourceFileEntity: SourceFileEntity): string { 375 let mockApi = ''; 376 if (sourceFileEntity.exportDeclarations.length > 0) { 377 sourceFileEntity.exportDeclarations.forEach(value => { 378 const removeNoteRegx = /\/\*[\s\S]*?\*\//g; 379 const flieText = value.replace(removeNoteRegx, '').replace(/\n/g, ''); 380 if (flieText.includes('export type {')) { 381 return; 382 } 383 if (flieText.includes('export {') && value.includes(' from ')) { 384 mockApi += `${flieText}\n`; 385 } 386 if (flieText.includes('export *')) { 387 mockApi += `${flieText}\n`; 388 } 389 }); 390 } 391 return mockApi; 392} 393 394/** 395 * add extra export default expression 396 * @param mockApi file mock text 397 * @returns export text info 398 */ 399function addExportDefaultExpression(mockApi: string): string { 400 const paramIndex = 2; 401 const reg = /export\sconst\s.*\s=/g; 402 const regDefault = /export\sdefault\s/g; 403 const regFunc = /export\sfunction\s/g; 404 const results = mockApi.match(reg); 405 const resultDefaults = mockApi.match(regDefault); 406 const resultFuncs = mockApi.match(regFunc); 407 if (results && results.length === 1 && !resultDefaults && !resultFuncs) { 408 const arr = results[0].split(' '); 409 const moduleName = arr[arr.length - paramIndex]; 410 mockApi += `\nexport default ${moduleName};`; 411 } 412 return mockApi; 413} 414 415/** 416 * generate import definition 417 * @param importEntity import entity data 418 * @param sourceFileName file name 419 * @param heritageClausesArray heritage elements array data 420 * @param currentFilePath current file path 421 * @param dependsSourceFileList reference Files data 422 * @returns string 423 */ 424export function generateImportDeclaration( 425 importEntity: ImportElementEntity, 426 sourceFileName: string, 427 heritageClausesArray: string[], 428 currentFilePath: string, 429 dependsSourceFileList: SourceFile[] 430): string { 431 const importEntities = handleImportKit(importEntity); 432 if (importEntities.length) { 433 return importEntities 434 .map(entity => 435 generateImportDeclaration(entity, sourceFileName, heritageClausesArray, currentFilePath, dependsSourceFileList) 436 ) 437 .join('\n'); 438 } 439 440 const importDeclaration = referenctImport2ModuleImport(importEntity, currentFilePath, dependsSourceFileList); 441 if (importDeclaration) { 442 return importDeclaration; 443 } 444 445 const importPathSplit = importEntity.importPath.split('/'); 446 447 let importPath = importPathSplit.slice(0, -1).join('/') + '/'; 448 importPath += getImportPathName(importPathSplit); 449 450 let importElements = generateImportElements(importEntity, heritageClausesArray); 451 if (importElements === '{ mockWantAgent }' && importPath.includes('ohos_app_ability_wantAgent')) { 452 importElements = '{ mockWantAgent as mockAbilityWantAgent }'; 453 } 454 const testPath = importPath.replace(/"/g, '').replace(/'/g, '').split('/'); 455 if (!getAllFileNameList().has(testPath[testPath.length - 1]) && testPath[testPath.length - 1] !== 'ohos_application_want') { 456 return ''; 457 } 458 459 const tmpImportPath = importPath.replace(/["']/g, ''); 460 if (!tmpImportPath.startsWith('./') && !tmpImportPath.startsWith('../')) { 461 importPath = `'./${tmpImportPath}'`; 462 } 463 if (sourceFileName === 'tagSession' && tmpImportPath === './basic' || sourceFileName === 'notificationContent' && 464 tmpImportPath === './ohos_multimedia_image') { 465 importPath = `'.${importPath.replace(/'/g, '')}'`; 466 } 467 468 if (sourceFileName === 'AbilityContext' && tmpImportPath === '../ohos_application_Ability') { 469 return ''; 470 } 471 if (sourceFileName === 'Context' && tmpImportPath === './ApplicationContext') { 472 return 'import { mockEnvironmentCallback } from \'../ohos_app_ability_EnvironmentCallback\'\n'; 473 } 474 if (!importElements.includes('{') && !importElements.includes('}') && needToAddBrace.includes(importElements)) { 475 importElements = `{ ${importElements} }`; 476 } 477 collectAllLegalImports(importElements); 478 return `import ${importElements} from ${importPath}\n`; 479} 480 481/** 482 * handle module declarations does it exist 483 * @param rootName absolute path to the mock file to be generated 484 * @param fileName file name 485 * @param sourceFile file Text Information 486 * @param mockApi file mock text 487 * @param mockFunctionElements all function element entity 488 * @returns ReturnDataParams 489 */ 490function handleModuleDeclarationsNotExist( 491 rootName: string, 492 fileName: string, 493 sourceFile: SourceFile, 494 mockApi: string, 495 mockFunctionElements: Array<MockFunctionElementEntity> 496): ReturnDataParams { 497 const data: ReturnDataParams = { 498 mockData: '', 499 mockFunctionElements: mockFunctionElements 500 }; 501 const mockNameArr = fileName.split('_'); 502 const mockName = mockNameArr[mockNameArr.length - 1]; 503 const defaultExportClass = getDefaultExportClassDeclaration(sourceFile); 504 defaultExportClass.forEach(value => { 505 data.mockData += generateClassDeclaration(rootName, value, false, mockName, '', sourceFile, false, mockApi) + '\n'; 506 data.mockFunctionElements.push({ elementName: value.className, type: 'class' }); 507 }); 508 data.mockData += `export function mock${firstCharacterToUppercase(mockName)}() {\n`; 509 if (fileName.startsWith('system_')) { 510 addToSystemIndexArray({ 511 filename: fileName, 512 mockFunctionName: `mock${firstCharacterToUppercase(mockName)}` 513 }); 514 data.mockData += `global.systemplugin.${mockName} = {`; 515 const defaultClass = getDefaultExportClassDeclaration(sourceFile); 516 let staticMethodBody = ''; 517 defaultClass.forEach(value => { 518 value.staticMethods.forEach(val => { 519 staticMethodBody += generateStaticFunction(val, true, sourceFile, mockApi); 520 }); 521 }); 522 data.mockData += staticMethodBody; 523 data.mockData += '}'; 524 } else { 525 if (!fileName.startsWith('webgl')) { 526 addToIndexArray({ fileName: fileName, mockFunctionName: `mock${firstCharacterToUppercase(mockName)}` }); 527 } 528 } 529 data.mockData += `\nconst mockModule${firstCharacterToUppercase(mockName)} = {`; 530 data.mockFunctionElements.forEach(val => { 531 data.mockData += `${val.elementName}: ${val.elementName},`; 532 }); 533 data.mockData += '}\n'; 534 const isHaveExportDefault = hasExportDefaultKeyword(mockName, sourceFile); 535 const mockNameUppercase = firstCharacterToUppercase(mockName); 536 data.mockData += isHaveExportDefault 537 ? `return mockModule${mockNameUppercase}\n` 538 : `return mockModule${mockNameUppercase}.${mockNameUppercase}\n`; 539 data.mockData += '}'; 540 return data; 541} 542 543/** 544 * adapter default export 545 * @param importName 546 * @returns boolean 547 */ 548function checIsDefaultExportClass(importName: string): boolean { 549 const defaultExportClass = [ 550 'Context', 551 'BaseContext', 552 'ExtensionContext', 553 'ApplicationContext', 554 'ExtensionAbility', 555 'Ability', 556 'UIExtensionAbility', 557 'UIExtensionContext' 558 ]; 559 return defaultExportClass.includes(importName); 560} 561 562/** 563 * get heritage elements 564 * @param sourceFileEntity all node information in the file 565 * @param sourceFile file Text Information 566 * @returns string[] 567 */ 568function getCurrentApiHeritageArray(sourceFileEntity: SourceFileEntity, sourceFile: SourceFile): string[] { 569 const heritageClausesArray = []; 570 const defaultClassArray = getDefaultExportClassDeclaration(sourceFile); 571 sourceFileEntity.classDeclarations.forEach(value => { 572 value.heritageClauses.forEach(val => { 573 val.types.forEach(v => { 574 heritageClausesArray.push(v); 575 }); 576 }); 577 }); 578 defaultClassArray.forEach(value => { 579 value.heritageClauses.forEach(val => { 580 val.types.forEach(v => { 581 heritageClausesArray.push(v); 582 }); 583 }); 584 }); 585 return heritageClausesArray; 586} 587 588/** 589 * collect reference Files 590 * @param sourceFile file Text Information 591 * @returns SourceFile[] 592 */ 593function collectReferenceFiles(sourceFile: SourceFile): SourceFile[] { 594 const referenceElementTemplate = /\/\/\/\s*<reference\s+path="[^'"\[\]]+/g; 595 const referenceFiles: SourceFile[] = []; 596 const text = sourceFile.text; 597 const referenceElement = text.match(referenceElementTemplate); 598 599 referenceElement && 600 referenceElement.forEach(element => { 601 const referenceRelatePath = element.split(/path=["']/g)[1]; 602 const realReferenceFilePath = contentRelatePath2RealRelatePath(sourceFile.fileName, referenceRelatePath); 603 if (!realReferenceFilePath) { 604 return; 605 } 606 607 if (!fs.existsSync(realReferenceFilePath)) { 608 console.error(`Can not resolve file: ${realReferenceFilePath}`); 609 return; 610 } 611 const code = fs.readFileSync(realReferenceFilePath); 612 referenceFiles.push(createSourceFile(realReferenceFilePath, code.toString(), ScriptTarget.Latest)); 613 !dtsFileList.includes(realReferenceFilePath) && dtsFileList.push(realReferenceFilePath); 614 }); 615 return referenceFiles; 616} 617 618/** 619 * content relatePath to real relatePath 620 * @param currentFilePath file name 621 * @param contentReferenceRelatePath reference relate Path 622 * @returns string 623 */ 624function contentRelatePath2RealRelatePath(currentFilePath: string, contentReferenceRelatePath: string): string { 625 const conmponentSourceFileTemplate = /component\/[^'"\/]+\.d\.ts/; 626 const currentFolderSourceFileTemplate = /\.\/[^\/]+\.d\.ts/; 627 const baseFileNameTemplate = /[^\/]+\.d\.ts/; 628 629 let realReferenceFilePath: string; 630 if (conmponentSourceFileTemplate.test(contentReferenceRelatePath)) { 631 const newRelateReferencePath = contentReferenceRelatePath.match(conmponentSourceFileTemplate)[0]; 632 const referenceFileName = path.basename(newRelateReferencePath); 633 realReferenceFilePath = path.join(getApiInputPath(), '@internal', 'component', 'ets', referenceFileName); 634 } else if (currentFolderSourceFileTemplate.test(contentReferenceRelatePath)) { 635 const referenceFileName = path.basename(contentReferenceRelatePath); 636 realReferenceFilePath = currentFilePath.replace(baseFileNameTemplate, referenceFileName).replace(/\//g, path.sep); 637 } else { 638 console.error(`Can not find reference ${contentReferenceRelatePath} from ${currentFilePath}`); 639 return ''; 640 } 641 return realReferenceFilePath; 642} 643 644/** 645 * referenct import to module import 646 * @param importEntity import entity data 647 * @param currentFilePath current file path data 648 * @param dependsSourceFileList reference Files data 649 * @returns string 650 */ 651export function referenctImport2ModuleImport( 652 importEntity: ImportElementEntity, 653 currentFilePath: string, 654 dependsSourceFileList: SourceFile[] 655): string { 656 if (dependsSourceFileList.length && !importEntity.importPath.includes('.')) { 657 for (let i = 0; i < dependsSourceFileList.length; i++) { 658 if (dependsSourceFileList[i].text.includes(`declare module ${importEntity.importPath.replace(/'/g, '"')}`)) { 659 let relatePath = path 660 .relative(path.dirname(currentFilePath), dependsSourceFileList[i].fileName) 661 .replace(/\\/g, '/') 662 .replace(/.d.ts/g, '') 663 .replace(/.d.ets/g, ''); 664 relatePath = (relatePath.startsWith('@internal/component') ? './' : '') + relatePath; 665 return `import ${importEntity.importElements} from '${relatePath}'\n`; 666 } 667 } 668 } 669 return ''; 670} 671 672/** 673 * get import pathName 674 * @param importPathSplit import path split to array data 675 * @returns string 676 */ 677function getImportPathName(importPathSplit: string[]): string { 678 let importPathName: string; 679 let fileName = importPathSplit[importPathSplit.length - 1]; 680 if (fileName.endsWith('.d.ts') || fileName.endsWith('.d.ets')) { 681 fileName = fileName.split(/\.d\.e?ts/)[0]; 682 } 683 if (fileName.includes('@')) { 684 importPathName = fileName.replace('@', '').replace(/\./g, '_'); 685 } else { 686 importPathName = fileName.replace(/\./g, '_'); 687 } 688 return importPathName; 689} 690 691/** 692 * get import pathName 693 * @param importEntity import entity data 694 * @param heritageClausesArray heritage elements array data 695 * @returns string 696 */ 697function generateImportElements(importEntity: ImportElementEntity, heritageClausesArray: string[]): string { 698 let importElements = importEntity.importElements; 699 if ( 700 !importElements.includes('{') && 701 !importElements.includes('* as') && 702 !heritageClausesArray.includes(importElements) && 703 importEntity.importPath.includes('@ohos') 704 ) { 705 const tmpArr = importEntity.importPath.split('.'); 706 const mockModuleName = firstCharacterToUppercase(tmpArr[tmpArr.length - 1].replace('"', '').replace('\'', '')); 707 if (importElements === 'observer' && importEntity.importPath.includes('@ohos.arkui.observer')) { 708 return `{ mockUiObserver as ${importElements}}`; 709 } 710 importElements = `{ mock${mockModuleName} }`; 711 } else { 712 // adapt no rules .d.ts 713 if (importElements.trim() === 'AccessibilityExtensionContext, { AccessibilityElement }') { 714 importElements = '{ AccessibilityExtensionContext, AccessibilityElement }'; 715 } else if (importElements.trim() === '{ image }') { 716 importElements = '{ mockImage as image }'; 717 } 718 } 719 return importElements; 720} 721