Enhance refactor commands with controller-aware Route() updates and fix code quality violations
Add semantic token highlighting for 'that' variable and comment file references in VS Code extension Add Phone_Text_Input and Currency_Input components with formatting utilities Implement client widgets, form standardization, and soft delete functionality Add modal scroll lock and update documentation Implement comprehensive modal system with form integration and validation Fix modal component instantiation using jQuery plugin API Implement modal system with responsive sizing, queuing, and validation support Implement form submission with validation, error handling, and loading states Implement country/state selectors with dynamic data loading and Bootstrap styling Revert Rsx::Route() highlighting in Blade/PHP files Target specific PHP scopes for Rsx::Route() highlighting in Blade Expand injection selector for Rsx::Route() highlighting Add custom syntax highlighting for Rsx::Route() and Rsx.Route() calls Update jqhtml packages to v2.2.165 Add bundle path validation for common mistakes (development mode only) Create Ajax_Select_Input widget and Rsx_Reference_Data controller Create Country_Select_Input widget with default country support Initialize Tom Select on Select_Input widgets Add Tom Select bundle for enhanced select dropdowns Implement ISO 3166 geographic data system for country/region selection Implement widget-based form system with disabled state support 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1171,7 +1171,7 @@ class Manifest
|
||||
console_debug('MANIFEST', 'Cache file written successfully', [
|
||||
'path' => $cache_file,
|
||||
'size' => $file_size,
|
||||
'permissions' => $file_perms
|
||||
'permissions' => $file_perms,
|
||||
]);
|
||||
} else {
|
||||
console_debug_force('MANIFEST', 'WARNING: Cache file does not exist after rebuild!', $cache_file);
|
||||
@@ -1262,6 +1262,7 @@ class Manifest
|
||||
|
||||
// Extract just the class name (last part after final backslash)
|
||||
$parts = explode('\\', $class_name);
|
||||
|
||||
return end($parts);
|
||||
}
|
||||
|
||||
@@ -1612,146 +1613,9 @@ class Manifest
|
||||
// ------------------------------------------------------------------------
|
||||
// ---- Private / Protected Methods:
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Generate JavaScript stub files for PHP controllers with Internal API methods
|
||||
* These stubs enable IDE autocomplete for Ajax.call() invocations from JavaScript
|
||||
*/
|
||||
protected static function _generate_js_api_stubs(): void
|
||||
{
|
||||
$stub_dir = storage_path('rsx-build/js-stubs');
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
if (!is_dir($stub_dir)) {
|
||||
mkdir($stub_dir, 0755, true);
|
||||
}
|
||||
|
||||
// Track generated stub files for cleanup
|
||||
$generated_stubs = [];
|
||||
|
||||
// Process each file
|
||||
foreach (static::$data['data']['files'] as $file_path => &$metadata) {
|
||||
// Skip non-PHP files
|
||||
if (!isset($metadata['extension']) || $metadata['extension'] !== 'php') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip files without classes or public static methods
|
||||
if (!isset($metadata['class']) || !isset($metadata['public_static_methods'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if this is a controller (extends Rsx_Controller_Abstract)
|
||||
$class_name = $metadata['class'] ?? '';
|
||||
if (!static::php_is_subclass_of($class_name, 'Rsx_Controller_Abstract')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if this controller has any Ajax_Endpoint methods
|
||||
$api_methods = [];
|
||||
foreach ($metadata['public_static_methods'] as $method_name => $method_info) {
|
||||
if (!isset($method_info['attributes'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for Ajax_Endpoint attribute
|
||||
$has_api_internal = false;
|
||||
foreach ($method_info['attributes'] as $attr_name => $attr_data) {
|
||||
if ($attr_name === 'Ajax_Endpoint' ||
|
||||
basename(str_replace('\\', '/', $attr_name)) === 'Ajax_Endpoint') {
|
||||
$has_api_internal = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($has_api_internal && isset($method_info['static']) && $method_info['static']) {
|
||||
$api_methods[$method_name] = [
|
||||
'name' => $method_name,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// If no API methods, remove js_stub property if it exists and skip
|
||||
if (empty($api_methods)) {
|
||||
if (isset($metadata['js_stub'])) {
|
||||
unset($metadata['js_stub']);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Generate stub filename and paths
|
||||
$controller_name = $metadata['class'];
|
||||
$stub_filename = static::_sanitize_stub_filename($controller_name) . '.js';
|
||||
$stub_relative_path = 'storage/rsx-build/js-stubs/' . $stub_filename;
|
||||
$stub_full_path = base_path($stub_relative_path);
|
||||
|
||||
// Check if stub needs regeneration
|
||||
$needs_regeneration = true;
|
||||
if (file_exists($stub_full_path)) {
|
||||
// Get mtime of source PHP file
|
||||
$source_mtime = $metadata['mtime'] ?? 0;
|
||||
$stub_mtime = filemtime($stub_full_path);
|
||||
|
||||
// Only regenerate if source is newer than stub
|
||||
if ($stub_mtime >= $source_mtime) {
|
||||
// Also check if the API methods signature has changed
|
||||
// by comparing a hash of the methods
|
||||
$api_methods_hash = md5(json_encode($api_methods));
|
||||
$old_api_hash = $metadata['api_methods_hash'] ?? '';
|
||||
|
||||
if ($api_methods_hash === $old_api_hash) {
|
||||
$needs_regeneration = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store the API methods hash for future comparisons
|
||||
$metadata['api_methods_hash'] = md5(json_encode($api_methods));
|
||||
|
||||
if ($needs_regeneration) {
|
||||
// Generate stub content
|
||||
$stub_content = static::_generate_stub_content($controller_name, $api_methods);
|
||||
|
||||
// Write stub file
|
||||
file_put_contents($stub_full_path, $stub_content);
|
||||
}
|
||||
|
||||
$generated_stubs[] = $stub_filename;
|
||||
|
||||
// Add js_stub property to manifest data (relative path)
|
||||
$metadata['js_stub'] = $stub_relative_path;
|
||||
|
||||
// Add the stub file itself to the manifest
|
||||
// This is critical because storage/rsx-build/js-stubs is not in scan directories
|
||||
$stat = stat($stub_full_path);
|
||||
static::$data['data']['files'][$stub_relative_path] = [
|
||||
'file' => $stub_relative_path,
|
||||
'hash' => sha1_file($stub_full_path),
|
||||
'mtime' => $stat['mtime'],
|
||||
'size' => $stat['size'],
|
||||
'extension' => 'js',
|
||||
'class' => $controller_name,
|
||||
'is_stub' => true, // Mark this as a generated stub
|
||||
'source_controller' => $file_path, // Reference to the source controller
|
||||
];
|
||||
}
|
||||
|
||||
// Clean up orphaned stub files (both from disk and manifest)
|
||||
$existing_stubs = glob($stub_dir . '/*.js');
|
||||
foreach ($existing_stubs as $existing_stub) {
|
||||
$filename = basename($existing_stub);
|
||||
if (!in_array($filename, $generated_stubs)) {
|
||||
// Remove from disk
|
||||
unlink($existing_stub);
|
||||
|
||||
// Remove from manifest
|
||||
$stub_relative_path = 'storage/rsx-build/js-stubs/' . $filename;
|
||||
if (isset(static::$data['data']['files'][$stub_relative_path])) {
|
||||
unset(static::$data['data']['files'][$stub_relative_path]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// DEAD CODE REMOVED: _generate_js_api_stubs()
|
||||
// Stub generation now handled by Controller_BundleIntegration
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Generate JavaScript stub files for ORM models
|
||||
@@ -2093,34 +1957,10 @@ class Manifest
|
||||
return strtolower(str_replace('_', '-', $controller_name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate JavaScript stub content for a controller
|
||||
*/
|
||||
private static function _generate_stub_content(string $controller_name, array $api_methods): string
|
||||
{
|
||||
$content = "/**\n";
|
||||
$content .= " * Auto-generated JavaScript stub for {$controller_name}\n";
|
||||
$content .= ' * Generated by RSX Manifest at ' . date('Y-m-d H:i:s') . "\n";
|
||||
$content .= " * DO NOT EDIT - This file is automatically regenerated\n";
|
||||
$content .= " */\n\n";
|
||||
|
||||
$content .= "class {$controller_name} {\n";
|
||||
|
||||
foreach ($api_methods as $method_name => $method_info) {
|
||||
$content .= " /**\n";
|
||||
$content .= " * Call {$controller_name}::{$method_name} via Ajax.call()\n";
|
||||
$content .= " * @param {...*} args - Arguments to pass to the method\n";
|
||||
$content .= " * @returns {Promise<*>}\n";
|
||||
$content .= " */\n";
|
||||
$content .= " static async {$method_name}(...args) {\n";
|
||||
$content .= " return Ajax.call('{$controller_name}', '{$method_name}', args);\n";
|
||||
$content .= " }\n\n";
|
||||
}
|
||||
|
||||
$content .= "}\n";
|
||||
|
||||
return $content;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
// DEAD CODE REMOVED: _generate_stub_content()
|
||||
// Stub generation now handled by Controller_BundleIntegration
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get or create the kernel instance
|
||||
@@ -2936,6 +2776,7 @@ class Manifest
|
||||
// Check if method calls parent::methodname()
|
||||
// Use the correct file for trait methods
|
||||
$source_file_to_read = $is_from_trait ? $method_file : $file_path;
|
||||
|
||||
try {
|
||||
$method_source = file($source_file_to_read);
|
||||
$start_line = $method->getStartLine() - 1;
|
||||
@@ -3488,6 +3329,7 @@ class Manifest
|
||||
|
||||
$has_route = false;
|
||||
$has_ajax_endpoint = false;
|
||||
$has_task = false;
|
||||
|
||||
foreach ($method_info['attributes'] as $attr_name => $attr_instances) {
|
||||
if ($attr_name === 'Route' || str_ends_with($attr_name, '\\Route')) {
|
||||
@@ -3496,17 +3338,26 @@ class Manifest
|
||||
if ($attr_name === 'Ajax_Endpoint' || str_ends_with($attr_name, '\\Ajax_Endpoint')) {
|
||||
$has_ajax_endpoint = true;
|
||||
}
|
||||
if ($attr_name === 'Task' || str_ends_with($attr_name, '\\Task')) {
|
||||
$has_task = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($has_route && $has_ajax_endpoint) {
|
||||
// Check for conflicting attributes
|
||||
$conflicts = [];
|
||||
if ($has_route) $conflicts[] = 'Route';
|
||||
if ($has_ajax_endpoint) $conflicts[] = 'Ajax_Endpoint';
|
||||
if ($has_task) $conflicts[] = 'Task';
|
||||
|
||||
if (count($conflicts) > 1) {
|
||||
$class_name = $metadata['class'] ?? 'Unknown';
|
||||
|
||||
throw new \RuntimeException(
|
||||
"Controller action cannot have both Route and Ajax_Endpoint attributes.\n" .
|
||||
"Method cannot have multiple execution type attributes: " . implode(', ', $conflicts) . "\n" .
|
||||
"Class: {$class_name}\n" .
|
||||
"Method: {$method_name}\n" .
|
||||
"File: {$file_path}\n" .
|
||||
'A controller action must be either a web route OR an AJAX endpoint, not both.'
|
||||
'A method must be either a Route, Ajax_Endpoint, OR Task, not multiple types.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user