diff --git a/compiler/main.js b/compiler/main.js index c9d6a4e889a8a355df6584b3cbcc9efa5e021c8e..22dbce8fafa8a62c8c9254b3a1fe8aa021e68c23 100644 --- a/compiler/main.js +++ b/compiler/main.js @@ -419,7 +419,7 @@ function setAbilityPages(projectConfig) { if (projectConfig.aceModuleJsonPath && fs.existsSync(projectConfig.aceModuleJsonPath)) { const moduleJson = JSON.parse(fs.readFileSync(projectConfig.aceModuleJsonPath).toString()); abilityPages = readAbilityEntrance(moduleJson); - setAbilityFile(projectConfig, abilityPages); + setAbilityFile(projectConfig, abilityPages, moduleJson.module?.codeLanguage); setBundleModuleInfo(projectConfig, moduleJson); } } @@ -486,13 +486,16 @@ function setBundleModuleInfo(projectConfig, moduleJson) { } } -function setAbilityFile(projectConfig, abilityPages) { +function setAbilityFile(projectConfig, abilityPages, codeLanguage) { abilityPages.forEach(abilityPath => { const projectAbilityPath = path.resolve(projectConfig.projectPath, '../', abilityPath); if (path.isAbsolute(abilityPath)) { abilityPath = '.' + abilityPath.slice(projectConfig.projectPath.length); } const entryPageKey = abilityPath.replace(/^\.\/ets\//, './').replace(/\.ts$/, '').replace(/\.ets$/, ''); + if (codeLanguage === '1.2') { + return; + } if (fs.existsSync(projectAbilityPath)) { abilityConfig.projectAbilityPath.push(projectAbilityPath); projectConfig.entryObj[entryPageKey] = projectAbilityPath + '?entry'; diff --git a/compiler/src/ets_checker.ts b/compiler/src/ets_checker.ts index 1ec5ea72b0daa6f0124e523ba1c28940ba3a50a9..3e3ed92b29e113a3f5d6b0219b527c17d6b5b59b 100644 --- a/compiler/src/ets_checker.ts +++ b/compiler/src/ets_checker.ts @@ -110,6 +110,7 @@ import { } from '../node_modules/declgen/build/src/generateInteropDecls'; import { arkTSEvolutionModuleMap, + arkTSHybridModuleMap, getArkTSEvoDeclFilePath } from './process_arkts_evolution'; import { processInteropUI } from './process_interop_ui'; @@ -572,9 +573,6 @@ export function serviceChecker(rootFileNames: string[], newLogger: Object = null processBuildHap(cacheFile, rootFileNames, compilationTime, rollupShareObject); MemoryMonitor.stopRecordStage(processBuildHaprrecordInfo); } - if (rollupShareObject?.projectConfig.mixCompile) { - generateDeclarationFileForSTS(rootFileNames); - } if (globalProgram.program && (process.env.watchMode !== 'true' && !projectConfig.isPreview && !projectConfig.hotReload && !projectConfig.coldReload)) { @@ -1093,7 +1091,7 @@ export function resolveModuleNames(moduleNames: string[], containingFile: string resolvedModules.push(result.resolvedModule); } } else if (result.resolvedModule.resolvedFileName && /\.ets$/.test(result.resolvedModule.resolvedFileName) && - !/\.d\.ets$/.test(result.resolvedModule.resolvedFileName) && arkTSEvolutionModuleMap.size !== 0) { + !/\.d\.ets$/.test(result.resolvedModule.resolvedFileName) && (arkTSEvolutionModuleMap.size !== 0 || arkTSHybridModuleMap.size !== 0)) { // When result has a value and the path parsed is the source code file path of module 1.2, // the parsing result needs to be modified to the glue code path of module 1.2 let arktsEvoDeclFilePathExist: boolean = false; @@ -1315,7 +1313,7 @@ export function instanceInsteadThis(content: string, fileName: string, extendFun return content; } -function getResolveModule(modulePath: string, type): ts.ResolvedModuleFull { +export function getResolveModule(modulePath: string, type): ts.ResolvedModuleFull { return { resolvedFileName: modulePath, isExternalLibraryImport: false, diff --git a/compiler/src/fast_build/ark_compiler/interop/run_declgen_standalone.ts b/compiler/src/fast_build/ark_compiler/interop/run_declgen_standalone.ts new file mode 100644 index 0000000000000000000000000000000000000000..cf724c889e00ad255cba56c78cc2c4466004bf39 --- /dev/null +++ b/compiler/src/fast_build/ark_compiler/interop/run_declgen_standalone.ts @@ -0,0 +1,408 @@ +/* + * 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 { FileManager } from './interop_manager'; +import { ResolveModuleInfo, getResolveModule, readDeaclareFiles } from '../../../ets_checker'; +import { processInteropUI } from '../../../process_interop_ui'; +import { + mkdirsSync, + readFile, + toUnixPath +} from '../../../utils'; +import { + ArkTSEvolutionModule, + BuildType, + DeclFilesConfig, + Params, + ProjectConfig, + RunnerParms +} from './type'; +import fs from 'fs'; +import path from 'path'; +import * as ts from 'typescript'; +import { EXTNAME_D_ETS, EXTNAME_JS } from '../common/ark_define'; +import { getRealModulePath } from '../../system_api/api_check_utils'; +import { generateInteropDecls } from '../../../../node_modules/declgen/build/src/generateInteropDecls'; + +export function run(param: Params): boolean { + FileManager.init(param.dependentModuleMap); + DeclfileProductor.init(param); + param.tasks.forEach(task => { + const moduleInfo = FileManager.arkTSModuleMap.get(task.packageName); + if (task.buildTask === BuildType.DECLGEN) { + DeclfileProductor.getInstance().runDeclgen(moduleInfo); + } else if (task.buildTask === BuildType.INTEROP_CONTEXT) { + DeclfileProductor.getInstance().writeDeclFileInfo(moduleInfo, task.mainModuleName); + } else if (task.buildTask === BuildType.BYTE_CODE_HAR) { + //todo + } + }); + return true; +} + +class DeclfileProductor { + private static declFileProductor: DeclfileProductor; + + static compilerOptions: ts.CompilerOptions; + static sdkConfigPrefix = 'ohos|system|kit|arkts'; + static sdkConfigs = []; + static systemModules = []; + static defaultSdkConfigs = []; + static projectPath; + private projectConfig; + private pkgDeclFilesConfig: { [pkgName: string]: DeclFilesConfig } = {}; + + static init(param: Params): void { + DeclfileProductor.declFileProductor = new DeclfileProductor(param); + DeclfileProductor.compilerOptions = ts.readConfigFile( + path.join(__dirname, '../../../../tsconfig.json'), ts.sys.readFile).config.compilerOptions; + DeclfileProductor.initSdkConfig(); + Object.assign(DeclfileProductor.compilerOptions, { + emitNodeModulesFiles: true, + importsNotUsedAsValues: ts.ImportsNotUsedAsValues.Preserve, + module: ts.ModuleKind.CommonJS, + moduleResolution: ts.ModuleResolutionKind.NodeJs, + noEmit: true, + packageManagerType: 'ohpm', + allowJs: true, + allowSyntheticDefaultImports: true, + esModuleInterop: true, + noImplicitAny: false, + noUnusedLocals: false, + noUnusedParameters: false, + experimentalDecorators: true, + resolveJsonModule: true, + skipLibCheck: false, + sourceMap: true, + target: 8, + types: [], + typeRoots: [], + lib: ['lib.es2021.d.ts'], + alwaysStrict: true, + checkJs: false, + maxFlowDepth: 2000, + etsAnnotationsEnable: false, + etsLoaderPath: path.join(__dirname, '../../../'), + needDoArkTsLinter: true, + isCompatibleVersion: false, + skipTscOhModuleCheck: false, + skipArkTSStaticBlocksCheck: false, + incremental: true, + tsImportSendableEnable: false, + skipPathsInKeyForCompilationSettings: true, + }); + DeclfileProductor.projectPath = param.projectConfig.projectRootPath; + } + static getInstance(param?: Params): DeclfileProductor { + if (!this.declFileProductor) { + this.declFileProductor = new DeclfileProductor(param); + } + return this.declFileProductor; + } + + private constructor(param: Params) { + this.projectConfig = param.projectConfig as ProjectConfig; + } + + runDeclgen(moduleInfo: ArkTSEvolutionModule): void { + let inputList = []; + moduleInfo.dynamicFiles.forEach(path => { + inputList.push(toUnixPath(path)); + }); + readDeaclareFiles().forEach(path => { + inputList.push(toUnixPath(path)); + }); + + inputList = inputList.filter(filePath => !filePath.endsWith('.js')); + const config: RunnerParms = { + inputDirs: [], + inputFiles: inputList, + outDir: moduleInfo.declgenV2OutPath, + // use package name as folder name + rootDir: moduleInfo.modulePath, + customResolveModuleNames: resolveModuleNames, + customCompilerOptions: DeclfileProductor.compilerOptions, + includePaths: [moduleInfo.modulePath] + }; + if (fs.existsSync(config.outDir)) { + fs.rmSync(config.outDir, { recursive: true, force: true }); + } + fs.mkdirSync(config.outDir, { recursive: true }); + generateInteropDecls(config); + processInteropUI(FileManager.arkTSModuleMap.get(moduleInfo.packageName)?.declgenV2OutPath); + } + + writeDeclFileInfo(moduleInfo: ArkTSEvolutionModule, mainModuleName: string): void { + moduleInfo.dynamicFiles.forEach(file => { + this.addDeclFilesConfig(file, mainModuleName, this.projectConfig.bundleName, moduleInfo); + }); + + const declFilesConfigFile: string = toUnixPath(moduleInfo.declFilesPath); + mkdirsSync(path.dirname(declFilesConfigFile)); + fs.writeFileSync(declFilesConfigFile, JSON.stringify(this.pkgDeclFilesConfig[moduleInfo.packageName], null, 2), 'utf-8'); + } + + addDeclFilesConfig(filePath: string, mainModuleName: string, bundleName: string, moduleInfo: ArkTSEvolutionModule): void { + const projectFilePath = getRelativePath(filePath, moduleInfo.modulePath); + + const declgenV2OutPath: string = this.getDeclgenV2OutPath(moduleInfo.packageName); + if (!declgenV2OutPath) { + return; + } + if (!this.pkgDeclFilesConfig[moduleInfo.packageName]) { + this.pkgDeclFilesConfig[moduleInfo.packageName] = { packageName: moduleInfo.packageName, files: {} }; + } + if (this.pkgDeclFilesConfig[moduleInfo.packageName].files[projectFilePath]) { + return; + } + // The module name of the entry module of the project during the current compilation process. + const normalizedFilePath: string = `${moduleInfo.packageName}/${projectFilePath}`; + const declPath: string = path.join(toUnixPath(declgenV2OutPath), projectFilePath) + EXTNAME_D_ETS; + const ohmUrl: string = `N&${mainModuleName}&${bundleName}&${normalizedFilePath}&${moduleInfo.packageVersion}`; + this.pkgDeclFilesConfig[moduleInfo.packageName].files[projectFilePath] = { declPath, ohmUrl: `@normalized:${ohmUrl}` }; + } + + getDeclgenV2OutPath(pkgName: string): string { + if (FileManager.arkTSModuleMap.size && FileManager.arkTSModuleMap.get(pkgName)) { + const arkTsModuleInfo: ArkTSEvolutionModule = FileManager.arkTSModuleMap.get(pkgName); + return arkTsModuleInfo.declgenV2OutPath; + } + return ''; + } + + static initSdkConfig(): void { + const apiDirPath = path.resolve(__dirname, '../../../../../api'); + const arktsDirPath = path.resolve(__dirname, '../../../../../arkts'); + const kitsDirPath = path.resolve(__dirname, '../../../../../kits'); + const systemModulePathArray = [apiDirPath]; + if (!process.env.isFaMode) { + systemModulePathArray.push(arktsDirPath, kitsDirPath); + } + systemModulePathArray.forEach(systemModulesPath => { + if (fs.existsSync(systemModulesPath)) { + const modulePaths = []; + readFile(systemModulesPath, modulePaths); + DeclfileProductor.systemModules.push(...fs.readdirSync(systemModulesPath)); + const moduleSubdir = modulePaths.filter(filePath => { + const dirName = path.dirname(filePath); + return !(dirName === apiDirPath || dirName === arktsDirPath || dirName === kitsDirPath); + }).map(filePath => { + return filePath + .replace(apiDirPath, '') + .replace(arktsDirPath, '') + .replace(kitsDirPath, '') + .replace(/(^\\)|(.d.e?ts$)/g, '') + .replace(/\\/g, '/'); + }); + } + }); + DeclfileProductor.defaultSdkConfigs = [ + { + 'apiPath': systemModulePathArray, + 'prefix': '@ohos' + }, { + 'apiPath': systemModulePathArray, + 'prefix': '@system' + }, { + 'apiPath': systemModulePathArray, + 'prefix': '@arkts' + } + ]; + DeclfileProductor.sdkConfigs = [...DeclfileProductor.defaultSdkConfigs]; + } +} + +function resolveModuleNames(moduleNames: string[], containingFile: string): ts.ResolvedModuleFull[] { + const resolvedModules: ts.ResolvedModuleFull[] = []; + + for (const moduleName of moduleNames) { + let resolvedModule: ts.ResolvedModuleFull | null = null; + + resolvedModule = resolveWithDefault(moduleName, containingFile); + if (resolvedModule) { + resolvedModules.push(resolvedModule); + continue; + } + + resolvedModule = resolveSdkModule(moduleName); + if (resolvedModule) { + resolvedModules.push(resolvedModule); + continue; + } + + resolvedModule = resolveEtsModule(moduleName, containingFile); + if (resolvedModule) { + resolvedModules.push(resolvedModule); + continue; + } + + resolvedModule = resolveTsModule(moduleName, containingFile); + if (resolvedModule) { + resolvedModules.push(resolvedModule); + continue; + } + + resolvedModule = resolveOtherModule(moduleName, containingFile); + resolvedModules.push(resolvedModule ?? null); + } + + return resolvedModules; +} + +function resolveWithDefault( + moduleName: string, + containingFile: string +): ts.ResolvedModuleFull | null { + const result = ts.resolveModuleName(moduleName, containingFile, DeclfileProductor.compilerOptions, moduleResolutionHost); + if (!result.resolvedModule) { + return null; + } + + const resolvedFileName = result.resolvedModule.resolvedFileName; + if (resolvedFileName && path.extname(resolvedFileName) === EXTNAME_JS) { + const resultDETSPath = resolvedFileName.replace(EXTNAME_JS, EXTNAME_D_ETS); + if (ts.sys.fileExists(resultDETSPath)) { + return getResolveModule(resultDETSPath, EXTNAME_D_ETS); + } + } + + return result.resolvedModule; +} + +function resolveEtsModule(moduleName: string, containingFile: string): ts.ResolvedModuleFull | null { + if (!/\.ets$/.test(moduleName) || /\.d\.ets$/.test(moduleName)) { + return null; + } + + const modulePath = path.resolve(path.dirname(containingFile), moduleName); + return ts.sys.fileExists(modulePath) ? getResolveModule(modulePath, '.ets') : null; +} + +function resolveSdkModule(moduleName: string): ts.ResolvedModuleFull | null { + const prefixRegex = new RegExp(`^@(${DeclfileProductor.sdkConfigPrefix})\\.`, 'i'); + if (!prefixRegex.test(moduleName.trim())) { + return null; + } + + for (const sdkConfig of DeclfileProductor.sdkConfigs) { + const resolveModuleInfo: ResolveModuleInfo = getRealModulePath(sdkConfig.apiPath, moduleName, ['.d.ts', '.d.ets']); + const modulePath: string = resolveModuleInfo.modulePath; + const isDETS: boolean = resolveModuleInfo.isEts; + + const moduleKey = moduleName + (isDETS ? '.d.ets' : '.d.ts'); + if (DeclfileProductor.systemModules.includes(moduleKey) && ts.sys.fileExists(modulePath)) { + return getResolveModule(modulePath, isDETS ? '.d.ets' : '.d.ts'); + } + } + + return null; +} + +function resolveTsModule(moduleName: string, containingFile: string): ts.ResolvedModuleFull | null { + if (!/\.ts$/.test(moduleName)) { + return null; + } + + + const modulePath = path.resolve(path.dirname(containingFile), moduleName); + return ts.sys.fileExists(modulePath) ? getResolveModule(modulePath, '.ts') : null; +} + +function resolveOtherModule(moduleName: string, containingFile: string): ts.ResolvedModuleFull | null { + const apiModulePath = path.resolve(__dirname, '../../../api', moduleName + '.d.ts'); + const systemDETSModulePath = path.resolve(__dirname, '../../../api', moduleName + '.d.ets'); + const kitModulePath = path.resolve(__dirname, '../../../kits', moduleName + '.d.ts'); + const kitSystemDETSModulePath = path.resolve(__dirname, '../../../kits', moduleName + '.d.ets'); + const jsModulePath = path.resolve(__dirname, '../node_modules', moduleName + (moduleName.endsWith('.js') ? '' : '.js')); + const fileModulePath = path.resolve(__dirname, '../node_modules', moduleName + '/index.js'); + const DETSModulePath = path.resolve(path.dirname(containingFile), + moduleName.endsWith('.d.ets') ? moduleName : moduleName + EXTNAME_D_ETS); + + if (ts.sys.fileExists(apiModulePath)) { + return getResolveModule(apiModulePath, '.d.ts'); + } else if (ts.sys.fileExists(systemDETSModulePath)) { + return getResolveModule(systemDETSModulePath, '.d.ets'); + } else if (ts.sys.fileExists(kitModulePath)) { + return getResolveModule(kitModulePath, '.d.ts'); + } else if (ts.sys.fileExists(kitSystemDETSModulePath)) { + return getResolveModule(kitSystemDETSModulePath, '.d.ets'); + } else if (ts.sys.fileExists(jsModulePath)) { + return getResolveModule(jsModulePath, '.js'); + } else if (ts.sys.fileExists(fileModulePath)) { + return getResolveModule(fileModulePath, '.js'); + } else if (ts.sys.fileExists(DETSModulePath)) { + return getResolveModule(DETSModulePath, '.d.ets'); + } else { + const srcIndex = DeclfileProductor.projectPath.indexOf('src' + path.sep + 'main'); + if (srcIndex > 0) { + const DETSModulePathFromModule = path.resolve( + DeclfileProductor.projectPath.substring(0, srcIndex), + moduleName + path.sep + 'index' + EXTNAME_D_ETS + ); + if (ts.sys.fileExists(DETSModulePathFromModule)) { + return getResolveModule(DETSModulePathFromModule, '.d.ets'); + } + } + return null; + } +} + +function getRelativePath(filePath: string, pkgPath: string): string { + // rollup uses commonjs plugin to handle commonjs files, + // the commonjs files are prefixed with '\x00' and need to be removed. + if (filePath.startsWith('\x00')) { + filePath = filePath.replace('\x00', ''); + } + let unixFilePath: string = toUnixPath(filePath); + + // Handle .d.ets and .d.ts extensions + const dEtsIndex = unixFilePath.lastIndexOf('.d.ets'); + const dTsIndex = unixFilePath.lastIndexOf('.d.ts'); + + if (dEtsIndex !== -1) { + unixFilePath = unixFilePath.substring(0, dEtsIndex); + } else if (dTsIndex !== -1) { + unixFilePath = unixFilePath.substring(0, dTsIndex); + } else { + // Fallback to regular extension removal if not a .d file + const lastDotIndex = unixFilePath.lastIndexOf('.'); + if (lastDotIndex !== -1) { + unixFilePath = unixFilePath.substring(0, lastDotIndex); + } + } + + const projectFilePath: string = unixFilePath.replace(toUnixPath(pkgPath) + '/', ''); + return projectFilePath; +} + +const moduleResolutionHost: ts.ModuleResolutionHost = { + fileExists: (fileName: string): boolean => { + let exists = ts.sys.fileExists(fileName); + if (exists === undefined) { + exists = ts.sys.fileExists(fileName); + } + return exists; + }, + + readFile(fileName: string): string | undefined { + return ts.sys.readFile(fileName); + }, + realpath(path: string): string { + return ts.sys.realpath(path); + }, + trace(s: string): void { + console.info(s); + } +}; \ No newline at end of file diff --git a/compiler/src/fast_build/ark_compiler/interop/type.ts b/compiler/src/fast_build/ark_compiler/interop/type.ts index 66deaf308e7745ec5057218228b9087c116cb171..132f76602b588bc41b9835f177bcdcffadc5d986 100644 --- a/compiler/src/fast_build/ark_compiler/interop/type.ts +++ b/compiler/src/fast_build/ark_compiler/interop/type.ts @@ -13,6 +13,8 @@ * limitations under the License. */ +import * as ts from 'typescript'; + export interface ArkTSEvolutionModule { language: string; packageName: string; @@ -26,6 +28,7 @@ export interface ArkTSEvolutionModule { staticFiles: string[]; cachePath: string; byteCodeHarInfo?: Object; + packageVersion: string; } export const ARKTS_1_2: string = '1.2'; @@ -39,14 +42,14 @@ export interface Params { tasks: taskInfo[]; } -interface ProjectConfig { +export interface ProjectConfig { cachePath: string; bundleName: string; mainModuleName: string; projectRootPath: string; }; -enum BuildType { +export enum BuildType { DECLGEN = 'declgen', BYTE_CODE_HAR = 'byteCodeHar', INTEROP_CONTEXT = 'interopContext' @@ -55,6 +58,7 @@ enum BuildType { interface taskInfo { packageName: string; buildTask: BuildType; + mainModuleName?: string; } export interface AliasConfig { @@ -66,4 +70,27 @@ export interface FileInfo { recordName: string; baseUrl: string; absolutePath: string; + abstractPath: string; +} + +export interface RunnerParms { + inputDirs: string[]; + inputFiles: string[]; + outDir: string; + rootDir: string; + customResolveModuleNames?: (moduleName: string[], containingFile: string) => ts.ResolvedModuleFull[]; + customCompilerOptions?: ts.CompilerOptions; + includePaths?: string[]; +} + +export interface DeclFilesConfig { + packageName: string; + files: { + [filePath: string]: DeclFileConfig; + } +} + +interface DeclFileConfig { + declPath: string; + ohmUrl: string; } \ No newline at end of file diff --git a/compiler/src/fast_build/ark_compiler/module/module_mode.ts b/compiler/src/fast_build/ark_compiler/module/module_mode.ts index 04d649e96d5d457715b3af319cc7325907c0e261..41a2b3eb3475568b3a4d1acd3a16893962ff06b1 100644 --- a/compiler/src/fast_build/ark_compiler/module/module_mode.ts +++ b/compiler/src/fast_build/ark_compiler/module/module_mode.ts @@ -100,6 +100,7 @@ import { } from '../../../gen_aot'; import { ARKTS_1_2, + ARKTS_HYBRID, NATIVE_MODULE } from '../../../pre_define'; import { @@ -124,6 +125,7 @@ import { genCachePathForBridgeCode, getDeclgenBridgeCodePath, pkgDeclFilesConfig, + isArkTSEvolutionFile } from '../../../process_arkts_evolution'; export class ModuleInfo { @@ -251,9 +253,9 @@ export class ModuleMode extends CommonMode { ); this.logger.printErrorAndExit(errInfo); } - const isArkTSEvolution: boolean = metaInfo.language === ARKTS_1_2; + const isArkTSEvolution: boolean = isArkTSEvolutionFile(moduleId, metaInfo); const pkgPath: string = isArkTSEvolution ? - path.join(getDeclgenBridgeCodePath(metaInfo.pkgName), metaInfo.moduleName) : metaInfo.pkgPath; + path.join(getDeclgenBridgeCodePath(metaInfo.pkgName), metaInfo.pkgName) : metaInfo.pkgPath; const pkgParams = { pkgName: metaInfo.pkgName, pkgPath, @@ -520,16 +522,15 @@ export class ModuleMode extends CommonMode { let moduleName: string = metaInfo.moduleName; let recordName: string = ''; - let cacheFilePath: string = metaInfo.language === ARKTS_1_2 ? - genCachePathForBridgeCode(originalFilePath, metaInfo, this.projectConfig.cachePath) : + let cacheFilePath: string = isArkTSEvolutionFile(filePath, metaInfo) ? originalFilePath : this.genFileCachePath(filePath, this.projectConfig.projectRootPath, this.projectConfig.cachePath, metaInfo); let packageName: string = ''; if (this.useNormalizedOHMUrl) { packageName = metaInfo.pkgName; - const isArkTSEvolution: boolean = metaInfo.language === ARKTS_1_2; + const isArkTSEvolution: boolean = isArkTSEvolutionFile(filePath, metaInfo); const pkgPath: string = isArkTSEvolution ? - path.join(getDeclgenBridgeCodePath(packageName), metaInfo.moduleName) : metaInfo.pkgPath; + path.join(getDeclgenBridgeCodePath(packageName), metaInfo.pkgName) : metaInfo.pkgPath; const pkgParams = { pkgName: packageName, pkgPath, 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 78cd2330932fbc03e122e13ce7eecbce46a96238..6d7407b478e4e26822ddc64bcb9ea23c848f8689 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 @@ -53,6 +53,7 @@ import { import { ORIGIN_EXTENTION } from '../process_mock'; import { ARKTS_1_2, + ARKTS_HYBRID, ESMODULE, TRANSFORMED_MOCK_CONFIG, USER_DEFINE_MOCK_CONFIG @@ -81,7 +82,8 @@ import { import { checkIfJsImportingArkts } from '../check_import_module'; import { getDeclgenBridgeCodePath, - writeBridgeCodeFileSyncByNode + writeBridgeCodeFileSyncByNode, + isArkTSEvolutionFile } from '../../../process_arkts_evolution'; const ROLLUP_IMPORT_NODE: string = 'ImportDeclaration'; @@ -117,7 +119,7 @@ export class ModuleSourceFile { if (typeof this.source !== 'string') { this.isSourceNode = true; } - if (metaInfo?.language === ARKTS_1_2) { + if (metaInfo?.language === ARKTS_1_2 || (metaInfo && isArkTSEvolutionFile(moduleId, metaInfo))) { this.isArkTSEvolution = true; } } @@ -508,9 +510,9 @@ export class ModuleSourceFile { } private static spliceNormalizedOhmurl(moduleInfo: Object, filePath: string, importerFile?: string): string { - const isArkTSEvolution: boolean = moduleInfo.meta.language === ARKTS_1_2; + const isArkTSEvolution: boolean = isArkTSEvolutionFile(filePath, moduleInfo.meta); const pkgPath: string = isArkTSEvolution ? - path.join(getDeclgenBridgeCodePath(moduleInfo.meta.pkgName), moduleInfo.meta.moduleName) : moduleInfo.meta.pkgPath; + path.join(getDeclgenBridgeCodePath(moduleInfo.meta.pkgName), moduleInfo.meta.pkgName) : moduleInfo.meta.pkgPath; const pkgParams = { pkgName: moduleInfo.meta.pkgName, pkgPath, diff --git a/compiler/src/fast_build/common/process_project_config.ts b/compiler/src/fast_build/common/process_project_config.ts index ac205bf345553223b77408b355f272212e3f33b0..82da9bbf0eeb3b7be1deec6aa07f4616a7249046 100644 --- a/compiler/src/fast_build/common/process_project_config.ts +++ b/compiler/src/fast_build/common/process_project_config.ts @@ -38,7 +38,11 @@ export function getEntryObj() { } projectConfig.entryObj = Object.keys(projectConfig.entryObj).reduce((newEntry, key) => { const newKey: string = key.replace(/^\.\//, ''); - newEntry[newKey] = projectConfig.entryObj[key].replace('?entry', ''); + const filePath = projectConfig.entryObj[key].replace('?entry', ''); + const firstLine = fs.readFileSync(filePath, 'utf-8').split('\n')[0]; + if (!firstLine.includes('use static')) { + newEntry[newKey] = filePath; + } return newEntry; }, {}); } diff --git a/compiler/src/pre_define.ts b/compiler/src/pre_define.ts index 5da8a4c27d78f6f21f6680bde8222a96906740a5..354c315bc01476f61b6699df48e3cc45837a89ba 100644 --- a/compiler/src/pre_define.ts +++ b/compiler/src/pre_define.ts @@ -648,4 +648,5 @@ export const INTEGRATED_HSP: string = 'integratedHsp'; export const ARKTS_1_2: string = '1.2'; export const ARKTS_1_1: string = '1.1'; -export const ARKTS_1_0: string = '1.0'; \ No newline at end of file +export const ARKTS_1_0: string = '1.0'; +export const ARKTS_HYBRID: string = 'hybrid'; \ No newline at end of file diff --git a/compiler/src/process_arkts_evolution.ts b/compiler/src/process_arkts_evolution.ts index 866c017a665d73d9d03ee2863a82a4f1893ba906..47662d69bd739b47e6ccca8181f04d941ce5a382 100644 --- a/compiler/src/process_arkts_evolution.ts +++ b/compiler/src/process_arkts_evolution.ts @@ -20,9 +20,11 @@ import ts from 'typescript'; import { EXTNAME_ETS, EXTNAME_D_ETS, + EXTNAME_TS, ARKTS_1_0, ARKTS_1_1, ARKTS_1_2, + ARKTS_HYBRID, SUPER_ARGS } from './pre_define'; import { @@ -114,7 +116,8 @@ export function addDeclFilesConfig(filePath: string, projectConfig: Object, logg export function getArkTSEvoDeclFilePath(resolvedFileInfo: ResolvedFileInfo): string { const { moduleRequest, resolvedFileName } = resolvedFileInfo; let arktsEvoDeclFilePath: string = moduleRequest; - for (const [pkgName, arkTSEvolutionModuleInfo] of arkTSEvolutionModuleMap) { + const combinedMap = new Map([...arkTSEvolutionModuleMap, ...arkTSHybridModuleMap]); + for (const [pkgName, arkTSEvolutionModuleInfo] of combinedMap) { const declgenV1OutPath: string = toUnixPath(arkTSEvolutionModuleInfo.declgenV1OutPath); const modulePath: string = toUnixPath(arkTSEvolutionModuleInfo.modulePath); const declgenBridgeCodePath: string = toUnixPath(arkTSEvolutionModuleInfo.declgenBridgeCodePath); @@ -134,6 +137,19 @@ export function getArkTSEvoDeclFilePath(resolvedFileInfo: ResolvedFileInfo): str pkgName, toUnixPath(path.join(declgenV1OutPath, pkgName, 'src/main/ets')) ) + EXTNAME_D_ETS; + + if (fs.existsSync(arktsEvoDeclFilePath)) { + break; + } + /** + * If the import is exported via the package name, for example: + * import { xxx } from 'src/main/ets/xxx/xxx/...' + * there is no need to additionally concatenate 'src/main/ets' + */ + arktsEvoDeclFilePath = moduleRequest.replace( + pkgName, + toUnixPath(path.join(declgenV1OutPath, pkgName)) + ) + EXTNAME_D_ETS; break; } } @@ -149,23 +165,36 @@ export function collectArkTSEvolutionModuleInfo(share: Object): void { // dependentModuleMap Contents eg. // 1.2 hap -> 1.1 har: It contains the information of 1.1 har // 1.1 hap -> 1.2 har -> 1.1 har : There is information about 3 modules. + + const throwCollectionError = (pkgName: string): void => { + share.throwArkTsCompilerError(red, 'ArkTS:INTERNAL ERROR: Failed to collect arkTs evolution module info.\n' + + `Error Message: Failed to collect arkTs evolution module "${pkgName}" info from rollup.`, reset); + }; + for (const [pkgName, dependentModuleInfo] of share.projectConfig.dependentModuleMap) { - if (dependentModuleInfo.language === ARKTS_1_2) { - if (dependentModuleInfo.declgenV1OutPath && dependentModuleInfo.declgenBridgeCodePath) { - arkTSEvolutionModuleMap.set(pkgName, dependentModuleInfo); - } else { - share.throwArkTsCompilerError(red, 'ArkTS:INTERNAL ERROR: Failed to collect arkTs evolution module info.\n' + - `Error Message: Failed to collect arkTs evolution module "${pkgName}" info from rollup.`, reset); - } - } else if (dependentModuleInfo.language === ARKTS_1_1 || dependentModuleInfo.language === ARKTS_1_0) { - if (dependentModuleInfo.declgenV2OutPath && dependentModuleInfo.declFilesPath) { - arkTSModuleMap.set(pkgName, dependentModuleInfo); - } else { - share.throwArkTsCompilerError(red, 'ArkTS:INTERNAL ERROR: Failed to collect arkTs evolution module info.\n' + - `Error Message: Failed to collect arkTs evolution module "${pkgName}" info from rollup.`, reset); - } - } else { - arkTSHybridModuleMap.set(pkgName, dependentModuleInfo); + switch (dependentModuleInfo.language) { + case ARKTS_1_2: + if (dependentModuleInfo.declgenV1OutPath && dependentModuleInfo.declgenBridgeCodePath) { + arkTSEvolutionModuleMap.set(pkgName, dependentModuleInfo); + } else { + throwCollectionError(pkgName); + } + break; + case ARKTS_HYBRID: + if (dependentModuleInfo.declgenV2OutPath && dependentModuleInfo.declFilesPath && dependentModuleInfo.declgenBridgeCodePath) { + arkTSHybridModuleMap.set(pkgName, dependentModuleInfo); + } else { + throwCollectionError(pkgName); + } + break; + case ARKTS_1_1: + case ARKTS_1_0: + if (dependentModuleInfo.declgenV2OutPath && dependentModuleInfo.declFilesPath) { + arkTSModuleMap.set(pkgName, dependentModuleInfo); + } else { + throwCollectionError(pkgName); + } + break; } } } @@ -202,21 +231,52 @@ export function genCachePathForBridgeCode(moduleId: string, metaInfo: Object, ca } export function getDeclgenBridgeCodePath(pkgName: string): string { - if (arkTSEvolutionModuleMap.size && arkTSEvolutionModuleMap.get(pkgName)) { - const arkTSEvolutionModuleInfo: ArkTSEvolutionModule = arkTSEvolutionModuleMap.get(pkgName); + const combinedMap = new Map([...arkTSEvolutionModuleMap, ...arkTSHybridModuleMap]); + if (combinedMap.size && combinedMap.get(pkgName)) { + const arkTSEvolutionModuleInfo: ArkTSEvolutionModule = combinedMap.get(pkgName); return arkTSEvolutionModuleInfo.declgenBridgeCodePath; } return ''; } function getDeclgenV2OutPath(pkgName: string): string { - if (arkTSModuleMap.size && arkTSModuleMap.get(pkgName)) { - const arkTsModuleInfo: ArkTSEvolutionModule = arkTSModuleMap.get(pkgName); + const combinedMap = new Map([...arkTSModuleMap, ...arkTSHybridModuleMap]); + if (combinedMap.size && combinedMap.get(pkgName)) { + const arkTsModuleInfo: ArkTSEvolutionModule = combinedMap.get(pkgName); return arkTsModuleInfo.declgenV2OutPath; } return ''; } +export function isArkTSEvolutionFile(filePath: string, metaInfo: Object): boolean { + if (metaInfo.language === ARKTS_1_0 || metaInfo.language === ARKTS_1_1) { + return false; + } + + if (metaInfo.language === ARKTS_1_2) { + return true; + } + + if (metaInfo.language === ARKTS_HYBRID || arkTSHybridModuleMap.has(metaInfo.pkgName)) { + const hybridModule = arkTSHybridModuleMap.get(metaInfo.pkgName); + if (!hybridModule) { + return false; + } + + const normalizedFilePath = toUnixPath(filePath); + const staticFileList = hybridModule.staticFiles || []; + + // Concatenate the corresponding source code path based on the bridge code path. + const declgenCodeBrigdePath = path.join(toUnixPath(hybridModule.declgenBridgeCodePath), metaInfo.pkgName); + let moduleId = normalizedFilePath.replace(toUnixPath(declgenCodeBrigdePath), toUnixPath(metaInfo.pkgPath)); + const arktsEvolutionFile = moduleId.replace(new RegExp(`\\${EXTNAME_TS}$`), EXTNAME_ETS); + + return new Set(staticFileList.map(toUnixPath)).has(arktsEvolutionFile); + } + + return false; +} + export function interopTransform(program: ts.Program, id: string, mixCompile: boolean): ts.TransformerFactory { if (!mixCompile || /\.ts$/.test(id)) { return () => sourceFile => sourceFile; @@ -258,7 +318,8 @@ export function interopTransform(program: ts.Program, id: string, mixCompile: bo function isFromArkTSEvolutionModule(node: ts.Node): boolean { const sourceFile: ts.SourceFile = node.getSourceFile(); const filePath: string = toUnixPath(sourceFile.fileName); - for (const arkTSEvolutionModuleInfo of arkTSEvolutionModuleMap.values()) { + const combinedMap = new Map([...arkTSEvolutionModuleMap, ...arkTSHybridModuleMap]); + for (const arkTSEvolutionModuleInfo of combinedMap.values()) { const declgenV1OutPath: string = toUnixPath(arkTSEvolutionModuleInfo.declgenV1OutPath); if (filePath.startsWith(declgenV1OutPath + '/')) { const relative: string = filePath.replace(declgenV1OutPath + '/', '').replace(/\.d\.ets$/, '');