diff --git a/compiler/src/ark_utils.ts b/compiler/src/ark_utils.ts index 9017550761c57c3e6269f648bf88a006b9e3b24e..261b87a5617a345f46951c4ca3cad74f645b64ce 100644 --- a/compiler/src/ark_utils.ts +++ b/compiler/src/ark_utils.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2023-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -99,6 +99,9 @@ import { LogDataFactory } from './fast_build/ark_compiler/logger'; import * as ts from 'typescript'; +import { + PreloadFileModules +} from './fast_build/ark_compiler/module/module_preload_file_utils'; export const SRC_MAIN: string = 'src/main'; @@ -283,13 +286,19 @@ function processPackageDir(params: Object): string { return originalFilePath; } - -export function getOhmUrlBySystemApiOrLibRequest(moduleRequest: string, config?: Object, logger?: Object, - importerFile?: string, useNormalizedOHMUrl: boolean = false): string { +export type OhmUrlParams = { + moduleRequest: string; + moduleId: string; + config?: Object; + logger?: Object; + importerFile?: string; +}; +export function getOhmUrlBySystemApiOrLibRequest(params: OhmUrlParams, + useNormalizedOHMUrl: boolean = false, needPreloadSo: boolean = false): string { // 'arkui-x' represents cross platform related APIs, processed as 'ohos' const REG_SYSTEM_MODULE: RegExp = new RegExp(`@(${sdkConfigPrefix})\\.(\\S+)`); const REG_LIB_SO: RegExp = /lib(\S+)\.so/; - + const moduleRequest = params.moduleRequest; if (REG_SYSTEM_MODULE.test(moduleRequest.trim())) { return moduleRequest.replace(REG_SYSTEM_MODULE, (_, moduleType, systemKey) => { let moduleRequestStr = ''; @@ -297,30 +306,35 @@ export function getOhmUrlBySystemApiOrLibRequest(moduleRequest: string, config?: moduleRequestStr = moduleRequestCallback(moduleRequest, _, moduleType, systemKey); } if (moduleRequestStr !== '') { + needPreloadSo && PreloadFileModules.updatePreloadFileDataByItems( + moduleRequest, moduleRequestStr, params.moduleId); return moduleRequestStr; } + let resultOhmUrl: string = ''; const systemModule: string = `${moduleType}.${systemKey}`; if (NATIVE_MODULE.has(systemModule)) { - return `@native:${systemModule}`; + resultOhmUrl = `@native:${systemModule}`; } else if (moduleType === ARKTS_MODULE_NAME) { // @arkts.xxx -> @ohos:arkts.xxx - return `@ohos:${systemModule}`; + resultOhmUrl = `@ohos:${systemModule}`; } else { - return `@ohos:${systemKey}`; - }; + resultOhmUrl = `@ohos:${systemKey}`; + } + needPreloadSo && PreloadFileModules.updatePreloadFileDataByItems(moduleRequest, resultOhmUrl, params.moduleId); + return resultOhmUrl; }); } if (REG_LIB_SO.test(moduleRequest.trim())) { if (useNormalizedOHMUrl) { - const pkgInfo = config.pkgContextInfo[moduleRequest]; + const pkgInfo = params.config.pkgContextInfo[moduleRequest]; if (!pkgInfo) { const errInfo: LogData = LogDataFactory.newInstance( ErrorCode.ETS2BUNDLE_INTERNAL_UNABLE_TO_GET_PKG_CONTENT_INFO, ArkTSInternalErrorDescription, `Can not get pkgContextInfo of package '${moduleRequest}' ` + - `which being imported by '${importerFile}'` + `which being imported by '${params.importerFile}'` ); - logger?.printError(errInfo); + params.logger?.printError(errInfo); return moduleRequest; } const isSo = pkgInfo.isSO ? 'Y' : 'N'; diff --git a/compiler/src/fast_build/ark_compiler/error_code.ts b/compiler/src/fast_build/ark_compiler/error_code.ts index 9b1a594a525e71fe404d62330cff39c322d7e7ea..1f69287974316a40503ab143d246acb3bbdca584 100644 --- a/compiler/src/fast_build/ark_compiler/error_code.ts +++ b/compiler/src/fast_build/ark_compiler/error_code.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Huawei Device Co., Ltd. + * Copyright (c) 2024-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -45,6 +45,7 @@ export enum ErrorCode { ETS2BUNDLE_INTERNAL_SOURCE_CODE_OBFUSCATION_FAILED = '10310020', ETS2BUNDLE_INTERNAL_ES2ABC_SUBPROCESS_START_FAILED = '10310021', ETS2BUNDLE_INTERNAL_EXECUTE_ES2ABC_WITH_ASYNC_HANDLER_FAILED = '10310022', + ETS2BUNDLE_INTERNAL_WRITE_PERLOAD_SO_FAILED = '10310023', // EXTERNAL ERRORS ETS2BUNDLE_EXTERNAL_FORBIDDEN_IMPORT_ARKTS_FILE = '10311001', diff --git a/compiler/src/fast_build/ark_compiler/generate_module_abc.ts b/compiler/src/fast_build/ark_compiler/generate_module_abc.ts index 1053a7cf9f8f1bd6bbe372144acee964a19aca95..f24a68778a83a53ad6aa300fc7dfac74554f0254 100644 --- a/compiler/src/fast_build/ark_compiler/generate_module_abc.ts +++ b/compiler/src/fast_build/ark_compiler/generate_module_abc.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2023-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -28,6 +28,7 @@ import { createAndStartEvent, stopEvent } from '../../performance'; +import { PreloadFileModules } from './module/module_preload_file_utils'; let moduleMode: ModuleMode = null; @@ -53,6 +54,7 @@ export async function generateModuleAbc(error) { return; } } + PreloadFileModules.finalizeWritePreloadSoList(); generateAbc(this, hookEventFactory); } } diff --git a/compiler/src/fast_build/ark_compiler/module/module_preload_file_utils.ts b/compiler/src/fast_build/ark_compiler/module/module_preload_file_utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..bfe9b50ad22d2c2d63fbf01a5f06bf18896de4ea --- /dev/null +++ b/compiler/src/fast_build/ark_compiler/module/module_preload_file_utils.ts @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import path from 'path'; +import fs from 'fs'; +import { + CommonLogger, + LogData, + LogDataFactory +} from '../logger'; +import { + ArkTSInternalErrorDescription, + ErrorCode +} from '../error_code'; + +interface PreloadEntry { + name: string; + srcEntry: string; + ohmurl: string; + moduleId: string; +} + +interface PreloadFileStructure { + systemPreloadHintStartupTasks: PreloadEntry[]; +} + +export class PreloadFileModules { + private static needPreloadSo: boolean = true; + private static preloadEntries: Array<{ name: string; srcEntry: string; ohmurl: string }> = []; + private static preloadEntriesBack: Array<{ name: string; srcEntry: string; ohmurl: string; moduleId: string }> = []; + private static preloadFilePath: string; + private static preloadFilePathBack: string; + private static projectConfig: Object; + private static logger: CommonLogger; + private static moduleIds: string[] = []; + + public static initialize(rollupObject: Object): void { + this.projectConfig = Object.assign(rollupObject.share.arkProjectConfig, rollupObject.share.projectConfig); + this.logger = CommonLogger.getInstance(rollupObject); + if (this.projectConfig.widgetCompile) { + this.needPreloadSo = false; + return; + } + if (!this.projectConfig.preloadSoFilePath) { + this.needPreloadSo = false; + return; + } + this.needPreloadSo = true; + this.preloadFilePath = this.projectConfig.preloadSoFilePath; + this.preloadFilePathBack = this.preloadFilePath.replace('.json', '.backup.json'); + } + + public static updatePreloadFileDataByItems(moduleRequest: string, ohmurl: string, moduleId: string): void { + if (!this.needPreloadSo) { + return; + } + + const newEntryBack = { name: moduleRequest, srcEntry: moduleRequest, ohmurl: ohmurl, moduleId: moduleId }; + // One file is only need record once so + const backExists = this.preloadEntriesBack.some( + entry => entry.moduleId === moduleId && entry.name === moduleRequest + ); + if (!backExists) { + this.preloadEntriesBack.push(newEntryBack); + } + } + + public static removePreloadSoDataByModuleIds(): void { + if (!this.needPreloadSo) { + return; + } + + const backupFilePath = this.preloadFilePathBack; + if (!fs.existsSync(backupFilePath)) { + this.preloadEntries = [...this.deduplicateByName(this.preloadEntriesBack)]; + return; + } + + try { + const rawData = fs.readFileSync(backupFilePath, 'utf8'); + const parsed: PreloadFileStructure = JSON.parse(rawData); + + if (!parsed || !Array.isArray(parsed.systemPreloadHintStartupTasks)) { + const errInfo = LogDataFactory.newInstance( + ErrorCode.ETS2BUNDLE_INTERNAL_WRITE_PERLOAD_SO_FAILED, + ArkTSInternalErrorDescription, + 'Invalid JSON structure in preload so backup file.' + ); + this.logger?.printError?.(errInfo); + } + + const filtered = parsed.systemPreloadHintStartupTasks.filter( + entry => !this.moduleIds.includes(entry.moduleId) + ); + + const merged = [...this.preloadEntriesBack, ...filtered]; + const uniqueEntries = Array.from( + merged.reduce((map, entry) => { + const key = `${entry.moduleId}-${entry.name}`; + if (!map.has(key)) { + map.set(key, entry); + } + return map; + }, new Map()).values() + ); + this.preloadEntriesBack = uniqueEntries; + this.preloadEntries = [...this.deduplicateByName(this.preloadEntriesBack)]; + } catch (e) { + const errInfo = LogDataFactory.newInstance( + ErrorCode.ETS2BUNDLE_INTERNAL_WRITE_PERLOAD_SO_FAILED, + ArkTSInternalErrorDescription, + `Failed to update preload so backup file: ${e.message}` + ); + this.logger?.printError?.(errInfo); + } + } + + private static deduplicateByName(entries: T[]): T[] { + const seenNames = new Set(); + return entries + .map(({ moduleId, ...rest }) => rest) + .filter(entry => { + if (seenNames.has(entry.name)) { + return false; + } + seenNames.add(entry.name); + return true; + }); + } + + public static finalizeWritePreloadSoList(): void { + if (!this.needPreloadSo) { + return; + } + + try { + this.removePreloadSoDataByModuleIds(); + + const PRELOAD_FILE_STRUCTURE = { + systemPreloadHintStartupTasks: this.preloadEntries + }; + + const PRELOAD_FILE_STRUCTURE_BACK = { + systemPreloadHintStartupTasks: this.preloadEntriesBack + }; + + this.ensureDirectoryExistence(this.preloadFilePath); + fs.writeFileSync(this.preloadFilePath, JSON.stringify(PRELOAD_FILE_STRUCTURE, null, 2), 'utf8'); + + this.ensureDirectoryExistence(this.preloadFilePathBack); + fs.writeFileSync(this.preloadFilePathBack, JSON.stringify(PRELOAD_FILE_STRUCTURE_BACK, null, 2), 'utf8'); + } catch (error) { + const errInfo = LogDataFactory.newInstance( + ErrorCode.ETS2BUNDLE_INTERNAL_WRITE_PERLOAD_SO_FAILED, + ArkTSInternalErrorDescription, + `Failed to write preload so file: ${error.message}` + ); + this.logger?.printError?.(errInfo); + } + } + + static collectModuleIds(moduleId: string): void { + if (!this.needPreloadSo) { + return; + } + this.moduleIds.push(moduleId); + } + + private static ensureDirectoryExistence(filePath: string): void { + const dir = path.dirname(filePath); + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } + } + + public static cleanUpPreloadSoObjects(): void { + this.preloadEntries = []; + this.preloadEntriesBack = []; + this.preloadFilePath = ''; + this.preloadFilePathBack = ''; + this.logger = undefined; + this.projectConfig = undefined; + this.moduleIds = []; + this.needPreloadSo = true; + } +} \ No newline at end of file diff --git a/compiler/src/fast_build/ark_compiler/module/module_source_file.ts b/compiler/src/fast_build/ark_compiler/module/module_source_file.ts index 900b195c6ed77b185112fee4a35951d40c435ebe..78f5bf1db9c9aa38e4d3861498d8428e0875d78f 100644 --- a/compiler/src/fast_build/ark_compiler/module/module_source_file.ts +++ b/compiler/src/fast_build/ark_compiler/module/module_source_file.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2023-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use rollupObject file except in compliance with the License. * You may obtain a copy of the License at @@ -28,7 +28,8 @@ import { getOhmUrlByByteCodeHar, getOhmUrlByFilepath, getOhmUrlByExternalPackage, - getOhmUrlBySystemApiOrLibRequest + getOhmUrlBySystemApiOrLibRequest, + OhmUrlParams } from '../../../ark_utils'; import { writeFileSyncByNode } from '../../../process_module_files'; import { @@ -83,6 +84,7 @@ import { getDeclgenBridgeCodePath, writeBridgeCodeFileSyncByNode } from '../../../process_arkts_evolution'; +import { PreloadFileModules } from './module_preload_file_utils'; const ROLLUP_IMPORT_NODE: string = 'ImportDeclaration'; const ROLLUP_EXPORTNAME_NODE: string = 'ExportNamedDeclaration'; @@ -371,6 +373,7 @@ export class ModuleSourceFile { if (!rollupObject.share.projectConfig.compileHar || ModuleSourceFile.projectConfig.byteCodeHar) { //compileHar: compile closed source har of project, which convert .ets to .d.ts and js, doesn't transform module request. const eventBuildModuleSourceFile = createAndStartEvent(parentEvent, 'build module source files'); + PreloadFileModules.collectModuleIds(moduleId); await moduleSourceFile.processModuleRequest(rollupObject, eventBuildModuleSourceFile); stopEvent(eventBuildModuleSourceFile); } @@ -410,6 +413,7 @@ export class ModuleSourceFile { if (!rollupObject.share.projectConfig.compileHar || byteCodeHar) { // compileHar: compile closed source har of project, which convert .ets to .d.ts and js, doesn't transform module request. const eventBuildModuleSourceFile = createAndStartEvent(parentEvent, 'build module source files'); + PreloadFileModules.collectModuleIds(source.getModuleId()); await source.processModuleRequest(rollupObject, eventBuildModuleSourceFile); stopEvent(eventBuildModuleSourceFile); } @@ -457,8 +461,16 @@ export class ModuleSourceFile { if (!!rollupObject.share.projectConfig.useNormalizedOHMUrl) { useNormalizedOHMUrl = rollupObject.share.projectConfig.useNormalizedOHMUrl; } - let systemOrLibOhmUrl = getOhmUrlBySystemApiOrLibRequest(moduleRequest, ModuleSourceFile.projectConfig, - ModuleSourceFile.logger, importerFile, useNormalizedOHMUrl); + const metaModuleInfo: Object = rollupObject.getModuleInfo(this.moduleId); + const isNeedPreloadSo = metaModuleInfo?.meta?.needPreloadSo ? metaModuleInfo?.meta?.needPreloadSo : false; + const params: OhmUrlParams = { + moduleRequest, + moduleId: this.moduleId, + config: ModuleSourceFile.projectConfig, + logger: ModuleSourceFile.logger, + importerFile, + }; + let systemOrLibOhmUrl = getOhmUrlBySystemApiOrLibRequest(params, useNormalizedOHMUrl, isNeedPreloadSo); if (systemOrLibOhmUrl !== undefined) { if (ModuleSourceFile.needProcessMock) { ModuleSourceFile.generateNewMockInfo(moduleRequest, systemOrLibOhmUrl, rollupObject, importerFile); diff --git a/compiler/src/fast_build/ark_compiler/rollup-plugin-gen-abc.ts b/compiler/src/fast_build/ark_compiler/rollup-plugin-gen-abc.ts index 32df152df7571d4259e9dbffa8f70312b12bd32a..8c666e634cd44c8f96e0a34b2cc0ee4702a48dde 100644 --- a/compiler/src/fast_build/ark_compiler/rollup-plugin-gen-abc.ts +++ b/compiler/src/fast_build/ark_compiler/rollup-plugin-gen-abc.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2023-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -34,6 +34,7 @@ import { CompileEvent } from '../../performance'; import { BytecodeObfuscator } from './bytecode_obfuscator'; +import { PreloadFileModules } from './module/module_preload_file_utils'; export function genAbc() { return { @@ -44,6 +45,8 @@ export function genAbc() { //Because calling the method of SourceMapGenerator may not retrieve the rollupObject //it is necessary to assign the rollupObject to SourceMapGenerator in the early stages of build SourceMapGenerator.init(this); + // Check proload path exist or not, initialize preloadBack path + PreloadFileModules.initialize(this); }, shouldInvalidCache: shouldInvalidCache, transform: transformForModule, @@ -85,6 +88,7 @@ export function genAbc() { cleanUpAsyncEvents(); BytecodeObfuscator.cleanBcObfuscatorObject(); cleanUpProcessArkTSEvolutionObj(); + PreloadFileModules.cleanUpPreloadSoObjects(); } }; } diff --git a/compiler/test/ark_compiler_ut/module/ohmUrl/ohmUrl.test.ts b/compiler/test/ark_compiler_ut/module/ohmUrl/ohmUrl.test.ts index 53df1a2e785a50ce574680ef450074b6b3e69ba3..6c4d4d769dcff4c61c57a63e07fb17a78aca1708 100644 --- a/compiler/test/ark_compiler_ut/module/ohmUrl/ohmUrl.test.ts +++ b/compiler/test/ark_compiler_ut/module/ohmUrl/ohmUrl.test.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2023-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use rollupObject file except in compliance with the License. * You may obtain a copy of the License at @@ -16,6 +16,7 @@ import { expect } from 'chai'; import mocha from 'mocha'; import sinon from 'sinon'; +import fs from 'fs'; import { getOhmUrlByFilepath, @@ -24,7 +25,8 @@ import { getNormalizedOhmUrlByFilepath, getNormalizedOhmUrlByAliasName, getNormalizedOhmUrlByModuleRequest, - pkgDeclFilesConfig + pkgDeclFilesConfig, + OhmUrlParams } from '../../../../lib/ark_utils'; import { PACKAGES } from '../../../../lib/pre_define'; import projectConfig from '../../utils/processProjectConfig'; @@ -42,6 +44,7 @@ import { LogData, LogDataFactory } from '../../../../lib/fast_build/ark_compiler/logger'; +import { PreloadFileModules } from '../../../../lib/fast_build/ark_compiler/module/module_preload_file_utils'; const PRVIEW_MOCK_CONFIG : Object = { // system api mock @@ -108,9 +111,30 @@ mocha.describe('generate ohmUrl', function () { const systemModuleRequest: string = '@system.app'; const ohosModuleRequest: string = '@ohos.hilog'; const appSoModuleRequest: string = 'libapplication.so'; - const systemOhmUrl: string = getOhmUrlBySystemApiOrLibRequest(systemModuleRequest); - const ohosOhmUrl: string = getOhmUrlBySystemApiOrLibRequest(ohosModuleRequest); - const appOhmUrl: string = getOhmUrlBySystemApiOrLibRequest(appSoModuleRequest); + const systemParams: OhmUrlParams = { + moduleRequest:systemModuleRequest, + moduleId: '', + config: ModuleSourceFile.projectConfig, + logger: ModuleSourceFile.logger, + importerFile: undefined, + }; + const systemOhmUrl: string = getOhmUrlBySystemApiOrLibRequest(systemParams); + const ohosParams: OhmUrlParams = { + moduleRequest: ohosModuleRequest, + moduleId: '', + config: ModuleSourceFile.projectConfig, + logger: ModuleSourceFile.logger, + importerFile: undefined, + }; + const ohosOhmUrl: string = getOhmUrlBySystemApiOrLibRequest(ohosParams); + const appSoParams: OhmUrlParams = { + moduleRequest: appSoModuleRequest, + moduleId: '', + config: ModuleSourceFile.projectConfig, + logger: ModuleSourceFile.logger, + importerFile: undefined, + }; + const appOhmUrl: string = getOhmUrlBySystemApiOrLibRequest(appSoParams); const expectedSystemOhmUrl: string = '@native:system.app'; const expectedOhosOhmUrl: string = '@ohos:hilog'; const expectedappOhmUrl: string = '@app:UtTestApplication/entry/application'; @@ -1252,8 +1276,14 @@ mocha.describe('generate ohmUrl', function () { '/testHap/oh_modules/.ohpm/pkghar@test+har=/oh_modules/pkghar/src/main/ets/pages/Index.ets'; const appSoModuleRequest: string = 'libapplication.so'; try { - getOhmUrlBySystemApiOrLibRequest(appSoModuleRequest, this.rollup.share.projectConfig, logger, - importerFile, true); + const appSoParams: OhmUrlParams = { + moduleRequest: appSoModuleRequest, + moduleId: '', + config: this.rollup.share.projectConfig, + logger: logger, + importerFile: importerFile, + }; + getOhmUrlBySystemApiOrLibRequest(appSoParams, true); } catch (e) { } expect(loggerStub.calledWith(errInfo)).to.be.true; @@ -1279,8 +1309,14 @@ mocha.describe('generate ohmUrl', function () { '/testHap/oh_modules/.ohpm/pkghar@test+har=/oh_modules/pkghar/src/main/ets/pages/Index.ets'; const appSoModuleRequest: string = 'libapplication.so'; try { - getOhmUrlBySystemApiOrLibRequest(appSoModuleRequest, this.rollup.share.projectConfig, logger, - importerFile, true); + const appSoParams: OhmUrlParams = { + moduleRequest: appSoModuleRequest, + moduleId: '', + config: this.rollup.share.projectConfig, + logger: logger, + importerFile: importerFile, + }; + getOhmUrlBySystemApiOrLibRequest(appSoParams, true); } catch (e) { } expect(loggerStub.calledWith(errInfo.toString())).to.be.true; @@ -1474,4 +1510,49 @@ mocha.describe('generate ohmUrl', function () { this.rollup.share.getHvigorConsoleLogger = getHvigorConsoleLogger; loggerStub.restore(); }); + + mocha.it('Collect. so libraries referenced in the project and generate JSON files', function () { + this.rollup.build(); + this.rollup.share.projectConfig.useNormalizedOHMUrl = false; + this.rollup.share.projectConfig.preloadSoFilePath = 'build/default/intermediates/preload/default/preload.json'; + const filePath: string = '/testHsp/hsp/src/main/ets/utils/Calc.ets'; + const outFilePath: string = 'build/default/intermediates/preload/default/preload.json'; + const moduleRequest: string = '@ohos.router'; + const moduleInfo = { + id: filePath, + meta: { + needPreloadSo: true + }, + importedIdMaps: [filePath] + } + this.rollup.moduleInfos.push(moduleInfo); + const importerFile: string = '/testHsp/hsp/src/main/ets/pages/Index.ets' + const moduleSourceFile: string = new ModuleSourceFile(); + moduleSourceFile.moduleId = filePath; + ModuleSourceFile.initPluginEnv(this.rollup); + PreloadFileModules.initialize(this.rollup); + ModuleSourceFile.PreloadEntryNames = []; + ModuleSourceFile.preloadEntries = []; + + const resultOhmUrl: string = moduleSourceFile.getOhmUrl(this.rollup, moduleRequest, filePath, importerFile); + + PreloadFileModules.finalizeWritePreloadSoList(); + + const fileContent = fs.readFileSync(outFilePath, 'utf8'); + const expectedJson = { + "systemPreloadHintStartupTasks": [ + { + "name": "@ohos.router", + "ohmurl": "@ohos:router", + "srcEntry": "@ohos.router" + } + ] + }; + + // Remove trailing ',' if exists + const parsedFileContent = JSON.parse(fileContent.trim().replace(/,$/, '')); + expect(resultOhmUrl === '@ohos:router').to.be.true; + expect(fs.existsSync(outFilePath)).to.be.true; + expect(parsedFileContent).to.deep.equal(expectedJson); + }); }); \ No newline at end of file