import type { MixinModuleInfo } from '@/scripts/mf-modules' import type { ProjectPluginConfig, RelateModule, ProjectPluginConfigModulesField, AbilityTemplateSchema, ProjectPluginConfigAbilitiesField, } from '@ones-open/cli-utils' import { MODULE_TYPE } from '@ones-open/utils' import { cloneDeep } from '@senojs/lodash' import enquirer from 'enquirer' import inquirer from 'inquirer' import { relative } from 'path' import { getAddModuleInfo } from '../module' function generateExistsModuleMap( existsModules?: ProjectPluginConfigModulesField[], ): Map { const map = new Map() if (!existsModules) { return map } existsModules.forEach((module) => { const { moduleType } = module map.set(moduleType, (map.get(moduleType) || []).concat(module)) }) return map } async function getIsUseExistModule(moduleType: string) { const { isUseExistModule } = await inquirer.prompt<{ isUseExistModule: boolean }>({ type: 'confirm', name: 'isUseExistModule', message: `Do you want to bind existing modules of type '${moduleType}'?`, default: true, }) return isUseExistModule } async function getTargetModule(modules: ProjectPluginConfigModulesField[]) { const moduleIdMap = modules.map((module) => module.id) const { id } = await enquirer.prompt<{ id: string }>({ type: 'autocomplete', name: 'id', message: 'Please select the module you want to binded:', choices: moduleIdMap, }) const matchModule = modules.find((module) => module.id === id) if (!matchModule) throw new Error(`Module ${id} not found`) return matchModule } async function getBindRelateModuleInfo( currentPluginConfig: ProjectPluginConfig, abilityPluginConfig: Partial, ) { const { abilities = [] } = abilityPluginConfig const ability = abilities[0] as ProjectPluginConfigAbilitiesField const relateModule = ability.relateModule as RelateModule const tailModule: MixinModuleInfo[] = [] const newRelateModule: RelateModule = {} const existsModuleTypeMap = generateExistsModuleMap(currentPluginConfig.modules) let currentConfigContent = cloneDeep(currentPluginConfig) for (const [componentKey, moduleType] of Object.entries(relateModule)) { const existModules = existsModuleTypeMap.get(moduleType) if (existModules) { const isUseExistModule = await getIsUseExistModule(moduleType) // use exist module if (isUseExistModule) { const matchModule = await getTargetModule(existModules) newRelateModule[componentKey] = matchModule.id continue } } // add module const { pluginConfigContent, tailModuleInfo } = await getAddModuleInfo({ initialAnswer: { target: 'module', targetName: moduleType, optional: false }, pluginConfigContent: currentConfigContent, }) // Update apability Associated Module ID newRelateModule[componentKey] = tailModuleInfo.modulePath.split('/')[0] // Update module config currentConfigContent = pluginConfigContent // collect module tailModule.push(tailModuleInfo) } const newAbility = cloneDeep(ability) newAbility.relateModule = newRelateModule // Update configuration related to capabilities abilityPluginConfig.abilities = [newAbility] return { tailModule, pluginConfig: currentConfigContent, abilityPluginConfig, } } function getAbilityRelateModule(yamlContent: AbilityTemplateSchema) { const { templates } = yamlContent // a template contains only one ability return templates?.abilities?.[0]?.relateModule } function checkRelateModule( relateModule: RelateModule, yamlPath: string, currentWorkingDirectory: string, ) { const errorMessage = [] for (const key in relateModule) { const moduleType = relateModule[key] if (moduleType in MODULE_TYPE) { continue } errorMessage.push(`${key}: '${moduleType}' is a invalid moduleType`) } if (errorMessage.length) { const header = `Invalid relateModule in ${relative(currentWorkingDirectory, yamlPath)}\n` throw new Error(header + errorMessage.join('\n')) } } export { getAbilityRelateModule, checkRelateModule, getBindRelateModuleInfo }