vibe-codex
Version:
CLI tool to install development rules and git hooks with interactive configuration
222 lines (193 loc) ⢠6.21 kB
JavaScript
/**
* Validate command - Run validation checks against configured rules
*/
const chalk = require("chalk");
const ora = require("ora");
const fs = require("fs-extra");
const RuleValidator = require("../validator");
const moduleLoader = require("../modules/loader-wrapper");
const logger = require("../utils/logger");
module.exports = async function validate(options) {
const spinner = ora("Loading configuration...").start();
try {
// Load configuration
const configPath = ".vibe-codex.json";
if (!(await fs.pathExists(configPath))) {
spinner.fail("No vibe-codex configuration found");
console.log(
chalk.yellow('\nRun "npx vibe-codex init" to set up vibe-codex'),
);
return;
}
const config = await fs.readJSON(configPath);
spinner.succeed("Configuration loaded");
console.log(chalk.blue("\nđ Running vibe-codex validation...\n"));
// Initialize module loader
spinner.start("Loading rule modules...");
await moduleLoader.initialize(process.cwd());
const loadedModules = moduleLoader.getLoadedModules();
spinner.succeed(
`Loaded ${loadedModules.length} modules: ${loadedModules.join(", ")}`,
);
// Run validation with modular rules
spinner.start("Checking rules compliance...");
const results = await runModularValidation(options);
spinner.stop();
// Display results
displayResults(results, options);
// Exit with appropriate code
const exitCode = results.violations.length > 0 ? 1 : 0;
process.exitCode = exitCode;
} catch (error) {
spinner.fail(`Validation failed: ${error.message}`);
throw error;
}
};
/**
* Display validation results
* @param {Object} results - Validation results
* @param {Object} options - Display options
*/
function displayResults(results, options) {
// Display violations
if (results.violations.length > 0) {
console.log(chalk.red("\nâ Violations Found:\n"));
results.violations.forEach((violation) => {
console.log(chalk.red(` ⢠[${violation.rule}] ${violation.message}`));
if (violation.fix) {
console.log(chalk.gray(` Fix: ${violation.fix}`));
}
});
}
// Display warnings
if (results.warnings.length > 0) {
console.log(chalk.yellow("\nâ ď¸ Warnings:\n"));
results.warnings.forEach((warning) => {
console.log(chalk.yellow(` ⢠[${warning.rule}] ${warning.message}`));
if (warning.fix) {
console.log(chalk.gray(` Fix: ${warning.fix}`));
}
});
}
// Display passed rules
if (options.verbose && results.passed.length > 0) {
console.log(chalk.green("\nâ
Passed:\n"));
results.passed.forEach((pass) => {
console.log(chalk.green(` ⢠[${pass.rule}] ${pass.message}`));
});
}
// Display summary
console.log(chalk.blue("\nđ Validation Summary:\n"));
console.log(` Total checks: ${results.summary.total}`);
console.log(` ${chalk.green("Passed")}: ${results.summary.passed}`);
console.log(` ${chalk.yellow("Warnings")}: ${results.summary.warnings}`);
console.log(` ${chalk.red("Violations")}: ${results.summary.violations}`);
// Status message
if (results.violations.length === 0) {
console.log(chalk.green("\n⨠All mandatory rules passed!"));
} else {
console.log(
chalk.red(
`\nâ ${results.violations.length} violation(s) must be fixed.`,
),
);
}
// JSON output
if (options.json) {
console.log("\nJSON Output:");
console.log(JSON.stringify(results, null, 2));
}
}
/**
* Run modular validation
* @param {Object} options - Validation options
* @returns {Promise<Object>} - Validation results
*/
async function runModularValidation(options) {
const results = {
violations: [],
warnings: [],
passed: [],
summary: {},
};
// Get all rules from loaded modules
const rules = moduleLoader.getAllRules();
// Group rules by level
const rulesByLevel = {};
rules.forEach((rule) => {
if (!rulesByLevel[rule.level]) {
rulesByLevel[rule.level] = [];
}
rulesByLevel[rule.level].push(rule);
});
// Create validation context
const context = {
projectPath: process.cwd(),
files: await getProjectFiles(options),
branch: await getCurrentBranch(),
commits: await getRecentCommits(),
pr: await getCurrentPR(),
issue: await getCurrentIssue(),
};
// Run rules by level
for (const [level, levelRules] of Object.entries(rulesByLevel)) {
console.log(chalk.blue(`\nChecking Level ${level} rules...`));
for (const rule of levelRules) {
try {
const violations = await rule.check(context);
if (violations.length > 0) {
violations.forEach((v) => {
results.violations.push({
rule: rule.id,
name: rule.name,
level: rule.level,
module: rule.module,
severity: rule.severity,
...v,
});
});
console.log(chalk.red(` â ${rule.name}`));
} else {
results.passed.push(rule);
console.log(chalk.green(` â ${rule.name}`));
}
} catch (error) {
console.log(chalk.yellow(` â ${rule.name}: ${error.message}`));
results.warnings.push({
rule: rule.id,
name: rule.name,
error: error.message,
});
}
}
}
// Calculate summary
results.summary = {
total: rules.length,
passed: results.passed.length,
violations: results.violations.length,
warnings: results.warnings.length,
score: Math.round((results.passed.length / rules.length) * 100),
};
return results;
}
async function getProjectFiles(options) {
// Implementation would scan project files
return [];
}
async function getCurrentBranch() {
// Implementation would get current git branch
return "main";
}
async function getRecentCommits() {
// Implementation would get recent commits
return [];
}
async function getCurrentPR() {
// Implementation would get current PR if any
return null;
}
async function getCurrentIssue() {
// Implementation would extract issue from branch name
return null;
}