import type { ModuleTypeKey, ProjectPluginConfigModulesField, ProjectPluginConfigSubModulesField, } from '@ones-open/cli-utils' import { MODULE_TYPE } from '@ones-open/utils' import { nanoid } from 'nanoid' type MixinModule = ProjectPluginConfigModulesField | ProjectPluginConfigSubModulesField type MixinModuleInfo = ModuleInfo | SubModuleInfo enum AddTypeForModuleAndEntryIsTrue { root = 'root', subModule = 'subModule', none = 'none', } interface ModuleInfo { module: ProjectPluginConfigModulesField moduleType: string modulePath: string addType?: AddTypeForModuleAndEntryIsTrue } interface SubModuleInfo { module: ProjectPluginConfigSubModulesField moduleType: string modulePath: string addType?: AddTypeForModuleAndEntryIsTrue } /** * Only root module has 'moduleType' property * * We can use it to judge whether it is root module or not */ function isRootModule(module: MixinModule): module is ProjectPluginConfigModulesField { return module.moduleType !== undefined } function getModuleTypeInfo(module: ProjectPluginConfigModulesField) { const { moduleType } = module const moduleTypeInfo = MODULE_TYPE[moduleType] return moduleTypeInfo } /** * Determine whether to generate 'entry' based on root module 'moduleType' and 'addType' */ function isModuleHadEntry( module: MixinModule, addType: AddTypeForModuleAndEntryIsTrue | undefined, ): module is { entry: string } & ProjectPluginConfigModulesField { if (!isRootModule(module)) return true if (addType === AddTypeForModuleAndEntryIsTrue.root) { return true } if ( addType === AddTypeForModuleAndEntryIsTrue.none || addType === AddTypeForModuleAndEntryIsTrue.subModule ) { return false } const moduleTypeInfo = getModuleTypeInfo(module) const hasEntryProperty = 'entry' in moduleTypeInfo && !!moduleTypeInfo.entry return hasEntryProperty } function doesModuleHasModuleAndEntry(module: ProjectPluginConfigModulesField) { const moduleTypeInfo = getModuleTypeInfo(module) as { modules?: boolean; entry?: boolean } return moduleTypeInfo.modules === true && moduleTypeInfo.entry === true } /** * Determine whether to generate 'subModule' based on root module 'moduleType' */ function isModuleHadSubModule( module: MixinModule, ): module is { modules: ProjectPluginConfigSubModulesField[] } & ProjectPluginConfigModulesField { if (!isRootModule(module)) return true /** * If the root module's module type has 'modules' and 'entry' properties in config and the module has 'entry' property, * this means this module is a root module and should not generate 'subModule'. * * For example, the `ones:app:new` module, if the developer wants to replace whole right zone includes the topbar, it * should not generate 'subModule' for it. */ if (doesModuleHasModuleAndEntry(module) && module.entry) { return false } const moduleTypeInfo = getModuleTypeInfo(module) const hasModulesProperty = 'modules' in moduleTypeInfo return hasModulesProperty } function generateModuleId(moduleType: string) { return `${moduleType.replace(/:/g, '-')}-${nanoid(4)}` } function getAndCollectAllModuleId(modules: MixinModule[]) { const moduleIds: string[] = [] const moduleIdToPath = new Map() const moduleIdToType = new Map() const moduleIdToModuleRef = new Map() const moduleIdToRootModuleRef = new Map() let currentModuleType: ModuleTypeKey let currentRootModule: MixinModule const dfs = (module: MixinModule, modulePath: string) => { if (isRootModule(module)) { currentModuleType = module.moduleType currentRootModule = module if (isModuleHadSubModule(module)) { moduleIds.push(module.id) } } else { moduleIds.push(module.id) } const newModulePath = `${modulePath}${module.id}/` moduleIdToType.set(module.id, currentModuleType) moduleIdToPath.set(module.id, newModulePath) moduleIdToModuleRef.set(module.id, module) moduleIdToRootModuleRef.set(module.id, currentRootModule) if (Array.isArray(module.modules)) { module.modules.forEach((module) => dfs(module, newModulePath)) } } modules.forEach((module) => dfs(module, '')) return { moduleIds, moduleIdToPath, moduleIdToType, moduleIdToModuleRef, moduleIdToRootModuleRef } } export type { MixinModule, MixinModuleInfo, ModuleInfo, SubModuleInfo } export { isRootModule, isModuleHadEntry, isModuleHadSubModule, getModuleTypeInfo, generateModuleId, getAndCollectAllModuleId, AddTypeForModuleAndEntryIsTrue, doesModuleHasModuleAndEntry, }