@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
483 lines (482 loc) โข 25.1 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.testCommandValidation = testCommandValidation;
exports.createCommandValidationSchema = createCommandValidationSchema;
exports.listValidationRules = listValidationRules;
exports.listTransformations = listTransformations;
exports.showCommandValidationSchema = showCommandValidationSchema;
exports.showValidationStats = showValidationStats;
exports.generateValidationTemplate = generateValidationTemplate;
const chalk_1 = __importDefault(require("chalk"));
const spinner_1 = require("../utils/spinner");
const error_handler_1 = require("../utils/error-handler");
const plugin_command_validation_1 = require("../utils/plugin-command-validation");
const plugin_command_registry_1 = require("../utils/plugin-command-registry");
// Test command validation with sample data
async function testCommandValidation(commandName, testData, options = {}) {
const { verbose = false, json = false, dryRun = false, strict = false } = options;
try {
const { Command } = require('commander');
const tempProgram = new Command();
const commandRegistry = (0, plugin_command_registry_1.createPluginCommandRegistry)(tempProgram);
await commandRegistry.initialize();
const validator = (0, plugin_command_validation_1.createCommandValidator)();
const commands = commandRegistry.getCommands();
const command = commands.find(cmd => cmd.definition.name === commandName ||
(cmd.definition.aliases && cmd.definition.aliases.includes(commandName)));
if (!command) {
throw new error_handler_1.ValidationError(`Command '${commandName}' not found`);
}
// Parse test data
let parsedTestData;
try {
parsedTestData = JSON.parse(testData);
}
catch (error) {
throw new error_handler_1.ValidationError(`Invalid test data JSON: ${error instanceof Error ? error.message : String(error)}`);
}
const args = parsedTestData.args || {};
const cmdOptions = parsedTestData.options || {};
// Create a basic validation schema for testing
const schema = (0, plugin_command_validation_1.createValidationSchema)({
strict,
arguments: {},
options: {},
globalRules: []
});
// Register schema for the command
validator.registerSchema(command.id, schema);
// Create mock context
const context = {
command: command.definition,
plugin: { manifest: { name: command.pluginName } },
cli: { program: tempProgram, rootPath: process.cwd(), configPath: '', version: '1.0.0' },
logger: {
debug: (msg) => console.debug(chalk_1.default.gray(msg)),
info: (msg) => console.info(chalk_1.default.blue(msg)),
warn: (msg) => console.warn(chalk_1.default.yellow(msg)),
error: (msg) => console.error(chalk_1.default.red(msg))
},
utils: { path: require('path'), chalk: chalk_1.default, spinner: null }
};
const actionText = dryRun ? 'Simulating validation' : 'Validating';
const spinner = (0, spinner_1.createSpinner)(`${actionText} for command '${commandName}'...`);
spinner.start();
const result = await validator.validateAndTransform(command.id, args, cmdOptions, context);
spinner.stop();
if (json) {
console.log(JSON.stringify({
command: commandName,
valid: result.valid,
errors: result.errors,
warnings: result.warnings,
info: result.info,
transformedArgs: result.transformedArgs,
transformedOptions: result.transformedOptions
}, null, 2));
return;
}
console.log(chalk_1.default.cyan(`\n๐งช Validation Test Results for '${commandName}'\n`));
// Overall result
const statusIcon = result.valid ? chalk_1.default.green('โ') : chalk_1.default.red('โ');
const statusText = result.valid ? 'PASSED' : 'FAILED';
console.log(`${statusIcon} ${statusText}`);
// Input data
console.log(chalk_1.default.yellow('\nInput Data:'));
console.log(` Arguments: ${JSON.stringify(args)}`);
console.log(` Options: ${JSON.stringify(cmdOptions)}`);
// Validation issues
if (result.errors.length > 0 || result.warnings.length > 0 || result.info.length > 0) {
console.log(chalk_1.default.yellow('\nValidation Issues:'));
console.log((0, plugin_command_validation_1.formatValidationResult)(result));
}
else {
console.log(chalk_1.default.green('\nNo validation issues found.'));
}
// Transformed data
if (verbose) {
console.log(chalk_1.default.yellow('\nTransformed Data:'));
console.log(` Arguments: ${JSON.stringify(result.transformedArgs)}`);
console.log(` Options: ${JSON.stringify(result.transformedOptions)}`);
}
if (!result.valid) {
console.log(chalk_1.default.red(`\n๐ก Fix the ${result.errors.length} error(s) above to make the command valid`));
}
}
catch (error) {
throw new error_handler_1.ValidationError(`Failed to test command validation: ${error instanceof Error ? error.message : String(error)}`);
}
}
// Create validation schema for a command
async function createCommandValidationSchema(commandName, schemaDefinition, options = {}) {
const { verbose = false, dryRun = false } = options;
try {
const { Command } = require('commander');
const tempProgram = new Command();
const commandRegistry = (0, plugin_command_registry_1.createPluginCommandRegistry)(tempProgram);
await commandRegistry.initialize();
const validator = (0, plugin_command_validation_1.createCommandValidator)();
const commands = commandRegistry.getCommands();
const command = commands.find(cmd => cmd.definition.name === commandName ||
(cmd.definition.aliases && cmd.definition.aliases.includes(commandName)));
if (!command) {
throw new error_handler_1.ValidationError(`Command '${commandName}' not found`);
}
// Parse schema definition
let parsedSchema;
try {
parsedSchema = JSON.parse(schemaDefinition);
}
catch (error) {
throw new error_handler_1.ValidationError(`Invalid schema JSON: ${error instanceof Error ? error.message : String(error)}`);
}
if (dryRun) {
console.log(chalk_1.default.blue('๐ Schema Validation (Dry Run)'));
console.log(chalk_1.default.yellow('\nSchema would be registered for:'));
console.log(` Command: ${commandName}`);
console.log(` Plugin: ${command.pluginName}`);
console.log(` Arguments: ${Object.keys(parsedSchema.arguments || {}).length}`);
console.log(` Options: ${Object.keys(parsedSchema.options || {}).length}`);
console.log(` Global rules: ${(parsedSchema.globalRules || []).length}`);
console.log(` Transformations: ${(parsedSchema.transformations || []).length}`);
return;
}
// Register the schema
validator.registerSchema(command.id, parsedSchema);
console.log(chalk_1.default.green(`โ Created validation schema for '${commandName}'`));
if (verbose) {
console.log(chalk_1.default.yellow('\nSchema Details:'));
console.log(` Strict mode: ${parsedSchema.strict || false}`);
console.log(` Allow unknown: ${parsedSchema.allowUnknown !== false}`);
console.log(` Fail fast: ${parsedSchema.failFast || false}`);
if (parsedSchema.arguments && Object.keys(parsedSchema.arguments).length > 0) {
console.log(chalk_1.default.yellow('\n Arguments:'));
Object.entries(parsedSchema.arguments).forEach(([name, config]) => {
console.log(` ${name}: ${config.rules.length} rule(s)`);
});
}
if (parsedSchema.options && Object.keys(parsedSchema.options).length > 0) {
console.log(chalk_1.default.yellow('\n Options:'));
Object.entries(parsedSchema.options).forEach(([name, config]) => {
console.log(` ${name}: ${config.rules.length} rule(s)`);
});
}
}
}
catch (error) {
throw new error_handler_1.ValidationError(`Failed to create validation schema: ${error instanceof Error ? error.message : String(error)}`);
}
}
// List available validation rules
async function listValidationRules(options = {}) {
const { verbose = false, json = false } = options;
try {
const validator = (0, plugin_command_validation_1.createCommandValidator)();
const builtInRules = validator.getBuiltInRules();
const ruleDescriptions = {
required: 'Ensures field has a value (not undefined, null, or empty)',
type: 'Validates field type (string, number, boolean, array, object)',
minLength: 'Ensures string field meets minimum length requirement',
maxLength: 'Ensures string field does not exceed maximum length',
min: 'Ensures numeric field meets minimum value requirement',
max: 'Ensures numeric field does not exceed maximum value',
pattern: 'Validates field against regular expression pattern',
enum: 'Ensures field value is one of specified allowed values',
email: 'Validates field as properly formatted email address',
url: 'Validates field as properly formatted URL',
path: 'Validates field as file system path, optionally checking existence',
json: 'Validates field as valid JSON string',
custom: 'Uses custom validation function'
};
if (json) {
const rules = Object.keys(builtInRules).map(name => ({
name,
description: ruleDescriptions[name] || 'No description available',
type: plugin_command_validation_1.ValidationRuleType.CUSTOM
}));
console.log(JSON.stringify(rules, null, 2));
return;
}
console.log(chalk_1.default.cyan('๐ Available Validation Rules\n'));
Object.keys(builtInRules).forEach(ruleName => {
const description = ruleDescriptions[ruleName] || 'No description available';
console.log(chalk_1.default.yellow(ruleName));
console.log(` ${description}`);
if (verbose) {
// Show example usage
switch (ruleName) {
case 'required':
console.log(chalk_1.default.gray(' Example: rules.required("Field is required")'));
break;
case 'type':
console.log(chalk_1.default.gray(' Example: rules.type("string", "Must be a string")'));
break;
case 'minLength':
console.log(chalk_1.default.gray(' Example: rules.minLength(3, "Must be at least 3 characters")'));
break;
case 'pattern':
console.log(chalk_1.default.gray(' Example: rules.pattern(/^[a-z]+$/, "Must be lowercase letters only")'));
break;
case 'enum':
console.log(chalk_1.default.gray(' Example: rules.enum(["red", "green", "blue"], "Must be a valid color")'));
break;
}
}
console.log('');
});
console.log(chalk_1.default.gray(`Total: ${Object.keys(builtInRules).length} built-in rule(s)`));
}
catch (error) {
throw new error_handler_1.ValidationError(`Failed to list validation rules: ${error instanceof Error ? error.message : String(error)}`);
}
}
// List available transformations
async function listTransformations(options = {}) {
const { verbose = false, json = false } = options;
try {
const validator = (0, plugin_command_validation_1.createCommandValidator)();
const builtInTransformations = validator.getBuiltInTransformations();
const transformationDescriptions = {
trim: 'Removes whitespace from start and/or end of string',
lowercase: 'Converts string to lowercase',
uppercase: 'Converts string to uppercase',
camelCase: 'Converts string to camelCase format',
kebabCase: 'Converts string to kebab-case format',
snakeCase: 'Converts string to snake_case format',
parseNumber: 'Converts string to number (integer or float)',
parseBoolean: 'Converts string to boolean value',
parseJSON: 'Parses JSON string to object',
expandPath: 'Expands path shortcuts (~ to home directory)',
resolvePath: 'Resolves path to absolute path',
sanitizeHtml: 'Removes HTML tags from string',
normalizeUrl: 'Normalizes URL format',
custom: 'Uses custom transformation function'
};
if (json) {
const transformations = Object.keys(builtInTransformations).map(name => ({
name,
description: transformationDescriptions[name] || 'No description available',
type: plugin_command_validation_1.TransformationType.CUSTOM
}));
console.log(JSON.stringify(transformations, null, 2));
return;
}
console.log(chalk_1.default.cyan('๐ Available Parameter Transformations\n'));
Object.keys(builtInTransformations).forEach(transformationName => {
const description = transformationDescriptions[transformationName] || 'No description available';
console.log(chalk_1.default.yellow(transformationName));
console.log(` ${description}`);
if (verbose) {
// Show example usage
switch (transformationName) {
case 'trim':
console.log(chalk_1.default.gray(' Example: transforms.trim({ start: true, end: true })'));
break;
case 'parseNumber':
console.log(chalk_1.default.gray(' Example: transforms.parseNumber({ float: true, base: 10 })'));
break;
case 'expandPath':
console.log(chalk_1.default.gray(' Example: transforms.expandPath({ relative: "/home/user" })'));
break;
}
}
console.log('');
});
console.log(chalk_1.default.gray(`Total: ${Object.keys(builtInTransformations).length} built-in transformation(s)`));
}
catch (error) {
throw new error_handler_1.ValidationError(`Failed to list transformations: ${error instanceof Error ? error.message : String(error)}`);
}
}
// Show validation schema for a command
async function showCommandValidationSchema(commandName, options = {}) {
const { verbose = false, json = false } = options;
try {
const { Command } = require('commander');
const tempProgram = new Command();
const commandRegistry = (0, plugin_command_registry_1.createPluginCommandRegistry)(tempProgram);
await commandRegistry.initialize();
const validator = (0, plugin_command_validation_1.createCommandValidator)();
const commands = commandRegistry.getCommands();
const command = commands.find(cmd => cmd.definition.name === commandName ||
(cmd.definition.aliases && cmd.definition.aliases.includes(commandName)));
if (!command) {
throw new error_handler_1.ValidationError(`Command '${commandName}' not found`);
}
// For now, show that no schema is registered (would be expanded when schemas are actually stored)
const mockSchema = {
commandId: command.id,
commandName: command.definition.name,
plugin: command.pluginName,
hasSchema: false,
arguments: {},
options: {},
globalRules: [],
transformations: [],
strict: false,
allowUnknown: true,
failFast: false
};
if (json) {
console.log(JSON.stringify(mockSchema, null, 2));
return;
}
console.log(chalk_1.default.cyan(`๐ Validation Schema for '${commandName}'\n`));
console.log(chalk_1.default.yellow('Command Information:'));
console.log(` Name: ${command.definition.name}`);
console.log(` Plugin: ${command.pluginName}`);
console.log(` Description: ${command.definition.description}`);
console.log(` ID: ${command.id}`);
console.log(chalk_1.default.yellow('\nSchema Status:'));
const statusIcon = mockSchema.hasSchema ? chalk_1.default.green('โ') : chalk_1.default.red('โ');
const statusText = mockSchema.hasSchema ? 'Registered' : 'Not registered';
console.log(` ${statusIcon} ${statusText}`);
if (!mockSchema.hasSchema) {
console.log(chalk_1.default.blue('\n๐ก No validation schema registered for this command'));
console.log(chalk_1.default.gray('Use "plugin create-schema" to create one'));
return;
}
if (verbose) {
console.log(chalk_1.default.yellow('\nSchema Configuration:'));
console.log(` Strict mode: ${mockSchema.strict}`);
console.log(` Allow unknown: ${mockSchema.allowUnknown}`);
console.log(` Fail fast: ${mockSchema.failFast}`);
console.log(` Arguments: ${Object.keys(mockSchema.arguments).length}`);
console.log(` Options: ${Object.keys(mockSchema.options).length}`);
console.log(` Global rules: ${mockSchema.globalRules.length}`);
console.log(` Transformations: ${mockSchema.transformations.length}`);
}
}
catch (error) {
throw new error_handler_1.ValidationError(`Failed to show validation schema: ${error instanceof Error ? error.message : String(error)}`);
}
}
// Show validation statistics
async function showValidationStats(options = {}) {
const { verbose = false, json = false } = options;
try {
const validator = (0, plugin_command_validation_1.createCommandValidator)();
const stats = validator.getValidationStats();
if (json) {
console.log(JSON.stringify(stats, null, 2));
return;
}
console.log(chalk_1.default.cyan('๐ Validation System Statistics\n'));
console.log(chalk_1.default.yellow('Overview:'));
console.log(` Total schemas: ${stats.totalSchemas}`);
console.log(` Cache size: ${stats.cacheSize}`);
console.log(` Cache hit rate: ${Math.round(stats.cacheHitRate * 100)}%`);
if (verbose) {
console.log(chalk_1.default.yellow('\nPerformance:'));
console.log(` Total validations: ${stats.validationCount}`);
console.log(` Total errors: ${stats.errorCount}`);
console.log(` Total warnings: ${stats.warningCount}`);
console.log(` Average validation time: ${stats.averageValidationTime}ms`);
console.log(chalk_1.default.yellow('\nRule Types:'));
Object.values(plugin_command_validation_1.ValidationRuleType).forEach(ruleType => {
console.log(` ${ruleType}: Available`);
});
console.log(chalk_1.default.yellow('\nTransformation Types:'));
Object.values(plugin_command_validation_1.TransformationType).forEach(transformType => {
console.log(` ${transformType}: Available`);
});
}
}
catch (error) {
throw new error_handler_1.ValidationError(`Failed to show validation statistics: ${error instanceof Error ? error.message : String(error)}`);
}
}
// Generate validation schema template
async function generateValidationTemplate(commandName, options = {}) {
const { verbose = false, json = false } = options;
try {
const { Command } = require('commander');
const tempProgram = new Command();
const commandRegistry = (0, plugin_command_registry_1.createPluginCommandRegistry)(tempProgram);
await commandRegistry.initialize();
const commands = commandRegistry.getCommands();
const command = commands.find(cmd => cmd.definition.name === commandName ||
(cmd.definition.aliases && cmd.definition.aliases.includes(commandName)));
if (!command) {
throw new error_handler_1.ValidationError(`Command '${commandName}' not found`);
}
// Generate template based on command definition
const template = {
strict: false,
allowUnknown: true,
failFast: false,
arguments: {},
options: {},
globalRules: [],
transformations: []
};
// Add argument schemas
if (command.definition.arguments) {
command.definition.arguments.forEach(arg => {
template.arguments[arg.name] = {
rules: [
...(arg.required ? [{
type: plugin_command_validation_1.ValidationRuleType.REQUIRED,
severity: plugin_command_validation_1.ValidationSeverity.ERROR,
message: `${arg.name} is required`
}] : []),
...(arg.type ? [{
type: plugin_command_validation_1.ValidationRuleType.TYPE,
severity: plugin_command_validation_1.ValidationSeverity.ERROR,
message: `${arg.name} must be of type ${arg.type}`
}] : [])
],
transformations: []
};
});
}
// Add option schemas
if (command.definition.options) {
command.definition.options.forEach(opt => {
const optionName = opt.flag.replace(/^-+/, '').replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
template.options[optionName] = {
rules: [
...(opt.required ? [{
type: plugin_command_validation_1.ValidationRuleType.REQUIRED,
severity: plugin_command_validation_1.ValidationSeverity.ERROR,
message: `${opt.flag} is required`
}] : []),
...(opt.type ? [{
type: plugin_command_validation_1.ValidationRuleType.TYPE,
severity: plugin_command_validation_1.ValidationSeverity.ERROR,
message: `${opt.flag} must be of type ${opt.type}`
}] : [])
],
transformations: []
};
});
}
if (json) {
console.log(JSON.stringify(template, null, 2));
return;
}
console.log(chalk_1.default.cyan(`๐ Validation Schema Template for '${commandName}'\n`));
console.log(chalk_1.default.yellow('Generated template:'));
console.log('```json');
console.log(JSON.stringify(template, null, 2));
console.log('```');
if (verbose) {
console.log(chalk_1.default.blue('\n๐ก Usage:'));
console.log('1. Copy the template above');
console.log('2. Customize rules and transformations as needed');
console.log('3. Use "plugin create-schema" to register the schema');
console.log(chalk_1.default.blue('\n๐ Available rule types:'));
console.log(' - required, type, minLength, maxLength, min, max');
console.log(' - pattern, enum, email, url, path, json, custom');
console.log(chalk_1.default.blue('\n๐ Available transformations:'));
console.log(' - trim, lowercase, uppercase, camelCase, kebabCase');
console.log(' - parseNumber, parseBoolean, parseJSON, expandPath');
}
}
catch (error) {
throw new error_handler_1.ValidationError(`Failed to generate validation template: ${error instanceof Error ? error.message : String(error)}`);
}
}