feat: add argument parsing and module resolution for assistant app
- Implemented argument parsing in args.ts to handle root, home, and help options. - Added parseHomeArg and parseHelpArg functions for command line argument handling. - Created ModuleResolver class in assistant-app-resolve.ts to resolve module paths, including scoped packages and relative paths. - Introduced caching mechanism for package.json reads to improve performance. - Added utility functions for checking file existence and clearing the cache.
This commit is contained in:
79
assistant/src/command/plugins/install.ts
Normal file
79
assistant/src/command/plugins/install.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { program, Command, assistantConfig } from '@/program.ts';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { parseHomeArg, HomeConfigDir } from '@/module/assistant/config/args.ts';
|
||||
import { execCommand } from '@/module/npm-install.ts';
|
||||
|
||||
/**
|
||||
* 解析包名,分离出安装包名和配置名称
|
||||
* 例如: @kevisual/cnb/routes -> pkgName: @kevisual/cnb, configName: routes
|
||||
* 例如: react -> pkgName: react, configName: react
|
||||
*/
|
||||
function parsePluginName(name: string): { pkgName: string; configName: string } {
|
||||
if (name.startsWith('@') && name.includes('/')) {
|
||||
const parts = name.split('/');
|
||||
if (parts.length >= 3) {
|
||||
// @scope/package/submodule -> pkgName: @scope/package, configName: @scope/package/submodule
|
||||
return {
|
||||
pkgName: parts.slice(0, 2).join('/'),
|
||||
configName: name,
|
||||
};
|
||||
}
|
||||
}
|
||||
return { pkgName: name, configName: name };
|
||||
}
|
||||
|
||||
const pluginCommand = new Command('plugin');
|
||||
|
||||
const installCommand = new Command('install')
|
||||
.alias('i')
|
||||
.argument('<plugin-name>')
|
||||
.description('安装Routes插件').action(async (name, options) => {
|
||||
const { pkgName, configName } = parsePluginName(name);
|
||||
const m = parseHomeArg(HomeConfigDir);
|
||||
const cwd = m.isDev ? process.cwd() : m.configDir;
|
||||
const shellCommand = `pnpm i ${pkgName} -w`;
|
||||
const result = execCommand(shellCommand, { cwd });
|
||||
if (result.status === 0) {
|
||||
const mount = assistantConfig.checkMounted();
|
||||
const config = assistantConfig.getConfig();
|
||||
const routes = config.routes || [];
|
||||
if (!routes.includes(configName)) {
|
||||
routes.push(configName);
|
||||
config.routes = routes;
|
||||
assistantConfig.setConfig(config);
|
||||
console.log(`插件 ${configName} 安装成功并已添加到配置中。`);
|
||||
} else {
|
||||
console.log(`插件 ${configName} 已存在于配置中。`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const uninstallCommand = new Command('remove')
|
||||
.alias('r')
|
||||
.argument('<plugin-name>')
|
||||
.description('卸载Routes插件').action(async (name, options) => {
|
||||
const { pkgName, configName } = parsePluginName(name);
|
||||
const m = parseHomeArg(HomeConfigDir);
|
||||
const cwd = m.isDev ? process.cwd() : m.configDir;
|
||||
const shellCommand = `pnpm remove ${pkgName} -w`;
|
||||
const result = execCommand(shellCommand, { cwd });
|
||||
assistantConfig.checkMounted();
|
||||
const config = assistantConfig.getConfig();
|
||||
let routes = config.routes || [];
|
||||
// 从配置中移除时,查找匹配的配置名称
|
||||
const index = routes.findIndex(r => r === configName);
|
||||
if (index !== -1) {
|
||||
routes.splice(index, 1);
|
||||
config.routes = routes;
|
||||
assistantConfig.setConfig(config);
|
||||
console.log(`插件 ${configName} 卸载成功并已从配置中移除。`);
|
||||
} else {
|
||||
console.log(`插件 ${configName} 不存在于配置中。`);
|
||||
}
|
||||
});
|
||||
|
||||
pluginCommand.addCommand(uninstallCommand);
|
||||
|
||||
pluginCommand.addCommand(installCommand);
|
||||
|
||||
program.addCommand(pluginCommand);
|
||||
Reference in New Issue
Block a user