/
githubmirror
/
Front-End-Checklist
Обзор
Документация
Войти
/
githubmirror
/
Front-End-Checklist
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
scripts/validation/check-directory-structure.js
253 строки
7 KB
David Dias
chore: new v2 version
30 май 2026, 00:54
30 май 2026, 00:54
7c05904
Код
Авторство
О чём код?
#!/usr/bin/env node /** * Validates project directory structure for maintainability * Enforces consistent organization patterns */ // ============================================================================ // CONFIGURATION - Customize these settings for your project // ============================================================================ // Required top-level directories and their rules const REQUIRED_DIRECTORIES = [ 'src', // Source code 'components' // React components (can be in src/) ] // Optional directories that have specific structure rules when present const OPTIONAL_DIRECTORIES = [ 'lib', // Utility libraries 'hooks', // Custom React hooks 'types', // TypeScript type definitions 'styles', // CSS/styling files 'utils', // General utilities 'api', // API related code 'features' // Feature-based modules ] // Component organization patterns (adjust for your team's preference) const COMPONENT_STRUCTURE = { allowedSubdirectories: [ 'ui', // Basic UI components (Button, Input, etc.) usually for Shadcn/UI 'layout', // Layout components (Header, Footer, etc.) 'forms', // Form-related components 'common', // Shared/common components 'pages' // Page-specific components ], maxDepth: 3, // Maximum nesting depth for component directories enforceGrouping: true // Require components to be in subdirectories } // Files that are allowed in the root directory const ALLOWED_ROOT_FILES = [ // Configuration files 'package.json', 'tsconfig.json', 'jsconfig.json', 'next.config.js', 'next.config.mjs', 'next.config.ts', 'tailwind.config.js', 'tailwind.config.ts', 'tailwind.config.mjs', 'postcss.config.js', 'postcss.config.mjs', 'postcss.config.cjs', 'biome.json', 'vite.config.js', 'vite.config.ts', 'vite.config.mjs', 'vitest.config.js', 'vitest.config.ts', 'vitest.config.mjs', 'webpack.config.js', 'webpack.config.mjs', 'rollup.config.js', 'rollup.config.mjs', // Documentation 'README.md', 'CHANGELOG.md', 'LICENSE', // Git and CI '.gitignore', '.gitattributes', 'lefthook.yml', '.husky', // Other '.env.example', '.env.local', 'yarn.lock', 'package-lock.json', 'pnpm-lock.yaml' ] // Directories to exclude from structure checking const EXCLUDE_DIRECTORIES = [ 'node_modules', '.next', '.git', 'dist', 'build', 'out', 'coverage', '.turbo', '.vercel', '.netlify' ] // ============================================================================ // IMPLEMENTATION - No need to modify below this line // ============================================================================ const fs = require('node:fs') const path = require('node:path') // Helper function to check if directory should be excluded function shouldExcludeDirectory(dirPath) { return EXCLUDE_DIRECTORIES.some(exclude => dirPath.includes(exclude)) } // Helper function to validate component directory structure function validateComponentStructure(componentsDir) { const warnings = [] const errors = [] try { // Check for loose component files const componentFiles = fs .readdirSync(componentsDir, { withFileTypes: true }) .filter(dirent => dirent.isFile() && /\.(tsx?|jsx?)$/.test(dirent.name)) if (componentFiles.length > 5) { warnings.push( `Consider organizing components into subdirectories (found ${componentFiles.length} files in ${componentsDir})` ) } // Check subdirectory organization const subdirs = fs .readdirSync(componentsDir, { withFileTypes: true }) .filter(dirent => dirent.isDirectory()) .map(dirent => dirent.name) const unknownSubdirs = subdirs.filter( dir => !COMPONENT_STRUCTURE.allowedSubdirectories.includes(dir) && !shouldExcludeDirectory(path.join(componentsDir, dir)) ) if (unknownSubdirs.length > 0) { warnings.push( `Unexpected component subdirectories: ${unknownSubdirs.join(', ')}. Consider using: ${COMPONENT_STRUCTURE.allowedSubdirectories.join(', ')}` ) } // Check nesting depth const checkDepth = (dir, currentDepth = 0) => { if (currentDepth > COMPONENT_STRUCTURE.maxDepth) { errors.push( `Component directory nesting too deep in ${dir} (max: ${COMPONENT_STRUCTURE.maxDepth})` ) return } try { const items = fs.readdirSync(dir, { withFileTypes: true }) items.forEach(item => { if (item.isDirectory() && !shouldExcludeDirectory(path.join(dir, item.name))) { checkDepth(path.join(dir, item.name), currentDepth + 1) } }) } catch (_error) { // Skip directories that can't be read } } checkDepth(componentsDir) } catch (error) { warnings.push(`Could not validate component structure: ${error.message}`) } return { warnings, errors } } // Main validation function function validateDirectoryStructure() { const errors = [] const warnings = [] try { // Check if required directories exist REQUIRED_DIRECTORIES.forEach(dir => { if (!fs.existsSync(dir) && !fs.existsSync(path.join('src', dir))) { warnings.push(`Recommended directory missing: ${dir}`) } }) // Check for optional directories that have specific rules OPTIONAL_DIRECTORIES.forEach(dir => { const dirPath = fs.existsSync(dir) ? dir : fs.existsSync(path.join('src', dir)) ? path.join('src', dir) : null if (dirPath && !shouldExcludeDirectory(dirPath)) { // Optional directories exist and can be validated for structure if needed // This is where you could add specific validation rules for each directory type } }) // Check root directory for unwanted files const rootFiles = fs .readdirSync('.', { withFileTypes: true }) .filter(dirent => dirent.isFile()) .map(dirent => dirent.name) const unwantedFiles = rootFiles.filter(file => !ALLOWED_ROOT_FILES.includes(file)) if (unwantedFiles.length > 0) { warnings.push(`Consider organizing these root files: ${unwantedFiles.join(', ')}`) } // Check component structure if components directory exists const componentsDir = fs.existsSync('components') ? 'components' : fs.existsSync('src/components') ? 'src/components' : null if (componentsDir && COMPONENT_STRUCTURE.enforceGrouping) { const result = validateComponentStructure(componentsDir) warnings.push(...result.warnings) errors.push(...result.errors) } console.log('✅ Directory structure validation completed') if (warnings.length > 0) { console.log('⚠️ Warnings:') warnings.forEach(warning => console.log(` - ${warning}`)) } if (errors.length > 0) { console.log('❌ Errors:') errors.forEach(error => console.log(` - ${error}`)) } return errors.length === 0 } catch (error) { console.error('❌ Directory structure validation failed:', error.message) return false } } // Run validation if called directly if (require.main === module) { const success = validateDirectoryStructure() process.exit(success ? 0 : 1) } module.exports = { validateDirectoryStructure }