Files
assetx/landingpage/scripts/validate-colors.js
default 2ee4553b71 init: 初始化 AssetX 项目仓库
包含 webapp(Next.js 用户端)、webapp-back(Go 后端)、
antdesign(管理后台)、landingpage(营销落地页)、
数据库 SQL 和配置文件。
2026-03-27 11:26:43 +00:00

164 lines
4.5 KiB
JavaScript
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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();