Add class override system for framework customization

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2025-12-10 02:37:07 +00:00
parent 025bb2d768
commit ecc386301f
6 changed files with 337 additions and 4 deletions

View File

@@ -1272,8 +1272,9 @@ class Manifest
{
manifest_start:
// Reset manifest restart flag at the beginning of each pass
// Reset caches at the beginning of each pass (important for restarts)
static::$_needs_manifest_restart = false;
self::$__get_rsx_files_cache = null;
// Reset manifest structure, retaining only existing files data
$existing_files = static::$data['data']['files'] ?? [];
@@ -1354,9 +1355,15 @@ class Manifest
// but we don't need to log it as it's not an error condition
}
// Validate class names are unique.
// 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
// ==================================================================================
@@ -1438,6 +1445,12 @@ class Manifest
// so that abstract property is available for subclass filtering
static::__collate_files_by_classes();
// Check if a class override was detected and framework file renamed
if (static::$_needs_manifest_restart) {
console_debug('MANIFEST', 'Class override detected, restarting manifest build');
goto manifest_start;
}
// Build event handler index from attributes
static::__build_event_handler_index();
@@ -1692,7 +1705,11 @@ class Manifest
/**
* Check for duplicate base class names within the same file type
* Throws a fatal error if any base class name appears in multiple files of the same 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.
*
* 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
{
@@ -1725,6 +1742,31 @@ class Manifest
foreach ($classes_by_extension as $extension => $base_class_files) {
foreach ($base_class_files as $class_name => $files) {
if (count($files) > 1) {
// Check if this is a valid override (rsx/ vs app/RSpade/)
$rsx_files = array_filter($files, fn($f) => str_starts_with($f, 'rsx/'));
$framework_files = array_filter($files, fn($f) => str_starts_with($f, 'app/RSpade/'));
// Valid override: exactly one file in rsx/, rest in app/RSpade/
if (count($rsx_files) === 1 && count($framework_files) >= 1) {
// Rename framework files to .upstream and remove from manifest
foreach ($framework_files as $framework_file) {
$full_framework_path = base_path($framework_file);
$upstream_path = $full_framework_path . '.upstream';
if (file_exists($full_framework_path) && !file_exists($upstream_path)) {
rename($full_framework_path, $upstream_path);
console_debug('MANIFEST', "Class override: {$class_name} - moved {$framework_file} to .upstream");
}
// Remove from manifest data so it won't be indexed
unset(static::$data['data']['files'][$framework_file]);
}
static::$_needs_manifest_restart = true;
continue;
}
// Not a valid override - throw error
$file_type = $extension === 'php' ? 'PHP' : ($extension === 'js' ? 'JavaScript' : $extension);
throw new \RuntimeException(
@@ -1762,9 +1804,23 @@ class Manifest
// Step 1: Index files by class name for quick lookups
// This creates a map of className => filename (not full metadata to save space)
// NOTE: Class override detection (rsx/ vs app/RSpade/) happens earlier in __check_unique_base_class_names()
foreach (static::$data['data']['files'] as $file => $filedata) {
if ($filedata['extension'] == $ext && !empty($filedata['class'])) {
static::$data['data'][$ext . '_classes'][$filedata['class']] = $file;
$class_name = $filedata['class'];
// Duplicates should have been caught by __check_unique_base_class_names()
// but check here as a safety net
if (isset(static::$data['data'][$ext . '_classes'][$class_name])) {
$existing_file = static::$data['data'][$ext . '_classes'][$class_name];
throw new \RuntimeException(
"Duplicate {$ext} class detected: {$class_name}\n" .
"Found in:\n - {$existing_file}\n - {$file}\n" .
"Class names must be unique across the codebase."
);
}
static::$data['data'][$ext . '_classes'][$class_name] = $file;
}
}