import { DEFAULT_ABILITY_PACKAGE_NAME, PLUGIN_CONFIG_RELATIVE_PATH } from '@ones-open/cli-utils' import { checkProjectFilesExists, getPackageInNodeModulesDir, semverMajor, semverMaxSatisfying, semverGt, } from '@ones-open/cli-utils' import type { ProjectPluginConfig, MajorChange } from '@ones-open/cli-utils' import type { AddCLIOptionsSchema, PackageJson } from '@ones-open/cli-utils' import type { ListrTask } from 'listr' import { cwd } from 'process' type TargetType = 'ability' | 'module' | 'sub-module' | 'event' type AddCommandRawInputParams = { target: TargetType | string } & AddCLIOptionsSchema type Dependencies = PackageJson['dependencies'] interface AddCommandInitialAnswer { target: TargetType targetName?: string targetVersion?: string optional?: boolean } interface AddTasksGetter { (params: { initialAnswer: AddCommandInitialAnswer pluginConfigContent: ProjectPluginConfig currentWorkingDirectory: string }): Promise[]> } const ALLOW_TARGET_TYPES = new Set(['ability', 'module', 'sub-module', 'event']) const RELATIVE_PATHS = [ PLUGIN_CONFIG_RELATIVE_PATH, getPackageInNodeModulesDir('', DEFAULT_ABILITY_PACKAGE_NAME), ] async function validateAddCommandTargetingType({ target }: AddCommandRawInputParams) { if (!ALLOW_TARGET_TYPES.has(target)) throw new Error(`Invalid target type: ${target}`) return true } async function validateProjectCanExecuteAddCommand(currentWorkingDirectory = cwd()) { await checkProjectFilesExists(currentWorkingDirectory, RELATIVE_PATHS) return true } async function getAddCommandInitialAnswer(params: AddCommandRawInputParams) { // For some reason remove the code below // Keep this function here is for future reference return params as AddCommandInitialAnswer } function mergeAndCheckDependency( pluginDependencies: Dependencies, templateDependencies: Dependencies, ) { // 合并后的依赖 const mergedDependency = { ...pluginDependencies, ...templateDependencies } // 记录依赖有 `major` 级变化的信息 const majorChanges: MajorChange[] = [] // 是否有更新依赖包 let shouldUpdateDependency = false // todo 暂只支持 ~^ 限定符 Object.keys(mergedDependency).forEach((key) => { const pluginVersion = pluginDependencies?.[key]?.replace(/[\^~]/g, '') || '' const rawPluginVersion = pluginDependencies?.[key] const templateVersion = templateDependencies?.[key]?.replace(/[\^~]/g, '') || '' const rawTemplateVersion = templateDependencies?.[key] if (pluginVersion && templateVersion && rawPluginVersion && rawTemplateVersion) { const maxVersion = semverMaxSatisfying([pluginVersion, templateVersion], '*') || '' if (rawPluginVersion !== rawTemplateVersion) { if (pluginVersion === templateVersion) { shouldUpdateDependency = true // 版本号相同,^和~,优先取~ // todo 支持更多范围 mergedDependency[key] = `~${maxVersion}` } if (pluginVersion !== maxVersion) { shouldUpdateDependency = true mergedDependency[key] = semverGt(pluginVersion, templateVersion) ? rawPluginVersion : rawTemplateVersion } } if (semverMajor(pluginVersion) !== semverMajor(templateVersion)) { if (pluginVersion !== maxVersion) { majorChanges.push({ key, before: pluginVersion, after: maxVersion, }) } } } if (!pluginVersion && templateVersion) { shouldUpdateDependency = true } }) return { mergedDependency, majorChanges, shouldUpdateDependency, } } export { validateAddCommandTargetingType, validateProjectCanExecuteAddCommand, getAddCommandInitialAnswer, mergeAndCheckDependency, } export type { AddCommandRawInputParams, AddCommandInitialAnswer, AddTasksGetter, TargetType }