Framework pull: auto-revert use statement changes before update
Class override system: .upstream file handling and restore logic Php_Fixer: Redirect use statements to correct manifest FQCN Fix: Only match PHP files in __find_class_fqcn_in_manifest Complete Php_Fixer use statement redirection implementation (checkpoint 2) WIP: Php_Fixer use statement redirection for class overrides (checkpoint) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -94,6 +94,12 @@ class Monoprogenic_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
// Step 1: Find all classes with Monoprogenic attribute
|
||||
$monoprogenic_classes = [];
|
||||
foreach ($files as $file => $file_metadata) {
|
||||
// Skip .upstream files - they are framework files overridden by rsx/
|
||||
$extension = $file_metadata['extension'] ?? '';
|
||||
if ($extension === 'php.upstream') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($file_metadata['attributes']['Monoprogenic'])) {
|
||||
$fqcn = $file_metadata['fqcn'] ?? null;
|
||||
if ($fqcn) {
|
||||
@@ -119,6 +125,12 @@ class Monoprogenic_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
{
|
||||
// Find all classes that extend from any Monoprogenic class
|
||||
foreach ($files as $file => $metadata) {
|
||||
// Skip .upstream files - they are framework files overridden by rsx/
|
||||
$extension = $metadata['extension'] ?? '';
|
||||
if ($extension === 'php.upstream') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$fqcn = $metadata['fqcn'] ?? null;
|
||||
if (!$fqcn || !class_exists($fqcn)) {
|
||||
continue;
|
||||
|
||||
@@ -38,6 +38,7 @@ class ExtensionRegistry
|
||||
*/
|
||||
protected const CORE_EXTENSIONS = [
|
||||
'php' => ['priority' => 100],
|
||||
'php.upstream' => ['priority' => 101], // Framework files renamed during class override
|
||||
'js' => ['priority' => 200],
|
||||
'jsx' => ['priority' => 200],
|
||||
'ts' => ['priority' => 200],
|
||||
|
||||
@@ -1355,23 +1355,17 @@ class Manifest
|
||||
// but we don't need to log it as it's not an error condition
|
||||
}
|
||||
|
||||
// Validate class names are unique (also handles rsx/ overriding app/RSpade/ classes)
|
||||
static::__check_unique_base_class_names();
|
||||
|
||||
// If a class override was detected (rsx/ overriding app/RSpade/), restart manifest build
|
||||
if (static::$_needs_manifest_restart) {
|
||||
console_debug('MANIFEST', 'Class override detected, restarting manifest build');
|
||||
goto manifest_start;
|
||||
}
|
||||
|
||||
// ==================================================================================
|
||||
// PHP FIXER INTEGRATION POINT
|
||||
// ==================================================================================
|
||||
// This is where automatic code fixes are applied before Phase 2 parsing.
|
||||
// CRITICAL: Php_Fixer MUST run BEFORE __check_unique_base_class_names() so that
|
||||
// when a class override is detected and framework files are renamed to .upstream,
|
||||
// all use statements have already been updated to point to the rsx/ location.
|
||||
// This prevents autoloader failures when the manifest restarts.
|
||||
//
|
||||
// WHAT PHP_FIXER DOES:
|
||||
// 1. Fixes namespaces to match file paths
|
||||
// 2. Removes/rebuilds use statements (strips Rsx\ and App\RSpade\ prefixes)
|
||||
// 2. Redirects use statements to correct FQCN based on manifest (rsx/ takes priority)
|
||||
// 3. Replaces FQCNs like \Rsx\Models\User_Model with simple names User_Model
|
||||
// 4. Adds #[Relationship] attributes to model ORM methods
|
||||
// 5. Removes leading backslashes from attributes: #[\Route] → #[Route]
|
||||
@@ -1381,11 +1375,6 @@ class Manifest
|
||||
// - If structure changed: Fixes ALL files (cascading updates needed)
|
||||
// - If structure unchanged: Fixes ONLY $files_to_process (incremental)
|
||||
//
|
||||
// WHY BEFORE PHASE 2:
|
||||
// - Phase 2 parses metadata from file content
|
||||
// - If we fix AFTER parsing, manifest would have old/incorrect metadata
|
||||
// - By fixing BEFORE, we parse the corrected content
|
||||
//
|
||||
// RE-PARSING LOOP BELOW:
|
||||
// - If Php_Fixer modified files, we MUST re-parse them
|
||||
// - This updates manifest with corrected namespace/class/FQCN data
|
||||
@@ -1422,6 +1411,21 @@ class Manifest
|
||||
}
|
||||
}
|
||||
|
||||
// ==================================================================================
|
||||
// CLASS OVERRIDE DETECTION
|
||||
// ==================================================================================
|
||||
// Check for duplicate class names. When rsx/ contains a class that also exists in
|
||||
// app/RSpade/, rename the framework file to .upstream and restart the manifest.
|
||||
// At this point, Php_Fixer has already updated use statements to point to rsx/.
|
||||
// ==================================================================================
|
||||
static::__check_unique_base_class_names();
|
||||
|
||||
// If a class override was detected (rsx/ overriding app/RSpade/), restart manifest build
|
||||
if (static::$_needs_manifest_restart) {
|
||||
console_debug('MANIFEST', 'Class override detected, restarting manifest build');
|
||||
goto manifest_start;
|
||||
}
|
||||
|
||||
// Phase 2 complete. At this point we have a list of all files, and for php and js, their class data
|
||||
|
||||
// =======================================================
|
||||
@@ -1706,14 +1710,25 @@ class Manifest
|
||||
/**
|
||||
* Check for duplicate base class names within the same file type
|
||||
*
|
||||
* When a class exists in both rsx/ and app/RSpade/, this is a developer override.
|
||||
* The framework version is renamed to .upstream and removed from indexing.
|
||||
* This method handles two scenarios:
|
||||
* 1. RESTORE: If a .upstream file exists but no active override exists, restore it
|
||||
* 2. OVERRIDE: When a class exists in both rsx/ and app/RSpade/, rename framework to .upstream
|
||||
*
|
||||
* Throws a fatal error if duplicates exist within the same area (both rsx/ or both app/RSpade/)
|
||||
*/
|
||||
protected static function __check_unique_base_class_names(): void
|
||||
{
|
||||
// Group classes by extension first, then by class name
|
||||
// ==================================================================================
|
||||
// STEP 1: Restore orphaned .upstream files
|
||||
// ==================================================================================
|
||||
// Check all php.upstream files - if their class no longer has an override in rsx/,
|
||||
// restore the framework file by renaming .upstream back to .php
|
||||
// ==================================================================================
|
||||
static::__restore_orphaned_upstream_files();
|
||||
|
||||
// ==================================================================================
|
||||
// STEP 2: Group classes by extension, then by class name
|
||||
// ==================================================================================
|
||||
$classes_by_extension = [];
|
||||
|
||||
foreach (static::$data['data']['files'] as $file => $metadata) {
|
||||
@@ -1721,6 +1736,11 @@ class Manifest
|
||||
$base_class_name = $metadata['class'];
|
||||
$extension = $metadata['extension'] ?? '';
|
||||
|
||||
// Skip php.upstream files - they're tracked separately for restoration
|
||||
if ($extension === 'php.upstream') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Group JavaScript-like files together
|
||||
if (in_array($extension, ['js', 'jsx', 'ts', 'tsx'])) {
|
||||
$extension = 'js';
|
||||
@@ -1738,7 +1758,9 @@ class Manifest
|
||||
}
|
||||
}
|
||||
|
||||
// Check for duplicates within each extension type
|
||||
// ==================================================================================
|
||||
// STEP 3: Check for duplicates and create overrides
|
||||
// ==================================================================================
|
||||
foreach ($classes_by_extension as $extension => $base_class_files) {
|
||||
foreach ($base_class_files as $class_name => $files) {
|
||||
if (count($files) > 1) {
|
||||
@@ -1779,6 +1801,58 @@ class Manifest
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore orphaned .upstream files when their override no longer exists
|
||||
*
|
||||
* Scans all php.upstream files in the manifest. For each one, checks if a .php file
|
||||
* with the same class name exists. If not, the override was removed and we should
|
||||
* restore the framework file.
|
||||
*/
|
||||
protected static function __restore_orphaned_upstream_files(): void
|
||||
{
|
||||
// Collect all PHP class names currently in the manifest
|
||||
$active_php_classes = [];
|
||||
foreach (static::$data['data']['files'] as $file => $metadata) {
|
||||
if (isset($metadata['extension']) && $metadata['extension'] === 'php' &&
|
||||
isset($metadata['class']) && !empty($metadata['class'])) {
|
||||
$active_php_classes[$metadata['class']] = $file;
|
||||
}
|
||||
}
|
||||
|
||||
// Check each .upstream file
|
||||
foreach (static::$data['data']['files'] as $file => $metadata) {
|
||||
if (!isset($metadata['extension']) || $metadata['extension'] !== 'php.upstream') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($metadata['class']) || empty($metadata['class'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$class_name = $metadata['class'];
|
||||
|
||||
// Check if an active .php file with this class exists
|
||||
if (isset($active_php_classes[$class_name])) {
|
||||
// Override still exists - keep .upstream as-is
|
||||
continue;
|
||||
}
|
||||
|
||||
// No active override - restore this framework file
|
||||
$upstream_path = base_path($file);
|
||||
$restored_path = preg_replace('/\.upstream$/', '', $upstream_path);
|
||||
|
||||
if (file_exists($upstream_path) && !file_exists($restored_path)) {
|
||||
rename($upstream_path, $restored_path);
|
||||
console_debug('MANIFEST', "Class restore: {$class_name} - restored {$file} to .php");
|
||||
|
||||
// Remove the .upstream entry from manifest
|
||||
unset(static::$data['data']['files'][$file]);
|
||||
|
||||
static::$_needs_manifest_restart = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collate files by class names and build inheritance indices
|
||||
*
|
||||
@@ -2515,9 +2589,11 @@ class Manifest
|
||||
$stat = stat($absolute_path);
|
||||
$extension = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
|
||||
|
||||
// Handle .blade.php as special case
|
||||
// Handle compound extensions as special cases
|
||||
if (str_ends_with($file_path, '.blade.php')) {
|
||||
$extension = 'blade.php';
|
||||
} elseif (str_ends_with($file_path, '.php.upstream')) {
|
||||
$extension = 'php.upstream';
|
||||
}
|
||||
|
||||
$data = [
|
||||
@@ -2550,6 +2626,14 @@ class Manifest
|
||||
}
|
||||
break;
|
||||
|
||||
case 'php.upstream':
|
||||
// Parse upstream files to extract class metadata
|
||||
// These are framework files that were renamed when an rsx/ override was created
|
||||
// Php_Fixer only runs on extension 'php', so upstream files are safe
|
||||
$php_metadata = \App\RSpade\Core\PHP\Php_Parser::parse($absolute_path, static::$data);
|
||||
$data = array_merge($data, $php_metadata);
|
||||
break;
|
||||
|
||||
case 'js':
|
||||
console_debug('BUILD', "Parsing JS file: {$file_path}");
|
||||
$js_metadata = \App\RSpade\Core\JsParsers\Js_Parser::extract_metadata($absolute_path);
|
||||
|
||||
@@ -428,11 +428,11 @@ class Php_Fixer
|
||||
$tokens = token_get_all($content);
|
||||
|
||||
// Extract existing non-Rsx\ use statement simple names BEFORE removing Rsx\ statements
|
||||
$existing_non_rsx_simple_names = self::__extract_existing_non_rsx_use_simple_names($tokens, $file_path);
|
||||
$existing_non_rsx_simple_names = self::__extract_existing_non_rsx_use_simple_names($tokens, $file_path, $step_2_manifest_data);
|
||||
|
||||
// Step 1: Remove all use statements that start with Rsx\
|
||||
// We'll rebuild these based on actual usage
|
||||
$content = self::__remove_rsx_use_statements($content, $tokens, $file_path);
|
||||
// Step 1: Process use statements - remove, keep, or redirect to correct FQCN
|
||||
// The manifest is the source of truth for where classes are defined
|
||||
$content = self::__remove_rsx_use_statements($content, $tokens, $file_path, $step_2_manifest_data);
|
||||
|
||||
// Step 2: For both rsx/ and app/RSpade/ files - fix fully qualified class names
|
||||
// Replace \Rsx\Namespace\ClassName with just ClassName if the class exists uniquely
|
||||
@@ -507,9 +507,11 @@ class Php_Fixer
|
||||
* Extract simple class names from existing use statements that won't be removed
|
||||
*
|
||||
* @param array $tokens Parsed tokens
|
||||
* @param string $file_path File being processed
|
||||
* @param array $step_2_manifest_data Manifest data for class lookups
|
||||
* @return array Simple class names already in use (e.g., ['Session', 'Request', 'Cache'])
|
||||
*/
|
||||
private static function __extract_existing_non_rsx_use_simple_names(array $tokens, string $file_path): array
|
||||
private static function __extract_existing_non_rsx_use_simple_names(array $tokens, string $file_path, array &$step_2_manifest_data): array
|
||||
{
|
||||
$simple_names = [];
|
||||
$i = 0;
|
||||
@@ -569,14 +571,19 @@ class Php_Fixer
|
||||
);
|
||||
}
|
||||
|
||||
// Check if this use statement will be kept (not removed)
|
||||
$will_be_removed = self::__should_remove_use_statement($use_fqcn, $file_path);
|
||||
// Check if this use statement will be kept (not removed/redirected)
|
||||
$action = self::__should_remove_use_statement($use_fqcn, $file_path, $step_2_manifest_data);
|
||||
|
||||
if (!$will_be_removed) {
|
||||
// Extract simple name (last part after final backslash)
|
||||
if ($action === false) {
|
||||
// Keeping as-is - extract simple name
|
||||
$simple_name = substr(strrchr($use_fqcn, '\\'), 1) ?: $use_fqcn;
|
||||
$simple_names[$simple_name] = true;
|
||||
} elseif (is_string($action)) {
|
||||
// Redirecting to new FQCN - extract simple name from new FQCN
|
||||
$simple_name = substr(strrchr($action, '\\'), 1) ?: $action;
|
||||
$simple_names[$simple_name] = true;
|
||||
}
|
||||
// If $action === true, it's being removed, don't add to simple_names
|
||||
}
|
||||
|
||||
$i++;
|
||||
@@ -586,36 +593,44 @@ class Php_Fixer
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a use statement should be removed
|
||||
* Determine what action to take on a use statement
|
||||
*
|
||||
* Returns one of:
|
||||
* - false: Keep as-is (vendor/Laravel classes, or already correct)
|
||||
* - true: Remove completely (framework dev mode for Rsx\ classes, or attribute stubs)
|
||||
* - string: Update to this FQCN (use statement points to wrong FQCN for this class)
|
||||
*
|
||||
* The manifest is the source of truth. If a class exists in the manifest,
|
||||
* the use statement should point to the manifest's FQCN for that class.
|
||||
*
|
||||
* @param string $use_fqcn Fully qualified class name from use statement
|
||||
* @return bool True if should be removed, false if should be kept
|
||||
* @param string $file_path File being processed
|
||||
* @param array $step_2_manifest_data Manifest data for class lookups
|
||||
* @return bool|string False=keep, true=remove, string=update to new FQCN
|
||||
*/
|
||||
private static function __should_remove_use_statement(string $use_fqcn, string $file_path): bool
|
||||
private static function __should_remove_use_statement(string $use_fqcn, string $file_path, array &$step_2_manifest_data): bool|string
|
||||
{
|
||||
// Get excluded directories from config
|
||||
$excluded_dirs = config('rsx.manifest.excluded_dirs', ['vendor', 'node_modules', 'storage', '.git', 'public', 'resource', 'archived']);
|
||||
|
||||
// Extract namespace parts (everything except the final class name)
|
||||
// Extract simple class name and namespace
|
||||
$last_backslash = strrpos($use_fqcn, '\\');
|
||||
$simple_name = $last_backslash !== false ? substr($use_fqcn, $last_backslash + 1) : $use_fqcn;
|
||||
|
||||
if ($last_backslash !== false) {
|
||||
$namespace_part = substr($use_fqcn, 0, $last_backslash);
|
||||
|
||||
// Check if namespace contains any excluded directory keyword (case insensitive)
|
||||
// These are protected namespaces (vendor, Laravel, etc.) - never modify
|
||||
foreach ($excluded_dirs as $excluded_dir) {
|
||||
if (stripos($namespace_part, $excluded_dir) !== false) {
|
||||
return false; // Protected - don't remove
|
||||
return false; // Protected - don't touch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove "Route" explicitly, this refers to the laravel Route:: helper which we just dont use. If the developer must, they should use the fqcn of the laravel route helper. The existience of this confuses the ide with how to deal with attributes.
|
||||
if ($use_fqcn == 'Route' && (substr($file_path, 0, 4) == 'rsx/' || substr($file_path, 0, 11) == 'app/RSpade/')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Remove if starts with Rsx\ or App\RSpade\
|
||||
if (str_starts_with($use_fqcn, 'Rsx\\') || str_starts_with($use_fqcn, 'App\\RSpade\\')) {
|
||||
// Remove "Route" explicitly - refers to Laravel Route:: helper which conflicts with our #[Route] attribute
|
||||
if ($use_fqcn == 'Route' && (str_starts_with($file_path, 'rsx/') || str_starts_with($file_path, 'app/RSpade/'))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -633,17 +648,87 @@ class Php_Fixer
|
||||
}
|
||||
}
|
||||
|
||||
// Look up the correct FQCN for this class in the manifest
|
||||
$correct_fqcn = self::__find_class_fqcn_in_manifest($simple_name, $step_2_manifest_data);
|
||||
|
||||
if ($correct_fqcn !== null) {
|
||||
// Class exists in manifest - check if use statement is correct
|
||||
if ($use_fqcn === $correct_fqcn) {
|
||||
// Already pointing to correct FQCN
|
||||
$is_framework_developer = config('rsx.code_quality.is_framework_developer', false);
|
||||
|
||||
// In framework developer mode, remove Rsx\ use statements (autoloader finds them)
|
||||
if ($is_framework_developer && str_starts_with($use_fqcn, 'Rsx\\')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // Keep as-is
|
||||
} else {
|
||||
// Use statement points to wrong FQCN
|
||||
$is_framework_developer = config('rsx.code_quality.is_framework_developer', false);
|
||||
|
||||
if ($is_framework_developer && str_starts_with($correct_fqcn, 'Rsx\\')) {
|
||||
// Framework developer mode: remove, autoloader will find Rsx\ classes
|
||||
return true;
|
||||
}
|
||||
|
||||
// Update to correct FQCN
|
||||
return $correct_fqcn;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if this is a Rsx\ or App\RSpade\ use statement for a class NOT in manifest
|
||||
// These should be removed (will be rebuilt based on actual usage)
|
||||
if (str_starts_with($use_fqcn, 'Rsx\\') || str_starts_with($use_fqcn, 'App\\RSpade\\')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // Keep all other use statements
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove existing Rsx\ use statements from the file
|
||||
* Find the correct FQCN for a PHP class by simple name in the manifest
|
||||
*
|
||||
* Searches the entire manifest for the class. Returns the FQCN from the manifest,
|
||||
* which is the authoritative source for where classes are defined.
|
||||
*
|
||||
* @param string $simple_name Simple class name (e.g., "User_Model")
|
||||
* @param array $step_2_manifest_data Manifest data
|
||||
* @return string|null FQCN if found in manifest, null otherwise
|
||||
*/
|
||||
private static function __find_class_fqcn_in_manifest(string $simple_name, array &$step_2_manifest_data): ?string
|
||||
{
|
||||
foreach ($step_2_manifest_data['data']['files'] ?? [] as $manifest_file => $metadata) {
|
||||
// Only check PHP files (not JS classes with same name)
|
||||
if (!str_ends_with($manifest_file, '.php')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only check files in rsx/ or app/RSpade/
|
||||
if (!str_starts_with($manifest_file, 'rsx/') && !str_starts_with($manifest_file, 'app/RSpade/')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if this file defines the class we're looking for
|
||||
if (isset($metadata['class']) && $metadata['class'] === $simple_name) {
|
||||
// Generate FQCN from file path
|
||||
return self::__calculate_namespace_from_path($manifest_file) . '\\' . $simple_name;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process use statements - remove, keep, or redirect as needed
|
||||
*
|
||||
* @param string $content File content
|
||||
* @param array $tokens Parsed tokens
|
||||
* @return string Content with Rsx use statements removed
|
||||
* @param string $file_path File being processed
|
||||
* @param array $step_2_manifest_data Manifest data for class lookups
|
||||
* @return string Content with use statements processed
|
||||
*/
|
||||
private static function __remove_rsx_use_statements(string $content, array $tokens, string $file_path): string
|
||||
private static function __remove_rsx_use_statements(string $content, array $tokens, string $file_path, array &$step_2_manifest_data): string
|
||||
{
|
||||
$output = '';
|
||||
$i = 0;
|
||||
@@ -687,10 +772,10 @@ class Php_Fixer
|
||||
|
||||
$use_statement = trim($use_statement);
|
||||
|
||||
// Check if this use statement should be kept
|
||||
$should_remove = self::__should_remove_use_statement($use_statement, $file_path);
|
||||
// Check what action to take on this use statement
|
||||
$action = self::__should_remove_use_statement($use_statement, $file_path, $step_2_manifest_data);
|
||||
|
||||
if (!$should_remove) {
|
||||
if ($action === false) {
|
||||
// Keep it - go back and add the original use statement
|
||||
for ($j = $use_start; $j <= $i; $j++) {
|
||||
if ($j < count($tokens)) {
|
||||
@@ -701,8 +786,11 @@ class Php_Fixer
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif (is_string($action)) {
|
||||
// Redirect - output a new use statement with the correct FQCN
|
||||
$output .= "use {$action};";
|
||||
}
|
||||
// Otherwise skip it (don't add to output)
|
||||
// If $action === true, skip it entirely (don't add to output)
|
||||
} else {
|
||||
// Add token to output
|
||||
if (is_array($token)) {
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
namespace App\RSpade\Core\SPA;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Session;
|
||||
use App\RSpade\Core\Controller\Rsx_Controller_Abstract;
|
||||
use App\RSpade\Core\Manifest\Manifest;
|
||||
use App\RSpade\Core\Session\Session;
|
||||
|
||||
/**
|
||||
* Spa_Session_Controller - Session validation endpoint for SPA navigation
|
||||
|
||||
@@ -216,6 +216,77 @@ if [ -n "$UPSTREAM_FILES" ]; then
|
||||
done
|
||||
fi
|
||||
|
||||
# Step 3: Restore files with ONLY use statement changes
|
||||
# When classes are overridden in rsx/, Php_Fixer updates use statements in system/ files
|
||||
# to point to the Rsx\ namespace. These changes should be reverted before framework update.
|
||||
# We only auto-revert files where ALL changes are use statement modifications.
|
||||
echo " Checking for auto-fixable use statement changes..."
|
||||
|
||||
MODIFIED_SYSTEM_FILES=$(git diff --name-only -- . ":(exclude)rsx" 2>/dev/null | grep "\.php$" || true)
|
||||
USE_STMT_REVERTED=0
|
||||
|
||||
if [ -n "$MODIFIED_SYSTEM_FILES" ]; then
|
||||
while IFS= read -r modified_file; do
|
||||
if [ -z "$modified_file" ] || [ ! -f "$modified_file" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Get the diff for this file, check if ALL changed lines are use statements
|
||||
# Changed lines start with + or - (excluding the diff header lines +++ and ---)
|
||||
DIFF_CONTENT=$(git diff -- "$modified_file" 2>/dev/null || true)
|
||||
|
||||
if [ -z "$DIFF_CONTENT" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Extract changed lines (+ or - at start, not +++ or ---)
|
||||
# Then check if all of them are use statements or empty
|
||||
ALL_USE_STATEMENTS=true
|
||||
|
||||
while IFS= read -r line; do
|
||||
# Skip diff metadata lines
|
||||
case "$line" in
|
||||
"+++"*|"---"*|"@@"*|"diff "*|"index "*) continue ;;
|
||||
esac
|
||||
|
||||
# Check lines that start with + or - (actual changes)
|
||||
case "$line" in
|
||||
"+"*|"-"*)
|
||||
# Remove the leading +/- and trim whitespace
|
||||
content="${line#[+-]}"
|
||||
content=$(echo "$content" | sed 's/^[[:space:]]*//')
|
||||
|
||||
# Empty lines are OK
|
||||
if [ -z "$content" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Use statements are OK (with or without leading backslash)
|
||||
if echo "$content" | grep -qE "^use[[:space:]]+(\\\\)?[A-Za-z]"; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Any other change means this file has non-use-statement modifications
|
||||
ALL_USE_STATEMENTS=false
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done <<< "$DIFF_CONTENT"
|
||||
|
||||
# If all changes were use statements, revert the file
|
||||
if [ "$ALL_USE_STATEMENTS" = true ]; then
|
||||
if git checkout HEAD -- "$modified_file" 2>/dev/null; then
|
||||
echo " ✓ Reverted use statements: $modified_file"
|
||||
USE_STMT_REVERTED=$((USE_STMT_REVERTED + 1))
|
||||
fi
|
||||
fi
|
||||
done <<< "$MODIFIED_SYSTEM_FILES"
|
||||
fi
|
||||
|
||||
if [ "$USE_STMT_REVERTED" -gt 0 ]; then
|
||||
echo " ✓ Reverted $USE_STMT_REVERTED file(s) with use statement changes"
|
||||
fi
|
||||
|
||||
echo " ✓ Override cleanup complete"
|
||||
echo ""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user