@sun-asterisk/sunlint
Version: 
āļø SunLint - Multi-language static analysis tool for code quality and security | Sun* Engineering Standards
149 lines (119 loc) ⢠5.06 kB
JavaScript
/**
 * Validation script to ensure all rule test fixtures follow standardized structure
 */
const fs = require('fs');
const path = require('path');
const RULES_DIR = 'examples/rule-test-fixtures/rules';
function validateRuleStructure() {
    console.log('š Validating Rule Test Fixtures Structure\n');
    
    const rulesPath = path.resolve(__dirname, '..', RULES_DIR);
    const ruleDirs = fs.readdirSync(rulesPath, { withFileTypes: true })
        .filter(dirent => dirent.isDirectory())
        .map(dirent => dirent.name)
        .filter(name => !name.startsWith('.') && name !== 'README.md');
    let allValid = true;
    const results = [];
    for (const ruleDir of ruleDirs) {
        const rulePath = path.join(rulesPath, ruleDir);
        const result = {
            rule: ruleDir,
            hasClean: false,
            hasViolations: false,
            cleanFiles: [],
            violationFiles: [],
            issues: []
        };
        // Check for clean directory
        const cleanPath = path.join(rulePath, 'clean');
        if (fs.existsSync(cleanPath)) {
            result.hasClean = true;
            result.cleanFiles = fs.readdirSync(cleanPath).filter(f => !f.startsWith('.'));
        } else {
            result.issues.push('Missing clean/ directory');
            allValid = false;
        }
        // Check for violations directory  
        const violationsPath = path.join(rulePath, 'violations');
        if (fs.existsSync(violationsPath)) {
            result.hasViolations = true;
            result.violationFiles = fs.readdirSync(violationsPath).filter(f => !f.startsWith('.'));
        } else {
            result.issues.push('Missing violations/ directory');
            allValid = false;
        }
        // Check for loose files (should be moved to clean/violations)
        const allFiles = fs.readdirSync(rulePath, { withFileTypes: true });
        const looseFiles = allFiles
            .filter(dirent => dirent.isFile() && !dirent.name.startsWith('.') && dirent.name !== 'README.md')
            .map(dirent => dirent.name);
        
        if (looseFiles.length > 0) {
            result.issues.push(`Loose files found: ${looseFiles.join(', ')}`);
            allValid = false;
        }
        results.push(result);
    }
    // Display results
    console.log(`š Validation Results for ${results.length} rules:\n`);
    
    for (const result of results) {
        const status = result.issues.length === 0 ? 'ā
' : 'ā';
        console.log(`${status} ${result.rule}`);
        
        if (result.hasClean) {
            console.log(`   ā
 clean/ (${result.cleanFiles.length} files)`);
        } else {
            console.log(`   ā clean/ directory missing`);
        }
        
        if (result.hasViolations) {
            console.log(`   ā
 violations/ (${result.violationFiles.length} files)`);
        } else {
            console.log(`   ā violations/ directory missing`);
        }
        if (result.issues.length > 0) {
            result.issues.forEach(issue => console.log(`   ā ļø  ${issue}`));
        }
        
        console.log('');
    }
    // Summary
    const validRules = results.filter(r => r.issues.length === 0).length;
    const invalidRules = results.length - validRules;
    console.log('š Summary:');
    console.log(`   ā
 Valid rules: ${validRules}`);
    console.log(`   ā Invalid rules: ${invalidRules}`);
    console.log(`   š Total rules: ${results.length}`);
    if (allValid) {
        console.log('\nš All rules follow standardized structure!');
    } else {
        console.log('\nā ļø  Some rules need structure fixes.');
    }
    return allValid;
}
// Create missing clean folders for empty rules
function createMissingFolders() {
    console.log('\nš ļø  Creating missing folders...\n');
    
    const rulesPath = path.resolve(__dirname, '..', RULES_DIR);
    const ruleDirs = fs.readdirSync(rulesPath, { withFileTypes: true })
        .filter(dirent => dirent.isDirectory())
        .map(dirent => dirent.name)
        .filter(name => !name.startsWith('.') && name !== 'README.md');
    for (const ruleDir of ruleDirs) {
        const rulePath = path.join(rulesPath, ruleDir);
        
        // Create clean folder if missing
        const cleanPath = path.join(rulePath, 'clean');
        if (!fs.existsSync(cleanPath)) {
            fs.mkdirSync(cleanPath, { recursive: true });
            console.log(`ā
 Created: ${ruleDir}/clean/`);
        }
        
        // Create violations folder if missing
        const violationsPath = path.join(rulePath, 'violations');
        if (!fs.existsSync(violationsPath)) {
            fs.mkdirSync(violationsPath, { recursive: true });
            console.log(`ā
 Created: ${ruleDir}/violations/`);
        }
    }
}
if (require.main === module) {
    createMissingFolders();
    const isValid = validateRuleStructure();
    process.exit(isValid ? 0 : 1);
}
module.exports = { validateRuleStructure, createMissingFolders };