HEX
Server: LiteSpeed
System: Linux w5304130.sdnsbox.com 4.18.0-425.3.1.lve.el8.x86_64 #1 SMP Tue Nov 22 22:59:23 EST 2022 x86_64
User: makefitmeserver (1001)
PHP: 8.2.30
Disabled: NONE
Upload Files
File: //usr/local/lib/node_modules/less/scripts/coverage-report.js
#!/usr/bin/env node

/**
 * Generates a per-file coverage report table for src/ directories
 */

const fs = require('fs');
const path = require('path');

const coverageSummaryPath = path.join(__dirname, '..', 'coverage', 'coverage-summary.json');

if (!fs.existsSync(coverageSummaryPath)) {
    console.error('Coverage summary not found. Run pnpm test:coverage first.');
    process.exit(1);
}

const coverage = JSON.parse(fs.readFileSync(coverageSummaryPath, 'utf8'));

// Filter to only src/ files (less, less-node) and bin/ files
// Note: src/less-browser/ is excluded because browser tests aren't included in coverage
// Abstract base classes are excluded as they're meant to be overridden by implementations
const abstractClasses = [
    'abstract-file-manager',
    'abstract-plugin-loader'
];

const srcFiles = Object.entries(coverage)
    .filter(([filePath]) => {
        const normalized = filePath.replace(/\\/g, '/');
        // Exclude abstract classes
        if (abstractClasses.some(abstract => normalized.includes(abstract))) {
            return false;
        }
        return (normalized.includes('/src/less/') && !normalized.includes('/src/less-browser/')) || 
               normalized.includes('/src/less-node/') ||
               normalized.includes('/bin/');
    })
    .map(([filePath, data]) => {
        // Extract relative path from absolute path
        const normalized = filePath.replace(/\\/g, '/');
        // Match src/ paths or bin/ paths
        const match = normalized.match(/((?:src\/[^/]+\/[^/]+\/|bin\/).+)$/);
        const relativePath = match ? match[1] : path.basename(filePath);
        
        return {
            path: relativePath,
            statements: data.statements,
            branches: data.branches,
            functions: data.functions,
            lines: data.lines
        };
    })
    .sort((a, b) => {
        // Sort by directory first, then by coverage percentage
        const pathCompare = a.path.localeCompare(b.path);
        if (pathCompare !== 0) return pathCompare;
        return a.statements.pct - b.statements.pct;
    });

if (srcFiles.length === 0) {
    console.log('No src/ files found in coverage report.');
    process.exit(0);
}

// Group by directory
const grouped = {
    'src/less/': [],
    'src/less-node/': [],
    'bin/': []
};

srcFiles.forEach(file => {
    if (file.path.startsWith('src/less/')) {
        grouped['src/less/'].push(file);
    } else if (file.path.startsWith('src/less-node/')) {
        grouped['src/less-node/'].push(file);
    } else if (file.path.startsWith('bin/')) {
        grouped['bin/'].push(file);
    }
});

// Print table
console.log('\n' + '='.repeat(100));
console.log('Per-File Coverage Report (src/less/, src/less-node/, and bin/)');
console.log('='.repeat(100));
console.log('For line-by-line coverage details, open coverage/index.html in your browser.');
console.log('='.repeat(100) + '\n');

Object.entries(grouped).forEach(([dir, files]) => {
    if (files.length === 0) return;
    
    console.log(`\n${dir.toUpperCase()}`);
    console.log('-'.repeat(100));
    console.log(
        'File'.padEnd(50) + 
        'Statements'.padStart(12) + 
        'Branches'.padStart(12) + 
        'Functions'.padStart(12) + 
        'Lines'.padStart(12)
    );
    console.log('-'.repeat(100));
    
    files.forEach(file => {
        const filename = file.path.replace(dir, '');
        const truncated = filename.length > 48 ? '...' + filename.slice(-45) : filename;
        
        console.log(
            truncated.padEnd(50) +
            `${file.statements.pct.toFixed(1)}%`.padStart(12) +
            `${file.branches.pct.toFixed(1)}%`.padStart(12) +
            `${file.functions.pct.toFixed(1)}%`.padStart(12) +
            `${file.lines.pct.toFixed(1)}%`.padStart(12)
        );
    });
    
    // Summary for this directory
    const totals = files.reduce((acc, file) => {
        acc.statements.total += file.statements.total;
        acc.statements.covered += file.statements.covered;
        acc.branches.total += file.branches.total;
        acc.branches.covered += file.branches.covered;
        acc.functions.total += file.functions.total;
        acc.functions.covered += file.functions.covered;
        acc.lines.total += file.lines.total;
        acc.lines.covered += file.lines.covered;
        return acc;
    }, {
        statements: { total: 0, covered: 0 },
        branches: { total: 0, covered: 0 },
        functions: { total: 0, covered: 0 },
        lines: { total: 0, covered: 0 }
    });
    
    const stmtPct = totals.statements.total > 0 
        ? (totals.statements.covered / totals.statements.total * 100).toFixed(1)
        : '0.0';
    const branchPct = totals.branches.total > 0
        ? (totals.branches.covered / totals.branches.total * 100).toFixed(1)
        : '0.0';
    const funcPct = totals.functions.total > 0
        ? (totals.functions.covered / totals.functions.total * 100).toFixed(1)
        : '0.0';
    const linePct = totals.lines.total > 0
        ? (totals.lines.covered / totals.lines.total * 100).toFixed(1)
        : '0.0';
    
    console.log('-'.repeat(100));
    console.log(
        'TOTAL'.padEnd(50) +
        `${stmtPct}%`.padStart(12) +
        `${branchPct}%`.padStart(12) +
        `${funcPct}%`.padStart(12) +
        `${linePct}%`.padStart(12)
    );
});

console.log('\n' + '='.repeat(100) + '\n');