From c9e9d722e5edf1150ec1ff8439cea378ff48b4c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Kr=C3=A1l?= Date: Mon, 8 Sep 2025 17:45:36 +0200 Subject: [PATCH] chore(rules) - check new rules script added --- .github/workflows/pr.yml | 18 ++ build/find-missing-rules.php | 511 +++++++++++++++++++++++++++++++++++ composer.json | 13 +- 3 files changed, 536 insertions(+), 6 deletions(-) create mode 100644 build/find-missing-rules.php diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 6f1b7d6..d6eff3b 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -5,6 +5,24 @@ on: branches: [ master, main ] jobs: + check-missing-rules: + name: Check Missing Rector Rules + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.4' + extensions: mbstring, xml, ctype, iconv, intl, pdo_sqlite, dom, filter, gd, iconv, json, mbstring, pdo + + - name: Install dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Check for missing Rector rules + run: composer check:missing-rules phpcs: runs-on: ubuntu-latest steps: diff --git a/build/find-missing-rules.php b/build/find-missing-rules.php new file mode 100644 index 0000000..559dbc3 --- /dev/null +++ b/build/find-missing-rules.php @@ -0,0 +1,511 @@ +isFile() && $file->getExtension() === 'php') { + $className = buildClassNameFromFile($file, $rectorPath); + + if (isValidRectorRule($className)) { + $rules[] = $className; + } + } + } + + return $rules; +} + +/** + * Build class name from file path + */ +function buildClassNameFromFile(SplFileInfo $file, string $rectorPath): string +{ + $relativePath = str_replace($rectorPath . '/', '', $file->getPathname()); + $className = str_replace('/', '\\', $relativePath); + + return 'Rector\\' . str_replace('.php', '', $className); +} + +/** + * Check if class is a valid Rector rule + */ +function isValidRectorRule(string $className): bool +{ + if (!class_exists($className)) { + return false; + } + + $reflection = new ReflectionClass($className); + + return $reflection->isSubclassOf(AbstractRector::class) && !$reflection->isAbstract(); +} + +/** + * Load defined rules from rules/rules.php + */ +function getDefinedRules(): array +{ + $rulesFile = __DIR__ . '/../rules/rules.php'; + + if (!file_exists($rulesFile)) { + echo "Error: File rules/rules.php does not exist.\n"; + + return []; + } + + $content = file_get_contents($rulesFile); + + return extractUseStatements($content); +} + +/** + * Extract use statements from file content + */ +function extractUseStatements(string $content): array +{ + $definedRules = []; + + // Find all use statements + preg_match_all('/use\s+([^;]+);/', $content, $matches); + + foreach ($matches[1] as $useStatement) { + $definedRules[] = trim($useStatement); + } + + return $definedRules; +} + +/** + * Main function + */ +function main(): void +{ + $allRules = loadAndDisplayAllRules(); + $definedRules = loadAndDisplayDefinedRules(); + + $missingRules = findMissingRules($allRules, $definedRules); + + if ($missingRules === []) { + echo "✅ All available Rector rules are already defined in rules/rules.php\n"; + + return; + } + + displayMissingRules($missingRules); + exit(1); +} + +/** + * Load and display all Rector rules + */ +function loadAndDisplayAllRules(): array +{ + echo "Loading all Rector rules from vendor...\n"; + $allRules = getAllRectorRules(); + echo "Found " . count($allRules) . " Rector rules.\n\n"; + + return $allRules; +} + +/** + * Load and display defined rules + */ +function loadAndDisplayDefinedRules(): array +{ + echo "Loading defined rules from rules/rules.php...\n"; + $definedRules = getDefinedRules(); + echo "Found " . count($definedRules) . " defined rules.\n\n"; + + return $definedRules; +} + +/** + * Find missing rules + */ +function findMissingRules(array $allRules, array $definedRules): array +{ + return array_diff($allRules, $definedRules, IGNORED_RULES); +} + +/** + * Display missing rules + */ +function displayMissingRules(array $missingRules): void +{ + echo "❌ Found " . count($missingRules) . " Rector rules that are not defined:\n\n"; + + $categorizedRules = categorizeRules($missingRules); + + foreach ($categorizedRules as $category => $rules) { + echo "📁 {$category}:\n"; + + foreach ($rules as $rule) { + echo sprintf(' - %s%s', $rule, PHP_EOL); + } + + echo "\n"; + } + + echo "💡 Tip: You can add missing rules to rules/rules.php using:\n"; + echo "use " . implode(";\nuse ", $missingRules) . ";\n"; +} + +/** + * Categorize rules by their namespace + */ +function categorizeRules(array $missingRules): array +{ + $categorizedRules = []; + + foreach ($missingRules as $rule) { + $parts = explode('\\', $rule); + + if (count($parts) >= 3) { + $category = $parts[2]; + $categorizedRules[$category][] = $rule; + } else { + $categorizedRules['Other'][] = $rule; + } + } + + ksort($categorizedRules); + + return $categorizedRules; +} + +// Run the script +main(); diff --git a/composer.json b/composer.json index 515c1bf..b8b8b2f 100644 --- a/composer.json +++ b/composer.json @@ -48,12 +48,13 @@ } }, "scripts": { - "phpcs:fix": "vendor/bin/phpcbf --standard=vendor/pekral/phpcs-rules/ruleset.xml --standard=vendor/pekral/phpcs-rules rules/ rector.php || true", - "phpcs": "vendor/bin/phpcs --standard=vendor/pekral/phpcs-rules rules/ rector.php -sp", - "check": "composer phpcs", - "rector": "vendor/bin/rector process rules/ rector.php --dry-run", - "rector:fix": "vendor/bin/rector process rules/ rector.php ", - "fix": "composer rector:fix && composer phpcs:fix" + "phpcs:fix": "vendor/bin/phpcbf --standard=vendor/pekral/phpcs-rules/ruleset.xml --standard=vendor/pekral/phpcs-rules rules/ build/ rector.php || true", + "phpcs": "vendor/bin/phpcs --standard=vendor/pekral/phpcs-rules rules/ build/ rector.php -sp", + "check": "composer phpcs && composer rector && composer check:missing-rules", + "rector": "vendor/bin/rector process rules/ build/ rector.php --dry-run", + "rector:fix": "vendor/bin/rector process rules/ build/ rector.php ", + "fix": "composer rector:fix && composer phpcs:fix", + "check:missing-rules": "php build/find-missing-rules.php" }, "config": { "prefer-stable": true,