@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
369 lines (368 loc) ⢠14.2 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.listWorkspaces = listWorkspaces;
exports.updateWorkspaces = updateWorkspaces;
exports.generateWorkspaceGraph = generateWorkspaceGraph;
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const child_process_1 = require("child_process");
const util_1 = require("util");
const chalk_1 = __importDefault(require("chalk"));
const monorepo_1 = require("../utils/monorepo");
const execAsync = (0, util_1.promisify)(child_process_1.exec);
/**
* List all workspaces in the monorepo
*/
async function listWorkspaces(options = {}) {
const { spinner } = options;
try {
if (spinner) {
spinner.setText('Finding monorepo root...');
}
// Add timeout to prevent hanging
const monorepoRoot = await Promise.race([
(0, monorepo_1.findMonorepoRoot)(),
new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout finding monorepo root')), 5000)),
]);
if (!monorepoRoot) {
throw new Error('Not in a monorepo. Run this command from a monorepo root or workspace.');
}
if (spinner) {
spinner.setText('Loading workspace information...');
}
const workspaces = await (0, monorepo_1.getWorkspaces)(monorepoRoot);
// Filter workspaces based on options
let filteredWorkspaces = workspaces;
if (options.type) {
filteredWorkspaces = filteredWorkspaces.filter(ws => ws.type === options.type);
}
if (options.framework) {
filteredWorkspaces = filteredWorkspaces.filter(ws => ws.framework === options.framework);
}
if (spinner) {
spinner.stop();
}
if (options.json) {
console.log(JSON.stringify(filteredWorkspaces, null, 2));
return;
}
// Display workspaces in a formatted table
console.log(chalk_1.default.cyan('\nš¦ Workspaces\n'));
if (filteredWorkspaces.length === 0) {
console.log(chalk_1.default.yellow('No workspaces found.'));
return;
}
// Group by type
const groupedWorkspaces = filteredWorkspaces.reduce((acc, ws) => {
if (!acc[ws.type])
acc[ws.type] = [];
acc[ws.type].push(ws);
return acc;
}, {});
for (const [type, workspaceList] of Object.entries(groupedWorkspaces)) {
console.log(chalk_1.default.bold(`\n${type.toUpperCase()}S:`));
workspaceList.forEach((ws) => {
const frameworkBadge = ws.framework ? chalk_1.default.blue(`[${ws.framework}]`) : '';
const versionBadge = chalk_1.default.gray(`v${ws.version}`);
console.log(` ${chalk_1.default.green('ā')} ${chalk_1.default.bold(ws.name)} ${frameworkBadge} ${versionBadge}`);
console.log(` ${chalk_1.default.gray(ws.path)}`);
if (ws.dependencies.length > 0) {
const depCount = ws.dependencies.length;
console.log(` ${chalk_1.default.gray(`${depCount} dependencies`)}`);
}
});
}
console.log(chalk_1.default.gray(`\nTotal: ${filteredWorkspaces.length} workspaces`));
}
catch (error) {
if (spinner) {
spinner.fail(chalk_1.default.red('Error listing workspaces'));
}
console.error(chalk_1.default.red('Error listing workspaces:'), error);
throw error;
}
}
/**
* Update dependencies across workspaces
*/
async function updateWorkspaces(options = {}) {
const { spinner } = options;
try {
if (spinner) {
spinner.setText('Finding monorepo root...');
}
const monorepoRoot = await (0, monorepo_1.findMonorepoRoot)();
if (!monorepoRoot) {
throw new Error('Not in a monorepo. Run this command from a monorepo root or workspace.');
}
if (spinner) {
spinner.setText('Loading workspace information...');
}
const workspaces = await (0, monorepo_1.getWorkspaces)(monorepoRoot);
if (options.workspace) {
// Update specific workspace
const workspace = workspaces.find((ws) => ws.name === options.workspace ||
(options.workspace && ws.path.includes(options.workspace)));
if (!workspace) {
throw new Error(`Workspace "${options.workspace}" not found.`);
}
if (spinner) {
spinner.setText(`Updating workspace: ${workspace.name}...`);
}
await updateSingleWorkspace(monorepoRoot, workspace, options);
if (spinner) {
spinner.succeed(chalk_1.default.green(`ā Workspace "${workspace.name}" updated successfully`));
}
}
else {
// Update all workspaces
if (spinner) {
spinner.setText('Updating all workspaces...');
}
for (let i = 0; i < workspaces.length; i++) {
const workspace = workspaces[i];
if (spinner) {
spinner.setText(`Updating ${workspace.name} (${i + 1}/${workspaces.length})...`);
}
await updateSingleWorkspace(monorepoRoot, workspace, options);
}
if (spinner) {
spinner.succeed(chalk_1.default.green('ā All workspaces updated'));
}
}
}
catch (error) {
if (spinner) {
spinner.fail(chalk_1.default.red('Error updating workspaces'));
}
console.error(chalk_1.default.red('Error updating workspaces:'), error);
throw error;
}
}
async function updateSingleWorkspace(monorepoRoot, workspace, options) {
const workspacePath = path.join(monorepoRoot, workspace.path);
if (options.dependency && options.version) {
// Update specific dependency
const depFlag = options.dev ? '--save-dev' : '--save';
const packageManager = await detectPackageManager(monorepoRoot);
let command;
switch (packageManager) {
case 'pnpm':
command = `pnpm add ${depFlag} ${options.dependency}@${options.version}`;
break;
case 'yarn':
command = `yarn add ${depFlag} ${options.dependency}@${options.version}`;
break;
default:
command = `npm install ${depFlag} ${options.dependency}@${options.version}`;
}
await execAsync(command, { cwd: workspacePath });
console.log(chalk_1.default.green(`ā Updated ${options.dependency} to ${options.version} in ${workspace.name}`));
}
else {
// Update all dependencies
const packageManager = await detectPackageManager(monorepoRoot);
let command;
switch (packageManager) {
case 'pnpm':
command = 'pnpm update';
break;
case 'yarn':
command = 'yarn upgrade';
break;
default:
command = 'npm update';
}
await execAsync(command, { cwd: workspacePath });
}
}
/**
* Generate workspace dependency graph
*/
async function generateWorkspaceGraph(options = {}) {
const { spinner } = options;
try {
if (spinner) {
spinner.setText('Finding monorepo root...');
}
const monorepoRoot = await (0, monorepo_1.findMonorepoRoot)();
if (!monorepoRoot) {
throw new Error('Not in a monorepo. Run this command from a monorepo root or workspace.');
}
if (spinner) {
spinner.setText('Loading workspace information...');
}
const workspaces = await (0, monorepo_1.getWorkspaces)(monorepoRoot);
if (spinner) {
spinner.setText('Building dependency graph...');
}
const graph = await buildDependencyGraph(workspaces);
if (spinner) {
spinner.stop();
}
switch (options.format) {
case 'json': {
const jsonOutput = JSON.stringify(graph, null, 2);
if (options.output) {
await fs.writeFile(options.output, jsonOutput);
console.log(chalk_1.default.green(`Graph saved to ${options.output}`));
}
else {
console.log(jsonOutput);
}
break;
}
case 'mermaid': {
const mermaidOutput = generateMermaidGraph(graph);
if (options.output) {
await fs.writeFile(options.output, mermaidOutput);
console.log(chalk_1.default.green(`Mermaid graph saved to ${options.output}`));
}
else {
console.log(mermaidOutput);
}
break;
}
default:
displayTextGraph(graph);
}
}
catch (error) {
if (spinner) {
spinner.fail(chalk_1.default.red('Error generating workspace graph'));
}
console.error(chalk_1.default.red('Error generating workspace graph:'), error);
throw error;
}
}
async function buildDependencyGraph(workspaces) {
const graph = {
nodes: workspaces.map(ws => ({
id: ws.name,
type: ws.type,
framework: ws.framework,
path: ws.path,
})),
edges: [],
};
// Build edges based on package.json dependencies
for (const workspace of workspaces) {
const packageJsonPath = path.join(workspace.path, 'package.json');
try {
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
const allDeps = {
...packageJson.dependencies,
...packageJson.devDependencies,
};
for (const depName of Object.keys(allDeps)) {
const targetWorkspace = workspaces.find(ws => ws.name === depName);
if (targetWorkspace) {
graph.edges.push({
from: workspace.name,
to: targetWorkspace.name,
type: packageJson.dependencies?.[depName] ? 'dependency' : 'devDependency',
});
}
}
}
catch (error) {
// Skip if package.json is not readable
}
}
return graph;
}
function displayTextGraph(graph) {
console.log(chalk_1.default.cyan('\nš Workspace Dependency Graph\n'));
for (const node of graph.nodes) {
const dependencies = graph.edges.filter((edge) => edge.from === node.id);
const dependents = graph.edges.filter((edge) => edge.to === node.id);
console.log(chalk_1.default.bold(`${node.id} (${node.type})`));
if (dependencies.length > 0) {
console.log(chalk_1.default.gray(' Dependencies:'));
dependencies.forEach((dep) => {
const typeColor = dep.type === 'dependency' ? chalk_1.default.green : chalk_1.default.yellow;
console.log(` ${typeColor('ā')} ${dep.to}`);
});
}
if (dependents.length > 0) {
console.log(chalk_1.default.gray(' Dependents:'));
dependents.forEach((dep) => {
console.log(` ${chalk_1.default.blue('ā')} ${dep.from}`);
});
}
console.log();
}
}
function generateMermaidGraph(graph) {
let mermaid = 'graph TD\n';
// Add nodes
for (const node of graph.nodes) {
const shape = getNodeShape(node.type);
mermaid += ` ${node.id}${shape}\n`;
}
// Add edges
for (const edge of graph.edges) {
const style = edge.type === 'dependency' ? '-->' : '-..->';
mermaid += ` ${edge.from} ${style} ${edge.to}\n`;
}
return mermaid;
}
function getNodeShape(type) {
switch (type) {
case 'app':
return '[App]';
case 'package':
return '(Package)';
case 'lib':
return '{Library}';
case 'tool':
return '[[Tool]]';
default:
return '[Unknown]';
}
}
async function detectPackageManager(rootPath) {
if (await fs.pathExists(path.join(rootPath, 'pnpm-lock.yaml'))) {
return 'pnpm';
}
if (await fs.pathExists(path.join(rootPath, 'yarn.lock'))) {
return 'yarn';
}
return 'npm';
}