#!/usr/bin/env node
const fs = require('fs')
const path = require('path')
const { execSync } = require('child_process')
// 创建报告目录
const reportDir = path.resolve(process.cwd(), 'quality-report')
if (!fs.existsSync(reportDir)) {
fs.mkdirSync(reportDir, { recursive: true })
}
// 生成时间戳
const timestamp = new Date().toISOString().replace(/[:.]/g, '-')
const reportFile = path.join(reportDir, `quality-report-${timestamp}.html`)
// 报告模板
const reportTemplate = `
代码质量报告
`
// 写入报告文件
fs.writeFileSync(reportFile, reportTemplate)
console.log(`✅ 代码质量报告已生成: ${reportFile}`)
// 运行各种检查并更新报告
async function generateQualityReport() {
try {
// 1. 运行测试覆盖率
console.log('🔍 运行测试覆盖率...')
try {
execSync('npm run test:unit:coverage', { stdio: 'pipe' })
const coverageSummary = JSON.parse(fs.readFileSync('coverage/coverage-summary.json', 'utf8'))
updateTestCoverage(coverageSummary)
} catch (error) {
console.error('❌ 测试覆盖率检查失败:', error.message)
updateTestCoverage(null, error.message)
}
// 2. 运行 ESLint
console.log('🔍 运行 ESLint...')
try {
const eslintOutput = execSync('npm run lint -- --format=json', { stdio: 'pipe' }).toString()
const eslintResults = JSON.parse(eslintOutput)
updateESLintResults(eslintResults)
} catch (error) {
console.error('❌ ESLint 检查失败:', error.message)
updateESLintResults(null, error.message)
}
// 3. 运行类型检查
console.log('🔍 运行类型检查...')
try {
execSync('npm run type-check', { stdio: 'pipe' })
updateTypeCheckResults(true)
} catch (error) {
console.error('❌ 类型检查失败:', error.message)
updateTypeCheckResults(false, error.message)
}
// 4. 运行安全审计
console.log('🔍 运行安全审计...')
try {
const auditOutput = execSync('npm audit --json', { stdio: 'pipe' }).toString()
const auditResults = JSON.parse(auditOutput)
updateSecurityResults(auditResults)
} catch (error) {
console.error('❌ 安全审计失败:', error.message)
updateSecurityResults(null, error.message)
}
console.log('✅ 代码质量报告更新完成')
} catch (error) {
console.error('❌ 生成代码质量报告时出错:', error)
}
}
// 更新测试覆盖率信息
function updateTestCoverage(coverageSummary, error) {
let html = ''
if (error) {
html = `
状态
检查失败
${error}
`
} else {
const { lines, functions, branches, statements } = coverageSummary.total
const linesPercent = parseFloat(lines.pct)
html = `
行覆盖率
${lines.pct}%
函数覆盖率
${functions.pct}%
分支覆盖率
${branches.pct}%
语句覆盖率
${statements.pct}%
`
// 更新概览
updateOverview('test-coverage', lines.pct + '%', linesPercent >= 80 ? 'success' : linesPercent >= 60 ? 'warning' : 'error')
}
updateReportSection('coverage-details', html)
}
// 更新 ESLint 结果
function updateESLintResults(eslintResults, error) {
let html = ''
if (error) {
html = `
状态
检查失败
${error}
`
} else {
let totalErrors = 0
let totalWarnings = 0
eslintResults.forEach(file => {
totalErrors += file.errorCount
totalWarnings += file.warningCount
})
const status = totalErrors === 0 && totalWarnings === 0 ? 'success' : totalErrors === 0 ? 'warning' : 'error'
html = `
错误
${totalErrors}
警告
${totalWarnings}
状态
${totalErrors === 0 && totalWarnings === 0 ? '通过' : totalErrors === 0 ? '警告' : '失败'}
`
// 更新概览
updateOverview('eslint-issues', totalErrors + totalWarnings, status)
}
updateReportSection('eslint-details', html)
}
// 更新类型检查结果
function updateTypeCheckResults(success, error) {
let html = ''
if (success) {
html = `
状态
通过
类型错误
0
`
// 更新概览
updateOverview('type-errors', '0', 'success')
} else {
html = `
状态
失败
${error}
`
// 更新概览
updateOverview('type-errors', '>', 'error')
}
updateReportSection('type-check-details', html)
}
// 更新安全检查结果
function updateSecurityResults(auditResults, error) {
let html = ''
if (error) {
html = `
状态
检查失败
${error}
`
// 更新概览
updateOverview('security-vulnerabilities', '?', 'error')
} else {
const { vulnerabilities } = auditResults.metadata
const { low, moderate, high, critical } = vulnerabilities
const totalVulns = low + moderate + high + critical
const status = critical > 0 || high > 0 ? 'error' : moderate > 0 ? 'warning' : 'success'
html = `
严重
${critical}
高危
${high}
中危
${moderate}
低危
${low}
总计
${totalVulns}
`
// 更新概览
updateOverview('security-vulnerabilities', totalVulns, status)
}
updateReportSection('security-details', html)
}
// 更新概览
function updateOverview(id, value, status) {
const elementId = id
const className = status === 'success' ? 'success' : status === 'warning' ? 'warning' : 'error'
// 这里需要使用 DOM 操作,但在 Node.js 环境中无法直接操作 HTML
// 实际实现中可以使用 cheerio 或其他 HTML 解析库
console.log(`更新概览 ${id}: ${value} (${status})`)
}
// 更新报告部分
function updateReportSection(id, html) {
// 这里需要使用 DOM 操作,但在 Node.js 环境中无法直接操作 HTML
// 实际实现中可以使用 cheerio 或其他 HTML 解析库
console.log(`更新报告部分 ${id}`)
}
// 运行报告生成
generateQualityReport()
module.exports = {
generateQualityReport
}