frontend-standards-checker
Version:
A comprehensive frontend standards validation tool with TypeScript support
351 lines (332 loc) • 14.7 kB
JavaScript
/* eslint-disable import/no-unused-modules */
/**
* @fileoverview Configuration file for checkFrontendStandards.mjs
*
* **Rule Structure:**
* Each rule must have:
* - `name`: Unique identifier (string)
* - `check`: Function that returns true for violations (content, filePath) => boolean | number[]
* - `message`: Error message shown to users (string)
* - `category`: Optional grouping ('structure', 'naming', 'content', 'style', 'documentation', etc.)
* - `severity`: Optional level ('error', 'warning', 'info')
*
* **Configuration Options:**
* - `merge`: Boolean to control if custom rules merge with defaults
* - `onlyChangedFiles`: Boolean to only check files staged for commit (default: true)
* - `zones`: Object to configure which directories to validate
* - `rules`: Array of custom validation rules
*
* @author Juan David Peña
* @license MIT
*/
export default {
// ==========================================
// ⚙️ SYSTEM CONFIGURATION
// ==========================================
// Merge custom rules with default rules (default: true)
merge: true,
// Only check files staged for commit (default: true)
// If set to false, all project files will be checked
onlyChangedFiles: true,
// Force pipeline mode for git file detection (default: false)
// When true, uses CI/CD-specific git strategies to find changed files
// Useful when running in pipelines where files are already committed
pipelineMode: false,
zones: {
// Whether to include 'packages' directory in validation (default: false)
includePackages: false,
// Validate only one specific zone
// onlyZone: 'auth', // Example: 'auth', 'src', 'components', 'pages', etc.
// onlyZone: 'src/auth', // For zone within src
// onlyZone: 'app/(auth)', // For Next.js App Router
// onlyZone: 'packages/ui', // For monorepos
// Custom zones to include in validation (ignored if onlyZone is defined)
// If customZones are specified, all files in those zones will be checked
// ignoring the onlyChangedFiles option
customZones: [
// 'custom-folder',
// 'another-folder'
],
},
// ==========================================
// 📋 RULES CONFIGURATION
// ==========================================
// Use all default rules (67 rules total)
// Empty array loads all default rules automatically
rules: [],
// ==========================================
// 📚 EXAMPLES FOR ADVANCED CONFIGURATION
// ==========================================
// 🚀 HOW TO USE ADVANCED CONFIGURATION:
//
// Step 1: Comment out "rules: []," above (line 59)
// Step 2: Uncomment the function below (remove /* and */ markers)
// Step 3: Uncomment specific examples inside the function that you want to use
// Step 4: Modify the examples according to your project needs
//
// 💡 TIP: Start with disabling rules you don't need, then add custom rules
//
// 🎯 COMMON USE CASES:
// - Keep all 67 default rules + add 2 custom rules = 69 total rules
// - Disable 3 default rules + add 1 custom rule = 65 total rules
// - Only modify existing rules without adding new ones = 67 total rules
//
/*
rules: function (defaultRules) {
// ==========================================
// � HOW THIS FUNCTION WORKS:
// ==========================================
// 🔥 This function receives all 67 default rules and lets you:
// 1. KEEP all default rules + ADD custom rules (most common)
// 2. DISABLE specific default rules you don't want
// 3. MODIFY existing rules (change severity, messages, etc.)
// 4. ADD completely new custom rules
//
// 💡 By default, ALL rules are included unless you disable them
// ==========================================
// �🚫 DISABLE EXISTING RULES
// ==========================================
// Filter out rules you want to disable from the 64 available default rules:
// Choose from the complete list of available rules:
//
// 🏗️ STRUCTURE RULES (12 rules):
// 'Folder structure', 'Src structure', 'Component size limit',
// 'No circular dependencies', 'Missing test files', 'Test file naming convention',
// 'Missing index.ts in organization folders', 'GitFlow branch naming convention',
// 'Environment-specific configuration', 'Proper release versioning',
// 'Platform-specific code organization', 'Sync branch validation'
//
// 🏷️ NAMING RULES (12 rules):
// 'Component naming', 'Hook naming', 'Type naming', 'Constants naming',
// 'Helper naming', 'Style naming', 'Assets naming', 'Folder naming convention',
// 'Directory naming convention', 'Interface naming with I prefix',
// 'Constant export naming UPPERCASE', 'Next.js app router naming'
//
// 💻 CONTENT RULES (10 rules):
// 'No console.log', 'No var', 'No any type', 'No inline styles',
// 'No alert', 'No hardcoded URLs', 'Must use async/await', 'No jQuery',
// 'No merge conflicts markers', 'No committed credentials'
//
// ⚛️ REACT RULES (7 rules):
// 'Client component directive', 'Proper hook dependencies',
// 'Component props interface', 'Avoid React.FC', 'Proper key prop in lists',
// 'Styled components naming', 'Tailwind CSS preference'
//
// 🔷 TYPESCRIPT RULES (3 rules):
// 'Prefer type over interface for unions', 'Explicit return types for functions',
// 'Proper generic naming'
//
// 📦 IMPORT RULES (5 rules):
// 'Direct imports for sibling files', 'Import order', 'Use absolute imports',
// 'No default and named imports mixed', 'No unused imports'
//
// ⚡ PERFORMANCE RULES (5 rules):
// 'Next.js Image optimization', 'Avoid inline functions in JSX',
// 'Missing React.memo for pure components', 'Large bundle imports',
// 'Avoid re-renders with object literals'
//
// ♿ ACCESSIBILITY RULES (6 rules):
// 'Button missing accessible name', 'Form inputs missing labels',
// 'Image alt text', 'Links missing accessible names',
// 'Missing focus management', 'Color contrast considerations'
//
// 📖 DOCUMENTATION RULES (4 rules):
// 'Missing comment in complex function', 'Should have TSDoc comments',
// 'JSDoc for complex functions', 'English-only comments'
// ==========================================
// 🚫 DISABLE RULES - HOW TO USE:
// ==========================================
// 1. Uncomment the rule names you want to disable
// 2. Remove the // at the beginning of each line
// 3. The rule will be excluded from validation
//
// Example: To allow console.log statements, uncomment:
// 'No console.log',
const disabledRules = [
// 'No console.log', // Allow console.log statements
// 'No any type', // Allow TypeScript any type
// 'English-only comments', // Allow non-English comments
// 'Component naming', // Disable component naming rules
// 'Missing test files', // Don't require test files
];
const filteredRules = defaultRules.filter(
(rule) => !disabledRules.includes(rule.name)
);
// ==========================================
// 🔄 MODIFY EXISTING RULES - HOW TO USE:
// ==========================================
// 1. Uncomment the if statement for the rule you want to modify
// 2. Change severity: 'error' to 'warning' or 'info'
// 3. Modify the message property to customize error text
//
// Example: To make 'No any type' a warning instead of error, uncomment:
// if (rule.name === 'No any type') {
// return { ...rule, severity: 'warning' };
// }
const modifiedRules = filteredRules.map((rule) => {
// Example: Change rule severity
// if (rule.name === 'No any type') {
// return { ...rule, severity: 'warning' }; // Change from error to warning
// }
// Example: Customize rule message
// if (rule.name === 'Component naming') {
// return {
// ...rule,
// message: 'Components should use PascalCase naming convention.',
// };
// }
return rule;
});
// ==========================================
// 🎯 CUSTOM RULES - HOW TO ADD:
// ==========================================
// 🔥 IMPORTANT: All 67 default rules are AUTOMATICALLY INCLUDED
// You only need to add your custom rules here - they will be ADDED to the defaults
//
// 1. Uncomment the rule object you want to use
// 2. Remove the comment slashes and markers around the rule
// 3. Modify the rule properties as needed:
// - name: Unique rule identifier
// - category: 'content', 'naming', 'structure', 'security', etc.
// - severity: 'error', 'warning', or 'info'
// - check: Function that returns true when rule is violated
// - message: Description shown to developers
//
// 💡 RESULT: You'll have 67 default rules + your custom rules
// Example: To add a rule against hardcoded URLs, uncomment the first rule below
const customRules = [
// {
// name: 'No hardcoded URLs',
// category: 'content',
// severity: 'warning',
// check: (content) => /https?:\/\/[^\s'"]+/.test(content),
// message: 'Use environment variables for URLs.',
// },
// {
// name: 'Custom hook naming',
// category: 'naming',
// severity: 'error',
// check: (content, filePath) => {
// if (!filePath.endsWith('.tsx') && !filePath.endsWith('.ts')) return false;
// return /const\s+\w+\s*=\s*use\w+/.test(content) && !/const\s+use\w+/.test(content);
// },
// message: 'Custom hooks should start with "use".',
// },
// {
// name: 'No pending tasks',
// category: 'content',
// severity: 'warning',
// check: (content) => content.includes('TASK'),
// message: 'Resolve pending tasks before committing.',
// },
// ==========================================
// 🔍 ADVANCED REGEX RULES
// ==========================================
// {
// name: 'No debug statements',
// category: 'content',
// severity: 'error',
// check: (content) => {
// const debugRegex = /(?:^|[^\/\*])(?:console\.(?:debug|trace)|debugger)/gm;
// return debugRegex.test(content);
// },
// message: 'Remove debug statements from production code.',
// },
// {
// name: 'No hardcoded secrets',
// category: 'security',
// severity: 'error',
// check: (content) => {
// const secretPatterns = [
// /(?:password|secret|key|token)\s*[:=]\s*['"][^'"]{8,}['"]/gi,
// /(?:api[_-]?key|access[_-]?token)\s*[:=]\s*['"][^'"]+['"]/gi,
// ];
// return secretPatterns.some(pattern => pattern.test(content));
// },
// message: 'Use environment variables for secrets.',
// },
// ==========================================
// 📁 FILE-SPECIFIC RULES
// ==========================================
// {
// name: 'Component prop types',
// category: 'typescript',
// severity: 'error',
// check: (content, filePath) => {
// if (!filePath.includes('/components/') || !filePath.endsWith('.tsx')) {
// return false;
// }
// const hasProps = /(?:function|const)\s+\w+.*\(\s*\{\s*\w+/.test(content);
// const hasInterface = /interface\s+\w+Props/.test(content);
// const hasType = /type\s+\w+Props/.test(content);
// return hasProps && !hasInterface && !hasType;
// },
// message: 'React components with props must define TypeScript interfaces.',
// },
// ==========================================
// 🔒 SECURITY RULES
// ==========================================
// {
// name: 'Unsafe HTML injection',
// category: 'security',
// severity: 'error',
// check: (content) => {
// const dangerousHTML = /dangerouslySetInnerHTML\s*=\s*{\s*{?\s*__html:/g;
// const hasSanitization = /DOMPurify|sanitize|xss/gi;
// return dangerousHTML.test(content) && !hasSanitization.test(content);
// },
// message: 'Sanitize HTML content before using dangerouslySetInnerHTML.',
// },
// ==========================================
// 🚀 PERFORMANCE RULES
// ==========================================
// {
// name: 'React performance',
// category: 'performance',
// severity: 'warning',
// check: (content, filePath) => {
// if (!filePath.endsWith('.tsx') && !filePath.endsWith('.jsx')) {
// return false;
// }
// const inlineFunctionRegex = /\w+\s*=\s*{\s*\([^)]*\)\s*=>/g;
// return inlineFunctionRegex.test(content);
// },
// message: 'Avoid inline functions in JSX props to prevent re-renders.',
// },
// ==========================================
// 🚀 QUICK START EXAMPLES - READY TO USE:
// ==========================================
// These are simple rules you can enable immediately.
// Just remove the comment slashes (//) to activate any rule:
//
// {
// name: 'No hardcoded URLs',
// category: 'content',
// severity: 'warning',
// check: (content) => /https?:\/\/[^\s'"]+/.test(content),
// message: 'Use environment variables for URLs.',
// },
// {
// name: 'React hooks naming',
// category: 'naming',
// severity: 'error',
// check: (content, filePath) => {
// if (!filePath.endsWith('.tsx') && !filePath.endsWith('.ts')) return false;
// return /const\s+\w+\s*=\s*use\w+/.test(content) && !/const\s+use\w+/.test(content);
// },
// message: 'Custom hooks should start with "use".',
// },
];
// ==========================================
// 🔄 FINAL RESULT EXPLANATION:
// ==========================================
// This return combines:
// - modifiedRules: Default rules (67) minus disabled ones, with any modifications
// - customRules: Your new custom rules (0+ rules)
//
// 💡 EXAMPLE: If you disable 2 rules and add 3 custom rules, you'll have:
// (67 - 2) + 3 = 68 total rules
return [...modifiedRules, ...customRules];
},
*/
};