@re-shell/cli
Version:
Full-stack development platform uniting microservices and microfrontends. Build complete applications with .NET (ASP.NET Core Web API, Minimal API), Java (Spring Boot, Quarkus, Micronaut, Vert.x), Rust (Actix-Web, Warp, Rocket, Axum), Python (FastAPI, Dja
402 lines (401 loc) ⢠18.8 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveDependencies = resolveDependencies;
exports.showDependencyTree = showDependencyTree;
exports.checkConflicts = checkConflicts;
exports.validateVersions = validateVersions;
exports.updateDependencies = updateDependencies;
const chalk_1 = __importDefault(require("chalk"));
const spinner_1 = require("../utils/spinner");
const error_handler_1 = require("../utils/error-handler");
const plugin_dependency_1 = require("../utils/plugin-dependency");
const plugin_system_1 = require("../utils/plugin-system");
// Resolve dependencies for a plugin
async function resolveDependencies(pluginName, options = {}) {
const { verbose = false, json = false, strategy = 'strict', allowPrerelease = false, ignoreOptional = false, autoInstall = false, dryRun = false } = options;
try {
const registry = (0, plugin_system_1.createPluginRegistry)();
await registry.initialize();
const plugin = registry.getPlugin(pluginName);
if (!plugin) {
throw new error_handler_1.ValidationError(`Plugin '${pluginName}' not found`);
}
const resolver = (0, plugin_dependency_1.createDependencyResolver)({
strategy,
allowPrerelease,
ignoreOptional,
autoInstall: autoInstall && !dryRun
});
// Register all available plugins with resolver
const allPlugins = registry.getPlugins();
allPlugins.forEach(p => resolver.registerPlugin(p));
const spinner = (0, spinner_1.createSpinner)(`Resolving dependencies for ${pluginName}...`);
spinner.start();
const result = await resolver.resolveDependencies(plugin.manifest, {
strategy,
allowPrerelease,
ignoreOptional,
autoInstall: autoInstall && !dryRun
});
spinner.stop();
if (json) {
console.log(JSON.stringify(result, null, 2));
return;
}
console.log(chalk_1.default.cyan(`\nš Dependency Resolution for ${pluginName}\n`));
displayResolutionResult(result, verbose);
if (dryRun && autoInstall) {
console.log(chalk_1.default.yellow('\nš Installation Plan (Dry Run):\n'));
displayInstallationPlan(result.installationPlan);
}
}
catch (error) {
throw new error_handler_1.ValidationError(`Dependency resolution failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
// Show dependency tree for a plugin
async function showDependencyTree(pluginName, options = {}) {
const { verbose = false, json = false } = options;
try {
const registry = (0, plugin_system_1.createPluginRegistry)();
await registry.initialize();
const resolver = (0, plugin_dependency_1.createDependencyResolver)();
// Register all available plugins
const allPlugins = registry.getPlugins();
allPlugins.forEach(p => resolver.registerPlugin(p));
const dependencyGraph = resolver.getDependencyGraph();
if (json) {
const graphData = Array.from(dependencyGraph.entries()).map(([name, node]) => ({
name,
version: node.version,
dependencies: Array.from(node.dependencies),
dependents: Array.from(node.dependents),
resolved: node.resolved,
depth: node.depth
}));
console.log(JSON.stringify(graphData, null, 2));
return;
}
console.log(chalk_1.default.cyan('\nš³ Plugin Dependency Tree\n'));
if (pluginName) {
const node = dependencyGraph.get(pluginName);
if (!node) {
throw new error_handler_1.ValidationError(`Plugin '${pluginName}' not found in dependency graph`);
}
displayDependencyNode(node, dependencyGraph, 0, new Set(), verbose);
}
else {
// Show all top-level plugins (no dependents)
const topLevel = Array.from(dependencyGraph.values())
.filter(node => node.dependents.size === 0)
.sort((a, b) => a.name.localeCompare(b.name));
if (topLevel.length === 0) {
console.log(chalk_1.default.yellow('No plugins found in dependency graph.'));
return;
}
topLevel.forEach(node => {
displayDependencyNode(node, dependencyGraph, 0, new Set(), verbose);
console.log('');
});
}
}
catch (error) {
throw new error_handler_1.ValidationError(`Failed to show dependency tree: ${error instanceof Error ? error.message : String(error)}`);
}
}
// Check for dependency conflicts
async function checkConflicts(options = {}) {
const { verbose = false, json = false, strategy = 'strict' } = options;
try {
const registry = (0, plugin_system_1.createPluginRegistry)();
await registry.initialize();
const resolver = (0, plugin_dependency_1.createDependencyResolver)({ strategy });
// Register all plugins
const allPlugins = registry.getPlugins();
allPlugins.forEach(p => resolver.registerPlugin(p));
const spinner = (0, spinner_1.createSpinner)('Checking for dependency conflicts...');
spinner.start();
const conflicts = [];
const resolutions = [];
// Check each plugin for conflicts
for (const plugin of allPlugins) {
try {
const result = await resolver.resolveDependencies(plugin.manifest);
resolutions.push(result);
conflicts.push(...result.conflicts);
}
catch (error) {
// Plugin has unresolvable conflicts
conflicts.push({
type: 'incompatible',
source: plugin.manifest.name,
target: 'unknown',
requested: 'unknown',
resolution: {
action: 'remove',
target: plugin.manifest.name,
reason: error instanceof Error ? error.message : String(error)
}
});
}
}
spinner.stop();
if (json) {
console.log(JSON.stringify({
conflicts,
totalPlugins: allPlugins.length,
pluginsWithConflicts: resolutions.filter(r => r.conflicts.length > 0).length
}, null, 2));
return;
}
console.log(chalk_1.default.cyan('\nā ļø Dependency Conflict Analysis\n'));
if (conflicts.length === 0) {
console.log(chalk_1.default.green('ā
No dependency conflicts found!'));
console.log(chalk_1.default.gray(`Analyzed ${allPlugins.length} plugins successfully.`));
return;
}
console.log(chalk_1.default.red(`Found ${conflicts.length} dependency conflicts:\n`));
displayConflicts(conflicts, verbose);
// Show resolution suggestions
const resolvableConflicts = conflicts.filter(c => c.resolution);
if (resolvableConflicts.length > 0) {
console.log(chalk_1.default.yellow('\nš” Suggested Resolutions:\n'));
resolvableConflicts.forEach((conflict, index) => {
if (conflict.resolution) {
console.log(`${index + 1}. ${chalk_1.default.cyan(conflict.resolution.action)} ${conflict.resolution.target}`);
if (conflict.resolution.version) {
console.log(` Version: ${conflict.resolution.version}`);
}
console.log(` Reason: ${chalk_1.default.gray(conflict.resolution.reason)}`);
console.log('');
}
});
}
}
catch (error) {
throw new error_handler_1.ValidationError(`Conflict check failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
// Validate dependency versions
async function validateVersions(options = {}) {
const { verbose = false, json = false } = options;
try {
const registry = (0, plugin_system_1.createPluginRegistry)();
await registry.initialize();
const plugins = registry.getPlugins();
const validationResults = [];
const spinner = (0, spinner_1.createSpinner)('Validating plugin versions...');
spinner.start();
for (const plugin of plugins) {
const result = {
plugin: plugin.manifest.name,
version: plugin.manifest.version,
valid: true,
issues: []
};
// Validate version format
const semver = require('semver');
if (!semver.valid(plugin.manifest.version)) {
result.valid = false;
result.issues.push('Invalid version format');
}
// Check for prerelease versions
if (semver.prerelease(plugin.manifest.version)) {
result.issues.push('Prerelease version');
}
// Validate dependency versions
if (plugin.manifest.dependencies) {
Object.entries(plugin.manifest.dependencies).forEach(([name, version]) => {
if (!semver.validRange(version)) {
result.valid = false;
result.issues.push(`Invalid dependency version range: ${name}@${version}`);
}
});
}
// Check for outdated dependencies
if (plugin.manifest.reshell?.plugins) {
Object.entries(plugin.manifest.reshell.plugins).forEach(([name, version]) => {
const depPlugin = registry.getPlugin(name);
if (depPlugin) {
const currentVersion = depPlugin.manifest.version;
if (semver.gt(currentVersion, version)) {
result.issues.push(`Outdated plugin dependency: ${name}@${version} (latest: ${currentVersion})`);
}
}
});
}
validationResults.push(result);
}
spinner.stop();
if (json) {
console.log(JSON.stringify(validationResults, null, 2));
return;
}
console.log(chalk_1.default.cyan('\nš Plugin Version Validation\n'));
const validPlugins = validationResults.filter(r => r.valid);
const invalidPlugins = validationResults.filter(r => !r.valid);
const pluginsWithIssues = validationResults.filter(r => r.issues.length > 0);
console.log(chalk_1.default.green(`ā
Valid plugins: ${validPlugins.length}/${validationResults.length}`));
if (invalidPlugins.length > 0) {
console.log(chalk_1.default.red(`ā Invalid plugins: ${invalidPlugins.length}`));
}
if (pluginsWithIssues.length > 0) {
console.log(chalk_1.default.yellow(`ā ļø Plugins with issues: ${pluginsWithIssues.length}`));
}
if (verbose || invalidPlugins.length > 0) {
console.log('');
validationResults.forEach(result => {
if (!result.valid || (verbose && result.issues.length > 0)) {
const status = result.valid ? chalk_1.default.yellow('ā ļø ') : chalk_1.default.red('ā');
console.log(`${status} ${chalk_1.default.white(result.plugin)} ${chalk_1.default.gray(`v${result.version}`)}`);
result.issues.forEach((issue) => {
const color = result.valid ? chalk_1.default.yellow : chalk_1.default.red;
console.log(` ${color(issue)}`);
});
console.log('');
}
});
}
}
catch (error) {
throw new error_handler_1.ValidationError(`Version validation failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
// Update plugin dependencies
async function updateDependencies(pluginName, options = {}) {
const { verbose = false, dryRun = false } = options;
try {
const registry = (0, plugin_system_1.createPluginRegistry)();
await registry.initialize();
const plugin = registry.getPlugin(pluginName);
if (!plugin) {
throw new error_handler_1.ValidationError(`Plugin '${pluginName}' not found`);
}
const spinner = (0, spinner_1.createSpinner)(`Updating dependencies for ${pluginName}...`);
spinner.start();
// TODO: Implement actual dependency update logic
// This would involve:
// 1. Checking for newer versions of dependencies
// 2. Updating package.json/manifest
// 3. Installing new versions
// 4. Running tests to ensure compatibility
await new Promise(resolve => setTimeout(resolve, 2000)); // Simulate update
spinner.succeed(chalk_1.default.green(`Dependencies updated for ${pluginName}!`));
if (verbose) {
console.log(chalk_1.default.gray('Updated dependencies would be listed here...'));
}
}
catch (error) {
throw new error_handler_1.ValidationError(`Dependency update failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
// Display resolution result
function displayResolutionResult(result, verbose) {
console.log(chalk_1.default.yellow('Resolution Status:'));
console.log(` Success: ${result.success ? chalk_1.default.green('ā') : chalk_1.default.red('ā')}`);
console.log(` Resolved: ${result.resolved.length} dependencies`);
console.log(` Conflicts: ${result.conflicts.length}`);
console.log(` Missing: ${result.missing.length}`);
if (result.circular.length > 0) {
console.log(` Circular: ${result.circular.length} cycles`);
}
if (result.resolved.length > 0) {
console.log(chalk_1.default.yellow('\nResolved Dependencies:'));
result.resolved.forEach(dep => {
const status = dep.resolved ? chalk_1.default.green('ā') : chalk_1.default.red('ā');
console.log(` ${status} ${chalk_1.default.white(dep.name)} ${chalk_1.default.gray(`${dep.version} ā ${dep.resolvedVersion || 'unknown'}`)}`);
if (verbose && dep.conflicts && dep.conflicts.length > 0) {
dep.conflicts.forEach(conflict => {
console.log(` ${chalk_1.default.yellow('ā ļø')} ${conflict.type}: ${conflict.requested} vs ${conflict.available}`);
});
}
});
}
if (result.missing.length > 0) {
console.log(chalk_1.default.red('\nMissing Dependencies:'));
result.missing.forEach(missing => {
console.log(` ${chalk_1.default.red('ā')} ${missing}`);
});
}
if (result.conflicts.length > 0) {
console.log(chalk_1.default.red('\nConflicts:'));
displayConflicts(result.conflicts, verbose);
}
if (result.warnings.length > 0) {
console.log(chalk_1.default.yellow('\nWarnings:'));
result.warnings.forEach(warning => {
console.log(` ${chalk_1.default.yellow('ā ļø')} ${warning}`);
});
}
}
// Display dependency conflicts
function displayConflicts(conflicts, verbose) {
conflicts.forEach((conflict, index) => {
console.log(`${index + 1}. ${chalk_1.default.red(conflict.type)} conflict:`);
console.log(` Source: ${chalk_1.default.white(conflict.source)}`);
console.log(` Target: ${chalk_1.default.white(conflict.target)}`);
console.log(` Requested: ${chalk_1.default.cyan(conflict.requested)}`);
if (conflict.available) {
console.log(` Available: ${chalk_1.default.cyan(conflict.available)}`);
}
if (verbose && conflict.resolution) {
console.log(` Resolution: ${chalk_1.default.yellow(conflict.resolution.action)} ${conflict.resolution.target}`);
if (conflict.resolution.version) {
console.log(` Version: ${conflict.resolution.version}`);
}
console.log(` Reason: ${chalk_1.default.gray(conflict.resolution.reason)}`);
}
console.log('');
});
}
// Display installation plan
function displayInstallationPlan(plan) {
if (plan.length === 0) {
console.log(chalk_1.default.gray('No installation steps required.'));
return;
}
plan.forEach((step, index) => {
const actionColor = step.action === 'install' ? chalk_1.default.green :
step.action === 'upgrade' ? chalk_1.default.blue :
step.action === 'downgrade' ? chalk_1.default.yellow : chalk_1.default.red;
console.log(`${step.order + 1}. ${actionColor(step.action)} ${chalk_1.default.white(step.plugin)} ${chalk_1.default.gray(`v${step.version}`)}`);
if (step.optional) {
console.log(` ${chalk_1.default.gray('(optional)')}`);
}
if (step.dependencies.length > 0) {
console.log(` Dependencies: ${step.dependencies.join(', ')}`);
}
});
}
// Display dependency node in tree format
function displayDependencyNode(node, graph, depth, visited, verbose) {
const indent = ' '.repeat(depth);
const prefix = depth === 0 ? '' : 'āā ';
const status = node.resolved ? chalk_1.default.green('ā') : chalk_1.default.red('ā');
console.log(`${indent}${prefix}${status} ${chalk_1.default.white(node.name)} ${chalk_1.default.gray(`v${node.version}`)}`);
if (verbose) {
console.log(`${indent} Dependencies: ${node.dependencies.size}`);
console.log(`${indent} Dependents: ${node.dependents.size}`);
}
if (visited.has(node.name)) {
console.log(`${indent} ${chalk_1.default.yellow('(circular reference)')}`);
return;
}
visited.add(node.name);
// Show dependencies
const deps = Array.from(node.dependencies).sort();
deps.forEach((depName) => {
const depNode = graph.get(depName);
if (depNode) {
displayDependencyNode(depNode, graph, depth + 1, new Set(visited), verbose);
}
else {
const depIndent = ' '.repeat(depth + 1);
console.log(`${depIndent}āā ${chalk_1.default.red('ā')} ${chalk_1.default.white(depName)} ${chalk_1.default.red('(missing)')}`);
}
});
visited.delete(node.name);
}