diff --git a/ets2panda/driver/build_system/src/build/base_mode.ts b/ets2panda/driver/build_system/src/build/base_mode.ts index abeb5ba7b8533042cbb7196ce9dc7d0e6e369515..153b439c86bf6b524866964edfe9b68f0800742d 100644 --- a/ets2panda/driver/build_system/src/build/base_mode.ts +++ b/ets2panda/driver/build_system/src/build/base_mode.ts @@ -68,7 +68,7 @@ import { ModuleInfo, ES2PANDA_MODE } from '../types'; -import { ArkTSConfigGenerator } from './generate_arktsconfig'; +import { ArkTSConfig, ArkTSConfigGenerator } from './generate_arktsconfig'; import { SetupClusterOptions } from '../types'; import { KitImportTransformer } from '../plugins/KitImportTransformer'; @@ -252,7 +252,7 @@ export abstract class BaseMode { // if aliasConfig is set, transform aliasName@kit.xxx to default@ohos.xxx through the plugin this.logger.printInfo('Transforming import statements with alias config'); let transformAst = new KitImportTransformer(arkts, arktsGlobal.compilerContext.program, - this.buildConfig.buildSdkPath,this.buildConfig.aliasConfig).transform(ast); + this.buildConfig.buildSdkPath, this.buildConfig.aliasConfig).transform(ast); PluginDriver.getInstance().getPluginContext().setArkTSAst(transformAst); } else { PluginDriver.getInstance().getPluginContext().setArkTSAst(ast); @@ -447,10 +447,33 @@ export abstract class BaseMode { } protected generateArkTSConfigForModules(): void { + let taskList: ModuleInfo[] = []; this.moduleInfos.forEach((moduleInfo: ModuleInfo, moduleRootPath: string) => { + if (moduleInfo.dependenciesSet.size === 0) { + taskList.push(moduleInfo); + } + ArkTSConfigGenerator.getInstance(this.buildConfig, this.moduleInfos) - .writeArkTSConfigFile(moduleInfo, this.enableDeclgenEts2Ts, this.buildConfig); + .generateArkTSConfigFile(moduleInfo, this.enableDeclgenEts2Ts); }); + + while(taskList.length>0){ + const task = taskList.pop(); + const arktsConfig = ArkTSConfigGenerator.getInstance().getArktsConfigPackageName(task!!.packageName) + task?.dependencies?.forEach(dependecyModule=>{ + arktsConfig?.mergeArktsConfig( + ArkTSConfigGenerator.getInstance().getArktsConfigPackageName(dependecyModule) + ); + }); + fs.writeFileSync(task!!.arktsConfigFile,JSON.stringify(arktsConfig!!.getCompilerOptions(), null, 2)) + task?.dependenciesSet.forEach((dependentTask) => { + const dependentModule = this.moduleInfos.get(dependentTask); + dependentModule?.dependenciesSet.delete(task.packageName); + if(dependentModule?.dependenciesSet.size ===0){ + taskList.push(dependentModule); + } + }); + } } private collectDepModuleInfos(): void { @@ -458,7 +481,16 @@ export abstract class BaseMode { let [dynamicDepModules, staticDepModules] = this.getDependentModules(moduleInfo); moduleInfo.dynamicDepModuleInfos = dynamicDepModules; moduleInfo.staticDepModuleInfos = staticDepModules; + + [...dynamicDepModules.keys(), ...staticDepModules.keys()].forEach(depName => { + moduleInfo.dependenciesSet.add(depName); + }); + moduleInfo.dependenciesSet.delete(moduleInfo.packageName); + moduleInfo.dependencies?.forEach(moduleName => { + this.moduleInfos.get(moduleName)?.dependentSet.add(moduleInfo.packageName); + }); }); + } protected collectModuleInfos(): void { @@ -500,7 +532,9 @@ export abstract class BaseMode { declFilesPath: module.declFilesPath, dependencies: module.dependencies, byteCodeHar: module.byteCodeHar, - abcPath: module.abcPath + abcPath: module.abcPath, + dependenciesSet: new Set(mainModuleInfo?.dependencies), + dependentSet: new Set(), }; this.moduleInfos.set(module.packageName, moduleInfo); }); @@ -526,6 +560,8 @@ export abstract class BaseMode { byteCodeHar: this.byteCodeHar, language: mainModuleInfo?.language ?? LANGUAGE_VERSION.ARKTS_1_2, declFilesPath: mainModuleInfo?.declFilesPath, + dependentSet: new Set(), + dependenciesSet: new Set(mainModuleInfo?.dependencies) }; } @@ -634,7 +670,7 @@ export abstract class BaseMode { } }); this.collectAbcFileFromByteCodeHar(); - + while (queue.length > 0) { const currentFile = queue.shift()!; processed.add(currentFile); diff --git a/ets2panda/driver/build_system/src/build/generate_arktsconfig.ts b/ets2panda/driver/build_system/src/build/generate_arktsconfig.ts index ec26e841675e95e2bc475aab66c2d206805ed39f..ee85bea03bfa177dc74acfc11e16e33e49d854cc 100644 --- a/ets2panda/driver/build_system/src/build/generate_arktsconfig.ts +++ b/ets2panda/driver/build_system/src/build/generate_arktsconfig.ts @@ -35,6 +35,7 @@ import { } from '../utils'; import { AliasConfig, + ArkTSConfigObject, BuildConfig, DependencyItem, DynamicFileContext, @@ -48,16 +49,80 @@ import { sdkConfigPrefix, } from '../pre_define'; -interface ArkTSConfigObject { - compilerOptions: { - package: string, - baseUrl: string, - paths: Record; - entry?: string; - dependencies: Record; - useEmptyPackage?: boolean; +export class ArkTSConfig { + config: ArkTSConfigObject; + + constructor(moduleInfo: ModuleInfo) { + this.config = { + compilerOptions: { + package: moduleInfo.packageName, + baseUrl: path.resolve(moduleInfo.moduleRootPath, moduleInfo.sourceRoots[0]), + paths: {}, + entry: moduleInfo.entryFile, + dependencies: {} + } + }; + } + + addPathMappings(mappings: Record): void { + const paths = this.config.compilerOptions.paths; + for (const [key, value] of Object.entries(mappings)) { + if (paths[key]) { + paths[key] = [...new Set([...paths[key], ...value])]; + } + } + } + + addDependency({ name, item }: { name: string; item: DependencyItem }): void { + const deps = this.config.compilerOptions.dependencies; + const existing = deps[name]; + + if (existing) { + const mergedAlias = Array.from(new Set([...(existing.alias ?? []), ...(item.alias ?? [])])); + deps[name] = { + ...existing, + ...item, + alias: mergedAlias + }; + } else { + deps[name] = item; + } + } + + addDependencies(deps: Record): void { + Object.entries(deps).forEach(([name, item]) => { + this.addDependency({ name, item }); + }); + } + + getCompilerOptions(): ArkTSConfigObject["compilerOptions"] { + return this.config.compilerOptions; } -}; + + getPackageName(): string { + return this.config.compilerOptions.package; + } + + getDependencies():Record{ + return this.config.compilerOptions.dependencies; + } + + getPathSection():Record{ + return this.config.compilerOptions.paths; + } + + setUseEmptyPackage(value: boolean = false): void { + this.config.compilerOptions.useEmptyPackage = value; + } + + mergeArktsConfig(source:ArkTSConfig|undefined):void{ + if(!source){ + return; + } + this.addDependencies(source.getDependencies()); + this.addPathMappings(source.getPathSection()); + } +} export class ArkTSConfigGenerator { private static instance: ArkTSConfigGenerator | undefined; @@ -65,13 +130,14 @@ export class ArkTSConfigGenerator { private stdlibEscompatPath: string; private systemSdkPath: string; private externalApiPaths: string[]; - - private moduleInfos: Map; - private pathSection: Record; - private logger: Logger; private aliasConfig: Map>; + private moduleInfos: Map; + private systemPathSection: Record; + private systemDependenciesSection: Record; private dynamicSDKPaths: Set; + private arktsconfigs: Map; + private buildConfig: BuildConfig; private constructor(buildConfig: BuildConfig, moduleInfos: Map) { this.logger = Logger.getInstance(); @@ -82,11 +148,17 @@ export class ArkTSConfigGenerator { this.stdlibEscompatPath = path.resolve(realPandaStdlibPath, 'escompat'); this.systemSdkPath = path.resolve(realBuildSdkPath, SYSTEM_SDK_PATH_FROM_SDK); this.externalApiPaths = buildConfig.externalApiPaths; + this.buildConfig = buildConfig; this.moduleInfos = moduleInfos; - this.pathSection = {}; this.aliasConfig = buildConfig.aliasConfig; this.dynamicSDKPaths = buildConfig.interopSDKPaths; + + this.systemPathSection = {} + this.systemDependenciesSection = {}; + this.arktsconfigs = new Map(); + + this.initPathInfo(); } public static getInstance(buildConfig?: BuildConfig, moduleInfos?: Map): ArkTSConfigGenerator { @@ -147,90 +219,61 @@ export class ArkTSConfigGenerator { let kitsPath: string = path.resolve(this.systemSdkPath, 'kits'); fs.existsSync(kitsPath) ? traverse(kitsPath) : this.logger.printWarn(`sdk path ${kitsPath} not exist.`); } + pathSection.std = [this.stdlibStdPath]; + pathSection.escompat = [this.stdlibEscompatPath]; } - private getPathSection(moduleInfo: ModuleInfo): Record { - if (Object.keys(this.pathSection).length !== 0) { - return this.pathSection; + private initPathInfo(): void { + this.generateSystemSdkPathSection(this.systemPathSection); + this.generateSystemSdkDependenciesSection(this.systemDependenciesSection); + if (this.buildConfig.paths) { + Object.entries(this.buildConfig.paths).map(([key, value]) => { + this.systemPathSection[key] = value + }); } - - this.pathSection.std = [this.stdlibStdPath]; - this.pathSection.escompat = [this.stdlibEscompatPath]; - - this.generateSystemSdkPathSection(this.pathSection); - - this.moduleInfos.forEach((moduleInfo: ModuleInfo, packageName: string) => { - if (moduleInfo.language !== LANGUAGE_VERSION.ARKTS_1_2 && moduleInfo.language !== LANGUAGE_VERSION.ARKTS_HYBRID) { - return; - } - if (!moduleInfo.entryFile) { - return; - } - this.handleEntryFile(moduleInfo); - }); - return this.pathSection; } - private handleEntryFile(moduleInfo: ModuleInfo): void { - try { - const stat = fs.statSync(moduleInfo.entryFile); - if (!stat.isFile()) { - return; - } - const entryFilePath = moduleInfo.entryFile; - const firstLine = fs.readFileSync(entryFilePath, 'utf-8').split('\n')[0]; - // If the file is an ArkTS 1.2 implementation, configure the path in pathSection. - if (moduleInfo.language === LANGUAGE_VERSION.ARKTS_1_2 || moduleInfo.language === LANGUAGE_VERSION.ARKTS_HYBRID && firstLine.includes('use static')) { - this.pathSection[moduleInfo.packageName] = [ - path.resolve(moduleInfo.moduleRootPath, moduleInfo.sourceRoots[0]) - ]; + private generateSystemSdkDependenciesSection(dependenciesSection: Record): void { + this.dynamicSDKPaths.forEach(basePath => { + if (fs.existsSync(basePath)) { + this.traverseDependencies(basePath, '', false, dependenciesSection); + this.traverseDependencies(basePath, '', false, dependenciesSection, 'dynamic/'); + } else { + this.logger.printWarn(`sdk path ${basePath} not exist.`); } - } catch (error) { - const logData: LogData = LogDataFactory.newInstance( - ErrorCode.BUILDSYSTEM_HANDLE_ENTRY_FILE, - `Error handle entry file for module ${moduleInfo.packageName}` - ); - this.logger.printError(logData); - } + }); } - private getOhmurl(file: string, moduleInfo: ModuleInfo): string { - let unixFilePath: string = file.replace(/\\/g, '/'); - let ohmurl: string = moduleInfo.packageName + '/' + unixFilePath; - return changeFileExtension(ohmurl, ''); - } + private getAllFilesToPathSection( + moduleInfo: ModuleInfo, + arktsConfig: ArkTSConfig + ): void { + const moduleRoot = toUnixPath(moduleInfo.moduleRootPath) + '/'; - private getDependenciesSection(moduleInfo: ModuleInfo, dependenciesection: Record): void { - let depModules: Map = moduleInfo.dynamicDepModuleInfos; + for (const file of this.buildConfig.compileFiles) { + const unixFilePath = toUnixPath(file); - depModules.forEach((depModuleInfo: ModuleInfo) => { - if (!depModuleInfo.declFilesPath || !fs.existsSync(depModuleInfo.declFilesPath)) { - console.error(`Module ${moduleInfo.packageName} depends on dynamic module ${depModuleInfo.packageName}, but - decl file not found on path ${depModuleInfo.declFilesPath}`); - return; + if (!isSubPathOf(unixFilePath, moduleRoot)) { + continue; } - let declFilesObject = JSON.parse(fs.readFileSync(depModuleInfo.declFilesPath, 'utf-8')); - Object.keys(declFilesObject.files).forEach((file: string) => { - let ohmurl: string = this.getOhmurl(file, depModuleInfo); - dependenciesection[ohmurl] = { - language: 'js', - path: declFilesObject.files[file].declPath, - ohmUrl: declFilesObject.files[file].ohmUrl - }; - let absFilePath: string = path.resolve(depModuleInfo.moduleRootPath, file); - let entryFileWithoutExtension: string = changeFileExtension(depModuleInfo.entryFile, ''); - if (absFilePath === entryFileWithoutExtension) { - dependenciesection[depModuleInfo.packageName] = dependenciesection[ohmurl]; - } - }); - }); + let relativePath = unixFilePath.startsWith(moduleRoot) + ? unixFilePath.substring(moduleRoot.length) + : unixFilePath; + + const keyWithoutExtension = relativePath.replace(/\.[^/.]+$/, ''); + arktsConfig.addPathMappings({ [keyWithoutExtension]: [file] }); + } + } + + private getPathSection(moduleInfo: ModuleInfo, arktsconfig: ArkTSConfig): void { + arktsconfig.addPathMappings(this.systemPathSection); + this.getAllFilesToPathSection(moduleInfo, arktsconfig); } - public writeArkTSConfigFile( + public generateArkTSConfigFile( moduleInfo: ModuleInfo, - enableDeclgenEts2Ts: boolean, - buildConfig: BuildConfig + enableDeclgenEts2Ts: boolean ): void { if (!moduleInfo.sourceRoots || moduleInfo.sourceRoots.length === 0) { const logData: LogData = LogDataFactory.newInstance( @@ -239,50 +282,38 @@ export class ArkTSConfigGenerator { ); this.logger.printErrorAndExit(logData); } - let pathSection = this.getPathSection(moduleInfo); + let arktsConfig: ArkTSConfig = new ArkTSConfig(moduleInfo); + this.arktsconfigs.set(moduleInfo.packageName, arktsConfig); + this.getPathSection(moduleInfo, arktsConfig); - this.getAllFilesToPathSectionForHybrid(moduleInfo, buildConfig); - let dependenciesection: Record = {}; if (!enableDeclgenEts2Ts) { - this.getDependenciesSection(moduleInfo, dependenciesection); - } - this.processAlias(moduleInfo, dependenciesection); - let baseUrl: string = path.resolve(moduleInfo.moduleRootPath, moduleInfo.sourceRoots[0]); - if (buildConfig.paths) { - Object.entries(buildConfig.paths).map(([key, value]) => { - pathSection[key] = value - }); - } - let arktsConfig: ArkTSConfigObject = { - compilerOptions: { - package: moduleInfo.packageName, - baseUrl: baseUrl, - paths: pathSection, - entry: moduleInfo.entryFile, - dependencies: dependenciesection - } - }; - - if (moduleInfo.entryFile && moduleInfo.language === LANGUAGE_VERSION.ARKTS_HYBRID) { - const entryFilePath = moduleInfo.entryFile; - const stat = fs.statSync(entryFilePath); - if (fs.existsSync(entryFilePath) && stat.isFile()) { - const firstLine = fs.readFileSync(entryFilePath, 'utf-8').split('\n')[0]; - // If the entryFile is not an ArkTS 1.2 implementation, remove the entry property field. - if (!firstLine.includes('use static')) { - delete arktsConfig.compilerOptions.entry; - } - } + this.getDependenciesSection(moduleInfo, arktsConfig); } + this.processAlias(arktsConfig); if (moduleInfo.frameworkMode) { - arktsConfig.compilerOptions.useEmptyPackage = moduleInfo.useEmptyPackage; + arktsConfig.setUseEmptyPackage(moduleInfo.useEmptyPackage); } ensurePathExists(moduleInfo.arktsConfigFile); - fs.writeFileSync(moduleInfo.arktsConfigFile, JSON.stringify(arktsConfig, null, 2), 'utf-8'); } +<<<<<<< HEAD + private getOhmurl(file: string, moduleInfo: ModuleInfo): string { + let unixFilePath: string = file.replace(/\\/g, '/'); + let ohmurl: string = moduleInfo.packageName + '/' + unixFilePath; + return changeFileExtension(ohmurl, ''); + } + + private getDependenciesSection(moduleInfo: ModuleInfo, arktsconfig: ArkTSConfig): void { + let depModules: Map = moduleInfo.dynamicDepModuleInfos; + + depModules.forEach((depModuleInfo: ModuleInfo) => { + if (!depModuleInfo.declFilesPath || !fs.existsSync(depModuleInfo.declFilesPath)) { + console.error(`Module ${moduleInfo.packageName} depends on dynamic module ${depModuleInfo.packageName}, but + decl file not found on path ${depModuleInfo.declFilesPath}`); + return; +======= private processAlias(moduleInfo: ModuleInfo, dependencySection: Record): void { this.dynamicSDKPaths.forEach(basePath => { if(basePath.includes(KITS)){ @@ -300,19 +331,49 @@ export class ArkTSConfigGenerator { }else{ this.traverseDependencies(basePath, '', false, dependencySection); this.traverseDependencies(basePath, '', false, dependencySection,'dynamic/'); +>>>>>>> 035ac45d22af6601e994d4634884f828c9df9571 } + + const declFilesObject = JSON.parse(fs.readFileSync(depModuleInfo.declFilesPath, 'utf-8')); + const files = declFilesObject.files; + + Object.keys(files).forEach((file: string) => { + const ohmurl: string = this.getOhmurl(file, depModuleInfo); + const depItem: DependencyItem = { + language: 'js', + path: files[file].declPath, + ohmUrl: files[file].ohmUrl + }; + + arktsconfig.addDependency({ + name: ohmurl, + item: depItem + }); + + const absFilePath: string = path.resolve(depModuleInfo.moduleRootPath, file); + const entryFileWithoutExtension: string = changeFileExtension(depModuleInfo.entryFile, ''); + + if (absFilePath === entryFileWithoutExtension) { + arktsconfig.addDependency({ + name: depModuleInfo.packageName, + item: depItem + }); + } + }); }); + } - const aliasForPkg: Map | undefined = this.aliasConfig?.get(moduleInfo.packageName); + private processAlias(arktsconfigs: ArkTSConfig): void { + const aliasForPkg: Map | undefined = this.aliasConfig?.get(arktsconfigs.getPackageName()); aliasForPkg?.forEach((aliasConfig, aliasName) => { - if(aliasConfig.isStatic){ + if (aliasConfig.isStatic) { return; } if (aliasConfig.originalAPIName.startsWith('@kit')) { - this.processStaticAlias(aliasName, aliasConfig); - }else{ - this.processDynamicAlias(aliasName, aliasConfig,dependencySection); + this.processStaticAlias(aliasName, aliasConfig, arktsconfigs); + } else { + this.processDynamicAlias(aliasName, aliasConfig, arktsconfigs); } }); } @@ -326,11 +387,11 @@ export class ArkTSConfigGenerator { ): void { const allowedExtensions = ['.d.ets']; const items = fs.readdirSync(currentDir); - + for (const item of items) { const itemPath = path.join(currentDir, item); const stat = fs.statSync(itemPath); - + if (stat.isFile()) { if (this.isAllowedExtension(item, allowedExtensions)) { this.processDynamicFile({ @@ -344,7 +405,7 @@ export class ArkTSConfigGenerator { } continue; } - + if (stat.isDirectory()) { const isRuntimeAPI = path.basename(currentDir) === 'arkui' && item === 'runtime-api'; const newRelativePath = isRuntimeAPI @@ -370,7 +431,7 @@ export class ArkTSConfigGenerator { const pattern = new RegExp(`^@(${sdkConfigPrefix})\\..+\\.d\\.ets$`, 'i'); return pattern.test(fileName); } - + private buildDynamicKey( baseName: string, relativePath: string, @@ -383,7 +444,7 @@ export class ArkTSConfigGenerator { : (relativePath ? `${relativePath}${separator}${baseName}` : baseName) ); } - + private processDynamicFile(ctx: DynamicFileContext): void { const { filePath, @@ -409,21 +470,33 @@ export class ArkTSConfigGenerator { }; } - private processStaticAlias(aliasName: string, aliasConfig: AliasConfig) { - this.pathSection[aliasName] = [getInteropFilePathByApi(aliasConfig.originalAPIName, this.dynamicSDKPaths)]; + private processStaticAlias( + aliasName: string, + aliasConfig: AliasConfig, + arktsConfig: ArkTSConfig + ): void { + const declPath = getInteropFilePathByApi(aliasConfig.originalAPIName, this.dynamicSDKPaths); + if (!declPath) { + return; + } + + arktsConfig.addPathMappings({ + [aliasName]: [declPath] + }); } private processDynamicAlias( aliasName: string, aliasConfig: AliasConfig, - dependencySection: Record - ) { + arktsConfig: ArkTSConfig + ): void { const originalName = aliasConfig.originalAPIName; const declPath = getInteropFilePathByApi(originalName, this.dynamicSDKPaths); + if (declPath === '') { return; } - + if (!fs.existsSync(declPath)) { const logData: LogData = LogDataFactory.newInstance( ErrorCode.BUILDSYSTEM_INTEROP_SDK_NOT_FIND, @@ -432,43 +505,18 @@ export class ArkTSConfigGenerator { this.logger.printErrorAndExit(logData); } - const existing = dependencySection[originalName]; - - if (existing) { - existing.alias = Array.from(new Set([...(existing.alias ?? []), aliasName])); - } else { - dependencySection[originalName] = { + arktsConfig.addDependency({ + name: originalName, + item: { language: 'js', path: declPath, ohmUrl: getOhmurlByApi(originalName), alias: [aliasName] - }; - } - } - - public getAllFilesToPathSectionForHybrid( - moduleInfo: ModuleInfo, - buildConfig: BuildConfig - ): void { - if (moduleInfo?.language !== LANGUAGE_VERSION.ARKTS_HYBRID) { - return; - } - - const moduleRoot = toUnixPath(moduleInfo.moduleRootPath) + '/'; - - for (const file of buildConfig.compileFiles) { - const unixFilePath = toUnixPath(file); - - if (!isSubPathOf(unixFilePath, moduleRoot)) { - continue; } + }); + } - let relativePath = unixFilePath.startsWith(moduleRoot) - ? unixFilePath.substring(moduleRoot.length) - : unixFilePath; - - const keyWithoutExtension = relativePath.replace(/\.[^/.]+$/, ''); - this.pathSection[keyWithoutExtension] = [file]; - } - } + public getArktsConfigPackageName(packageName: string): ArkTSConfig | undefined { + return this.arktsconfigs.get(packageName); + } } diff --git a/ets2panda/driver/build_system/src/types.ts b/ets2panda/driver/build_system/src/types.ts index 80f3f76ab3aa4b34374fba56991dff878c1ab5d8..00a5f2428f1f8653b99e06b421a036e823fa9ece 100644 --- a/ets2panda/driver/build_system/src/types.ts +++ b/ets2panda/driver/build_system/src/types.ts @@ -227,6 +227,9 @@ export interface ModuleInfo { frameworkMode?: boolean; useEmptyPackage?: boolean; byteCodeHar: boolean; + //for topological order merging + dependenciesSet:Set; + dependentSet:Set; } export type SetupClusterOptions = { @@ -313,4 +316,15 @@ export interface DependencyItem { path: string, ohmUrl: string, alias?:string[] -} \ No newline at end of file +} + +export interface ArkTSConfigObject { + compilerOptions: { + package: string, + baseUrl: string, + paths: Record; + entry?: string; + dependencies: Record; + useEmptyPackage?: boolean; + } +}; \ No newline at end of file