Initial TrueGrowth source import
This commit is contained in:
166
scripts/check-truegrowth-ui-system.mjs
Normal file
166
scripts/check-truegrowth-ui-system.mjs
Normal file
@@ -0,0 +1,166 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
const root = process.cwd();
|
||||
const appSourceRoots = ['apps/web/src'];
|
||||
const strictVisualRoots = ['apps/web/src/ui', 'docs/page-templates'];
|
||||
const allowedLegacyFiles = new Set([
|
||||
'apps/web/src/workbench/WorkbenchShell.tsx',
|
||||
]);
|
||||
|
||||
const bannedImports = [
|
||||
{
|
||||
pattern: /from\s+['"]tdesign-react['"]/,
|
||||
message: 'New app UI must use @/ui instead of tdesign-react.',
|
||||
},
|
||||
{
|
||||
pattern: /from\s+['"]tdesign-icons-react['"]/,
|
||||
message: 'New icons must use lucide-react instead of tdesign-icons-react.',
|
||||
},
|
||||
];
|
||||
|
||||
const bannedBluePrimary = [
|
||||
/#1677ff/i,
|
||||
/#1890ff/i,
|
||||
/#2563eb/i,
|
||||
/#3b82f6/i,
|
||||
/rgb\(\s*37\s*,\s*99\s*,\s*235\s*\)/i,
|
||||
];
|
||||
|
||||
const uiRequiredDirs = [
|
||||
'apps/web/src/ui',
|
||||
'docs/page-templates',
|
||||
];
|
||||
|
||||
const requiredFiles = [
|
||||
{
|
||||
path: 'docs/TRUEGROWTH_GOLDEN_IMAGE_PAGE_UI.md',
|
||||
includes: [
|
||||
'/image',
|
||||
'golden page',
|
||||
'Browser QA Requirement',
|
||||
'light and dark',
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'docs/TRUEGROWTH_UI_SYSTEM.md',
|
||||
includes: ['TRUEGROWTH_GOLDEN_IMAGE_PAGE_UI.md', '/image'],
|
||||
},
|
||||
{
|
||||
path: 'docs/TRUEGROWTH_GOLDEN_PAGE_MIGRATION_AUDIT.md',
|
||||
includes: ['/video', '/avatar', '/assets', 'Browser Evidence'],
|
||||
},
|
||||
{
|
||||
path: 'AGENTS.md',
|
||||
includes: ['TRUEGROWTH_GOLDEN_IMAGE_PAGE_UI.md', '/image'],
|
||||
},
|
||||
{
|
||||
path: 'docs/page-templates/generator-page.tsx',
|
||||
includes: ['tg-golden-generator'],
|
||||
},
|
||||
{
|
||||
path: 'docs/page-templates/media-library-page.tsx',
|
||||
includes: ['tg-golden-library'],
|
||||
},
|
||||
{
|
||||
path: 'docs/page-templates/status-page.tsx',
|
||||
includes: ['tg-golden-status'],
|
||||
},
|
||||
];
|
||||
|
||||
const errors = [];
|
||||
|
||||
for (const dir of appSourceRoots) {
|
||||
walk(path.join(root, dir), (file) => {
|
||||
const relative = path.relative(root, file).replace(/\\/g, '/');
|
||||
if (!/\.(tsx?)$/.test(relative)) {
|
||||
return;
|
||||
}
|
||||
const content = fs.readFileSync(file, 'utf8');
|
||||
if (!allowedLegacyFiles.has(relative)) {
|
||||
for (const rule of bannedImports) {
|
||||
if (rule.pattern.test(content)) {
|
||||
errors.push(`${relative}: ${rule.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (const dir of strictVisualRoots) {
|
||||
walk(path.join(root, dir), (file) => {
|
||||
const relative = path.relative(root, file).replace(/\\/g, '/');
|
||||
if (!/\.(tsx?|scss|css)$/.test(relative)) {
|
||||
return;
|
||||
}
|
||||
const content = fs.readFileSync(file, 'utf8');
|
||||
for (const rule of bannedImports) {
|
||||
if (rule.pattern.test(content)) {
|
||||
errors.push(`${relative}: ${rule.message}`);
|
||||
}
|
||||
}
|
||||
for (const pattern of bannedBluePrimary) {
|
||||
if (pattern.test(content)) {
|
||||
errors.push(
|
||||
`${relative}: Blue primary/focus colors are not allowed in the UI system. Use TrueGrowth orange tokens.`
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (const dir of uiRequiredDirs) {
|
||||
if (!fs.existsSync(path.join(root, dir))) {
|
||||
errors.push(`${dir}: required UI system directory is missing.`);
|
||||
}
|
||||
}
|
||||
|
||||
for (const file of requiredFiles) {
|
||||
const absolute = path.join(root, file.path);
|
||||
if (!fs.existsSync(absolute)) {
|
||||
errors.push(`${file.path}: required golden UI standard file is missing.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(absolute, 'utf8');
|
||||
for (const text of file.includes) {
|
||||
if (!content.includes(text)) {
|
||||
errors.push(`${file.path}: missing required golden UI reference "${text}".`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
console.error('TrueGrowth UI system check failed:');
|
||||
for (const error of errors) {
|
||||
console.error(`- ${error}`);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('TrueGrowth UI system check passed.');
|
||||
|
||||
function walk(dir, visit) {
|
||||
if (!fs.existsSync(dir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
||||
if (
|
||||
entry.name === 'node_modules' ||
|
||||
entry.name === 'dist' ||
|
||||
entry.name === '.nx'
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const fullPath = path.join(dir, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
walk(fullPath, visit);
|
||||
} else if (entry.isFile()) {
|
||||
visit(fullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user