包含 webapp(Next.js 用户端)、webapp-back(Go 后端)、 antdesign(管理后台)、landingpage(营销落地页)、 数据库 SQL 和配置文件。
164 lines
4.5 KiB
JavaScript
Executable File
164 lines
4.5 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
||
|
||
/**
|
||
* 颜色验证脚本
|
||
*
|
||
* 检查组件文件中是否还有硬编码的十六进制颜色值
|
||
* 用法: node scripts/validate-colors.js
|
||
*/
|
||
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
|
||
// 硬编码颜色的正则模式
|
||
const hardcodedColorPatterns = [
|
||
// Tailwind 类名中的十六进制颜色: bg-[#hex], text-[#hex], border-[#hex]
|
||
/(bg|text|border|from|to|via)-\[#[0-9a-fA-F]{3,8}\]/g,
|
||
|
||
// 内联样式中的十六进制颜色
|
||
/(?:background|color|border)(?:Color)?:\s*['"]?#[0-9a-fA-F]{3,8}/g,
|
||
|
||
// 对象样式中的十六进制颜色
|
||
/['"](?:background|color|border)(?:Color)?['"]\s*:\s*['"]#[0-9a-fA-F]{3,8}/g,
|
||
];
|
||
|
||
// 允许的例外情况(特殊设计需求)
|
||
const allowedExceptions = [
|
||
// rgba/hsla 透明度值(毛玻璃效果等)
|
||
/rgba?\(/,
|
||
/hsla?\(/,
|
||
|
||
// 渐变色(gradient-to-br from-green-400 to-emerald-500 等非硬编码)
|
||
// 注意:这里不排除硬编码的渐变,会被上面的模式捕获
|
||
];
|
||
|
||
// 需要检查的目录
|
||
const componentsDir = path.join(__dirname, '../components');
|
||
|
||
// 收集结果
|
||
const results = {
|
||
files: [],
|
||
totalViolations: 0,
|
||
};
|
||
|
||
/**
|
||
* 检查单个文件
|
||
*/
|
||
function checkFile(filePath) {
|
||
const content = fs.readFileSync(filePath, 'utf-8');
|
||
const violations = [];
|
||
|
||
// 按行分析
|
||
const lines = content.split('\n');
|
||
|
||
lines.forEach((line, index) => {
|
||
hardcodedColorPatterns.forEach(pattern => {
|
||
const matches = line.match(pattern);
|
||
if (matches) {
|
||
// 检查是否是允许的例外
|
||
const isException = allowedExceptions.some(exceptionPattern =>
|
||
exceptionPattern.test(line)
|
||
);
|
||
|
||
if (!isException) {
|
||
matches.forEach(match => {
|
||
violations.push({
|
||
line: index + 1,
|
||
content: line.trim(),
|
||
match: match,
|
||
});
|
||
});
|
||
}
|
||
}
|
||
});
|
||
});
|
||
|
||
if (violations.length > 0) {
|
||
results.files.push({
|
||
path: path.relative(process.cwd(), filePath),
|
||
violations: violations,
|
||
count: violations.length,
|
||
});
|
||
results.totalViolations += violations.length;
|
||
}
|
||
|
||
return violations.length === 0;
|
||
}
|
||
|
||
/**
|
||
* 递归扫描目录
|
||
*/
|
||
function scanDirectory(dir) {
|
||
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
||
|
||
entries.forEach(entry => {
|
||
const fullPath = path.join(dir, entry.name);
|
||
|
||
if (entry.isDirectory()) {
|
||
scanDirectory(fullPath);
|
||
} else if (entry.isFile() && /\.(tsx|ts|jsx|js)$/.test(entry.name)) {
|
||
checkFile(fullPath);
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 打印结果
|
||
*/
|
||
function printResults() {
|
||
console.log('\n='.repeat(80));
|
||
console.log('🎨 设计系统颜色验证报告');
|
||
console.log('='.repeat(80));
|
||
console.log();
|
||
|
||
if (results.totalViolations === 0) {
|
||
console.log('✅ 太棒了!没有发现硬编码颜色值。');
|
||
console.log();
|
||
console.log('所有组件都已成功迁移到设计系统!');
|
||
} else {
|
||
console.log(`⚠️ 发现 ${results.totalViolations} 处硬编码颜色值,分布在 ${results.files.length} 个文件中:`);
|
||
console.log();
|
||
|
||
results.files.forEach(file => {
|
||
console.log(`📄 ${file.path} (${file.count} 处问题)`);
|
||
console.log('─'.repeat(80));
|
||
|
||
// 按行号分组相同的问题
|
||
const lineMap = new Map();
|
||
file.violations.forEach(v => {
|
||
if (!lineMap.has(v.line)) {
|
||
lineMap.set(v.line, []);
|
||
}
|
||
lineMap.get(v.line).push(v.match);
|
||
});
|
||
|
||
lineMap.forEach((matches, lineNum) => {
|
||
const firstViolation = file.violations.find(v => v.line === lineNum);
|
||
console.log(` 行 ${lineNum}: ${firstViolation.content.substring(0, 100)}${firstViolation.content.length > 100 ? '...' : ''}`);
|
||
matches.forEach(match => {
|
||
console.log(` ↳ ${match}`);
|
||
});
|
||
});
|
||
|
||
console.log();
|
||
});
|
||
|
||
console.log('='.repeat(80));
|
||
console.log('💡 建议:');
|
||
console.log(' • 将硬编码颜色替换为设计系统的 token (如 text-text-primary, bg-bg-base 等)');
|
||
console.log(' • 检查是否有特殊设计需求需要保留硬编码');
|
||
console.log(' • 参考 /styles/design-system.css 中定义的颜色变量');
|
||
}
|
||
|
||
console.log('='.repeat(80));
|
||
console.log();
|
||
|
||
// 退出码
|
||
process.exit(results.totalViolations > 0 ? 1 : 0);
|
||
}
|
||
|
||
// 执行扫描
|
||
console.log('🔍 正在扫描组件文件...');
|
||
scanDirectory(componentsDir);
|
||
printResults();
|