UNPKG

@neurolint/cli

Version:

NeuroLint CLI for React/Next.js modernization with advanced 6-layer orchestration and intelligent AST transformations

462 lines (400 loc) 14.8 kB
import chalk from "chalk"; import ora from "ora"; import { table } from "table"; import inquirer from "inquirer"; import { PluginManager } from "../../lib/plugin-manager"; interface PluginOptions { // Common options verbose?: boolean; // Install options force?: boolean; // Create options author?: string; description?: string; // List options enabled?: boolean; disabled?: boolean; } const pluginManager = new PluginManager(); export async function pluginCommand(action: string, target?: string, options: PluginOptions = {}) { try { // Initialize plugin manager await pluginManager.initialize(); switch (action) { case 'install': await installPlugin(target!, options); break; case 'remove': case 'uninstall': await removePlugin(target!, options); break; case 'list': await listPlugins(options); break; case 'enable': await togglePlugin(target!, true, options); break; case 'disable': await togglePlugin(target!, false, options); break; case 'update': await updatePlugin(target, options); break; case 'search': await searchPlugins(target || '', options); break; case 'create': await createPlugin(target!, options); break; case 'info': await showPluginInfo(target!, options); break; default: await showPluginHelp(); } } catch (error) { console.error(chalk.red(`Plugin command failed: ${error instanceof Error ? error.message : 'Unknown error'}`)); process.exit(1); } } async function installPlugin(source: string, options: PluginOptions) { if (!source) { console.error(chalk.red('Plugin source is required')); process.exit(1); } const spinner = ora(`Installing plugin from ${source}...`).start(); try { const result = await pluginManager.installPlugin(source, options); spinner.succeed(`Plugin installed: ${result.plugin.name} v${result.plugin.version}`); if (options.verbose) { console.log(chalk.gray(`Plugin ID: ${result.pluginId}`)); console.log(chalk.gray(`Description: ${result.plugin.description || 'No description'}`)); } } catch (error) { spinner.fail('Plugin installation failed'); throw error; } } async function removePlugin(pluginName: string, options: PluginOptions) { if (!pluginName) { console.error(chalk.red('Plugin name is required')); process.exit(1); } // Confirm removal unless forced if (!options.force) { const { confirmed } = await inquirer.prompt([ { type: 'confirm', name: 'confirmed', message: `Are you sure you want to remove plugin "${pluginName}"?`, default: false } ]); if (!confirmed) { console.log(chalk.yellow('Plugin removal cancelled')); return; } } const spinner = ora(`Removing plugin ${pluginName}...`).start(); try { await pluginManager.removePlugin(pluginName); spinner.succeed(`Plugin removed: ${pluginName}`); } catch (error) { spinner.fail('Plugin removal failed'); throw error; } } async function listPlugins(options: PluginOptions) { const spinner = ora('Loading plugins...').start(); try { const plugins = pluginManager.listPlugins(); spinner.stop(); if (plugins.length === 0) { console.log(chalk.yellow('No plugins installed')); console.log(chalk.gray('Install a plugin with: neurolint plugin install <source>')); return; } // Filter plugins if needed let filteredPlugins = plugins; if (options.enabled !== undefined) { filteredPlugins = plugins.filter(p => p.enabled === options.enabled); } if (filteredPlugins.length === 0) { console.log(chalk.yellow(`No ${options.enabled ? 'enabled' : 'disabled'} plugins found`)); return; } console.log(chalk.white.bold(`\nInstalled Plugins (${filteredPlugins.length})\n`)); // Prepare table data const tableData = [ ['Name', 'Version', 'Status', 'Source', 'Installed'] ]; filteredPlugins.forEach(plugin => { tableData.push([ plugin.name, plugin.version || 'unknown', plugin.enabled ? chalk.green('enabled') : chalk.gray('disabled'), plugin.source || 'unknown', plugin.installedAt ? new Date(plugin.installedAt).toLocaleDateString() : 'unknown' ]); }); console.log(table(tableData, { border: { topBody: chalk.gray('─'), topJoin: chalk.gray('┬'), topLeft: chalk.gray('┌'), topRight: chalk.gray('┐'), bottomBody: chalk.gray('─'), bottomJoin: chalk.gray('┴'), bottomLeft: chalk.gray('└'), bottomRight: chalk.gray('┘'), bodyLeft: chalk.gray('│'), bodyRight: chalk.gray('│'), bodyJoin: chalk.gray('│'), joinBody: chalk.gray('─'), joinLeft: chalk.gray('├'), joinRight: chalk.gray('┤'), joinJoin: chalk.gray('┼') } })); if (options.verbose) { const stats = pluginManager.pluginSystem.getStatistics(); console.log(chalk.gray(`\nPlugin System Statistics:`)); console.log(chalk.gray(` Total Hooks: ${stats.totalHooks}`)); console.log(chalk.gray(` Total Transformers: ${stats.totalTransformers}`)); console.log(chalk.gray(` Total Validators: ${stats.totalValidators}`)); } } catch (error) { spinner.fail('Failed to list plugins'); throw error; } } async function togglePlugin(pluginName: string, enabled: boolean, options: PluginOptions) { if (!pluginName) { console.error(chalk.red('Plugin name is required')); process.exit(1); } const spinner = ora(`${enabled ? 'Enabling' : 'Disabling'} plugin ${pluginName}...`).start(); try { await pluginManager.togglePlugin(pluginName, enabled); spinner.succeed(`Plugin ${pluginName} ${enabled ? 'enabled' : 'disabled'}`); } catch (error) { spinner.fail(`Failed to ${enabled ? 'enable' : 'disable'} plugin`); throw error; } } async function updatePlugin(pluginName?: string, options: PluginOptions) { if (!pluginName) { // Update all plugins const plugins = pluginManager.listPlugins(); if (plugins.length === 0) { console.log(chalk.yellow('No plugins to update')); return; } for (const plugin of plugins) { try { console.log(chalk.blue(`Updating ${plugin.name}...`)); await pluginManager.updatePlugin(plugin.name); } catch (error) { console.warn(chalk.yellow(`Failed to update ${plugin.name}: ${error instanceof Error ? error.message : 'Unknown error'}`)); } } } else { const spinner = ora(`Updating plugin ${pluginName}...`).start(); try { await pluginManager.updatePlugin(pluginName); spinner.succeed(`Plugin updated: ${pluginName}`); } catch (error) { spinner.fail('Plugin update failed'); throw error; } } } async function searchPlugins(query: string, options: PluginOptions) { const spinner = ora(`Searching for plugins: ${query}...`).start(); try { const results = await pluginManager.searchPlugins(query); spinner.stop(); if (results.length === 0) { console.log(chalk.yellow(`No plugins found matching: ${query}`)); return; } console.log(chalk.white.bold(`\nPlugin Search Results (${results.length})\n`)); const tableData = [ ['Name', 'Version', 'Description', 'Downloads'] ]; results.forEach((plugin: any) => { tableData.push([ plugin.name, plugin.version || 'unknown', (plugin.description || 'No description').substring(0, 50) + (plugin.description?.length > 50 ? '...' : ''), plugin.downloads?.toLocaleString() || 'unknown' ]); }); console.log(table(tableData, { border: { topBody: chalk.gray('─'), topJoin: chalk.gray('┬'), topLeft: chalk.gray('┌'), topRight: chalk.gray('┐'), bottomBody: chalk.gray('─'), bottomJoin: chalk.gray('┴'), bottomLeft: chalk.gray('└'), bottomRight: chalk.gray('┘'), bodyLeft: chalk.gray('│'), bodyRight: chalk.gray('│'), bodyJoin: chalk.gray('│'), joinBody: chalk.gray('─'), joinLeft: chalk.gray('├'), joinRight: chalk.gray('┤'), joinJoin: chalk.gray('┼') } })); console.log(chalk.gray(`\nInstall a plugin with: neurolint plugin install <plugin-name>`)); } catch (error) { spinner.fail('Search failed'); throw error; } } async function createPlugin(pluginName: string, options: PluginOptions) { if (!pluginName) { console.error(chalk.red('Plugin name is required')); process.exit(1); } // Validate plugin name if (!/^[a-z][a-z0-9-]*$/.test(pluginName)) { console.error(chalk.red('Plugin name must start with a letter and contain only lowercase letters, numbers, and hyphens')); process.exit(1); } const spinner = ora(`Creating plugin template: ${pluginName}...`).start(); try { // Prompt for additional information if not provided const answers = await inquirer.prompt([ { type: 'input', name: 'description', message: 'Plugin description:', default: options.description || `Custom NeuroLint plugin: ${pluginName}` }, { type: 'input', name: 'author', message: 'Author name:', default: options.author || 'Your Name' }, { type: 'list', name: 'targetLayer', message: 'Primary target layer:', choices: [ { name: 'Layer 1: Configuration fixes', value: 1 }, { name: 'Layer 2: Content cleanup', value: 2 }, { name: 'Layer 3: Component intelligence', value: 3 }, { name: 'Layer 4: Hydration safety', value: 4 }, { name: 'Layer 5: App Router optimization', value: 5 }, { name: 'Layer 6: Quality enforcement', value: 6 } ], default: 3 } ]); await pluginManager.createPluginTemplate(pluginName, { description: answers.description, author: answers.author, targetLayer: answers.targetLayer }); spinner.succeed(`Plugin template created: ${pluginName}`); console.log(chalk.green('\nPlugin template created successfully!')); console.log(chalk.gray('\nNext steps:')); console.log(chalk.gray(` 1. cd ${pluginName}`)); console.log(chalk.gray(` 2. Edit index.js to implement your plugin logic`)); console.log(chalk.gray(` 3. Test with: npm test`)); console.log(chalk.gray(` 4. Install locally: neurolint plugin install .`)); } catch (error) { spinner.fail('Plugin template creation failed'); throw error; } } async function showPluginInfo(pluginName: string, options: PluginOptions) { if (!pluginName) { console.error(chalk.red('Plugin name is required')); process.exit(1); } const spinner = ora(`Loading plugin information: ${pluginName}...`).start(); try { const plugins = pluginManager.listPlugins(); const plugin = plugins.find(p => p.name === pluginName); if (!plugin) { spinner.fail(`Plugin not found: ${pluginName}`); return; } spinner.succeed(`Plugin information loaded: ${pluginName}`); console.log(chalk.white.bold(`\nPlugin Information: ${plugin.name}\n`)); const infoData = [ ['Property', 'Value'], ['Name', plugin.name], ['Version', plugin.version || 'unknown'], ['Description', plugin.description || 'No description'], ['Status', plugin.enabled ? chalk.green('enabled') : chalk.gray('disabled')], ['Source', plugin.source || 'unknown'], ['Installed', plugin.installedAt ? new Date(plugin.installedAt).toLocaleString() : 'unknown'] ]; console.log(table(infoData, { border: { topBody: chalk.gray('─'), topJoin: chalk.gray('┬'), topLeft: chalk.gray('┌'), topRight: chalk.gray('┐'), bottomBody: chalk.gray('─'), bottomJoin: chalk.gray('┴'), bottomLeft: chalk.gray('└'), bottomRight: chalk.gray('┘'), bodyLeft: chalk.gray('│'), bodyRight: chalk.gray('│'), bodyJoin: chalk.gray('│'), joinBody: chalk.gray('─'), joinLeft: chalk.gray('├'), joinRight: chalk.gray('┤'), joinJoin: chalk.gray('┼') } })); if (options.verbose) { const pluginInstance = pluginManager.pluginSystem.getPlugin(plugin.id); if (pluginInstance) { console.log(chalk.gray('\nPlugin Capabilities:')); if (pluginInstance.hooks) { console.log(chalk.gray(` Hooks: ${Object.keys(pluginInstance.hooks).join(', ')}`)); } if (pluginInstance.transformers) { console.log(chalk.gray(` Transformers: ${Object.keys(pluginInstance.transformers).join(', ')}`)); } if (pluginInstance.validators) { console.log(chalk.gray(` Validators: ${Object.keys(pluginInstance.validators).join(', ')}`)); } } } } catch (error) { spinner.fail('Failed to load plugin information'); throw error; } } async function showPluginHelp() { console.log(chalk.white.bold('\nNeuroLint Plugin Management\n')); console.log(chalk.white('Available Commands:')); console.log(chalk.gray(' install <source> Install a plugin from various sources')); console.log(chalk.gray(' remove <name> Remove an installed plugin')); console.log(chalk.gray(' list List all installed plugins')); console.log(chalk.gray(' enable <name> Enable a plugin')); console.log(chalk.gray(' disable <name> Disable a plugin')); console.log(chalk.gray(' update [name] Update plugin(s)')); console.log(chalk.gray(' search <query> Search for plugins in registry')); console.log(chalk.gray(' create <name> Create a new plugin template')); console.log(chalk.gray(' info <name> Show detailed plugin information')); console.log(chalk.white('\nPlugin Sources:')); console.log(chalk.gray(' Local file: ./my-plugin.js')); console.log(chalk.gray(' URL: https://example.com/plugin.js')); console.log(chalk.gray(' Registry: my-custom-plugin')); console.log(chalk.white('\nExamples:')); console.log(chalk.gray(' neurolint plugin install ./my-plugin.js')); console.log(chalk.gray(' neurolint plugin create my-awesome-plugin')); console.log(chalk.gray(' neurolint plugin list --verbose')); console.log(chalk.gray(' neurolint plugin search react')); }