Fix code quality violations and enhance ROUTE-EXISTS-01 rule
Implement JQHTML function cache ID system and fix bundle compilation Implement underscore prefix for system tables Fix JS syntax linter to support decorators and grant exception to Task system SPA: Update planning docs and wishlists with remaining features SPA: Document Navigation API abandonment and future enhancements Implement SPA browser integration with History API (Phase 1) Convert contacts view page to SPA action Convert clients pages to SPA actions and document conversion procedure SPA: Merge GET parameters and update documentation Implement SPA route URL generation in JavaScript and PHP Implement SPA bootstrap controller architecture Add SPA routing manual page (rsx:man spa) Add SPA routing documentation to CLAUDE.md Phase 4 Complete: Client-side SPA routing implementation Update get_routes() consumers for unified route structure Complete SPA Phase 3: PHP-side route type detection and is_spa flag Restore unified routes structure and Manifest_Query class Refactor route indexing and add SPA infrastructure Phase 3 Complete: SPA route registration in manifest Implement SPA Phase 2: Extract router code and test decorators Rename Jqhtml_Component to Component and complete SPA foundation setup 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -64,7 +64,7 @@ The Code Quality system is a modular, extensible framework for enforcing coding
|
||||
|
||||
1. **JqhtmlInlineScriptRule** (JQHTML-INLINE-01)
|
||||
- Prohibits inline <script> and <style> tags in .jqhtml templates
|
||||
- Enforces component class pattern with Jqhtml_Component
|
||||
- Enforces component class pattern with Component
|
||||
- Requires separate .js and .scss files
|
||||
- Severity: Critical
|
||||
- Runs at manifest-time
|
||||
@@ -187,15 +187,171 @@ php artisan rsx:check rsx/
|
||||
php artisan rsx:check app/Models/User.php
|
||||
```
|
||||
|
||||
### Exception Comments
|
||||
### Exception Granting System
|
||||
|
||||
Add exception comments to bypass specific violations:
|
||||
The code quality system supports granting exceptions to allow specific violations when justified. Exceptions are granted via specially formatted comments in the source files.
|
||||
|
||||
#### Exception Comment Format
|
||||
|
||||
```
|
||||
@{RULE-ID}-EXCEPTION - Optional rationale
|
||||
```
|
||||
|
||||
**Naming Convention:**
|
||||
- Use the exact rule ID from `get_id()` method
|
||||
- Add `-EXCEPTION` suffix
|
||||
- Examples: `@PHP-NAMING-01-EXCEPTION`, `@JS-DEFENSIVE-01-EXCEPTION`, `@FILE-CASE-01-EXCEPTION`
|
||||
|
||||
#### Exception Placement
|
||||
|
||||
**Line-Level Exceptions** (most common):
|
||||
Place the exception comment on the same line as the violation OR on the line immediately before it.
|
||||
|
||||
```php
|
||||
// @RULE-ID-EXCEPTION (e.g., @PHP-NAMING-01-EXCEPTION)
|
||||
// Code that would normally violate rules
|
||||
// Same-line exception
|
||||
if (key && key.startsWith('rsx::')) { // @JS-DEFENSIVE-01-EXCEPTION - storage.key() can return null
|
||||
|
||||
// Previous-line exception
|
||||
// @PHP-REFLECT-01-EXCEPTION - Test runner needs ReflectionClass for filtering
|
||||
if ($reflection->isAbstract()) {
|
||||
continue;
|
||||
}
|
||||
```
|
||||
|
||||
**File-Level Exceptions** (for entire file):
|
||||
Place at the top of the file, after namespace/use statements, before the main docblock.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace App\RSpade\Core\Ajax;
|
||||
|
||||
use SomeClass;
|
||||
|
||||
// @FILE-SUBCLASS-01-EXCEPTION
|
||||
|
||||
/**
|
||||
* Class docblock
|
||||
*/
|
||||
class MyClass {
|
||||
```
|
||||
|
||||
**Docblock Exceptions** (for method/class):
|
||||
Place inside the docblock using JSDoc/PHPDoc style.
|
||||
|
||||
```php
|
||||
/**
|
||||
* Check if a method is overriding a parent method
|
||||
*
|
||||
* @PHP-REFLECT-02-EXCEPTION: This method needs ReflectionClass to check parent methods
|
||||
* from Laravel framework classes which are not tracked in the manifest.
|
||||
*/
|
||||
protected function is_overriding_parent_method($class_name, $method_name) {
|
||||
```
|
||||
|
||||
#### Implementing Exception Handling in Rules
|
||||
|
||||
**NOT all rules implement exception handling** - it must be added per-rule. Approximately 31 of 111 rules currently support exceptions.
|
||||
|
||||
**To check if a rule supports exceptions:**
|
||||
|
||||
1. Open the rule file in `/system/app/RSpade/CodeQuality/Rules/`
|
||||
2. Search for `EXCEPTION` in the file
|
||||
3. If found, the rule implements exception checking
|
||||
4. If not found, exceptions will be ignored by that rule
|
||||
|
||||
**To implement exception handling in a rule:**
|
||||
|
||||
Add a check before calling `add_violation()`. The exact implementation depends on rule structure:
|
||||
|
||||
**Line-by-line checking pattern:**
|
||||
|
||||
```php
|
||||
public function check(string $file_path, string $contents, array $metadata = []): void
|
||||
{
|
||||
$lines = explode("\n", $contents);
|
||||
|
||||
foreach ($lines as $line_number => $line) {
|
||||
$actual_line_number = $line_number + 1;
|
||||
|
||||
// Skip if line has exception comment
|
||||
if (str_contains($line, '@' . $this->get_id() . '-EXCEPTION')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for violation
|
||||
if ($this->detect_violation($line)) {
|
||||
$this->add_violation(...);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Multi-line or previous-line pattern:**
|
||||
|
||||
```php
|
||||
// Check previous line for exception comment
|
||||
$prev_line_index = $line_number - 1;
|
||||
if ($prev_line_index >= 0 && str_contains($lines[$prev_line_index], '@' . $this->get_id() . '-EXCEPTION')) {
|
||||
continue; // Skip this line
|
||||
}
|
||||
```
|
||||
|
||||
**File-level pattern:**
|
||||
|
||||
```php
|
||||
public function check(string $file_path, string $contents, array $metadata = []): void
|
||||
{
|
||||
// Check if entire file has exception
|
||||
if (str_contains($contents, '@' . $this->get_id() . '-EXCEPTION')) {
|
||||
return; // Skip entire file
|
||||
}
|
||||
|
||||
// ... rest of checking logic
|
||||
}
|
||||
```
|
||||
|
||||
#### Exception Rationale Guidelines
|
||||
|
||||
**Always include a rationale** explaining WHY the exception is needed:
|
||||
|
||||
```javascript
|
||||
// @JS-DEFENSIVE-01-EXCEPTION - Browser API storage.key(i) can return null when i >= storage.length
|
||||
```
|
||||
|
||||
**Good rationales:**
|
||||
- Reference external API behavior: "Browser API returns null", "Laravel method signature requires this"
|
||||
- Explain architectural necessity: "Task system uses direct queries for performance"
|
||||
- Note optional/polymorphic patterns: "Array.find() returns undefined when no match"
|
||||
|
||||
**Bad rationales:**
|
||||
- "TODO: fix later"
|
||||
- "Not sure why this is needed"
|
||||
- No rationale at all
|
||||
|
||||
#### CRITICAL: AI Agent Exception Policy
|
||||
|
||||
**ABSOLUTE PROHIBITION - NEVER GRANT EXCEPTIONS AUTONOMOUSLY**
|
||||
|
||||
When you encounter a code quality violation, you are **FORBIDDEN** from granting exceptions without explicit programmer approval.
|
||||
|
||||
**Required procedure:**
|
||||
1. **STOP** - Do not add exception comments
|
||||
2. **ANALYZE** - Determine if the violation is:
|
||||
- Invalid defensive coding (should be removed)
|
||||
- Valid duck typing (needs exception)
|
||||
- External API constraint (needs exception)
|
||||
3. **REPORT** - Present findings: "Found violation X in file Y. Analysis: [your reasoning]. Options: a) Remove the check (fail-loud), b) Grant exception (provide rationale), c) Refactor differently"
|
||||
4. **WAIT** - Wait for programmer to decide
|
||||
5. **NEVER** add `@RULE-ID-EXCEPTION` comments without explicit approval
|
||||
|
||||
**Only grant exceptions when:**
|
||||
- Programmer explicitly requests it: "grant an exception for this"
|
||||
- Programmer approves your recommendation: "yes, add the exception"
|
||||
- You are implementing a fix that the programmer has already approved
|
||||
|
||||
**Exception grants are permanent code changes** - they suppress violations indefinitely and become part of the codebase. Do not make this decision autonomously.
|
||||
|
||||
## Development
|
||||
|
||||
### Creating New Rules
|
||||
|
||||
@@ -297,7 +297,7 @@ Companion JavaScript ({$js_path}):
|
||||
/**
|
||||
* {$class_name} jqhtml component
|
||||
*/
|
||||
class {$class_name} extends Jqhtml_Component {
|
||||
class {$class_name} extends Component {
|
||||
on_create() {
|
||||
// Initialize component state
|
||||
this.data.count = 0;
|
||||
|
||||
@@ -233,18 +233,18 @@ class HardcodedInternalUrl_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
if ($is_jqhtml) {
|
||||
// JavaScript version for .jqhtml files using <%= %> syntax
|
||||
if (empty($params)) {
|
||||
return "<%= Rsx.Route('{$class_name}', '{$method_name}') %>";
|
||||
return "<%= Rsx.Route('{$class_name}::{$method_name}') %>";
|
||||
} else {
|
||||
$params_json = json_encode($params, JSON_UNESCAPED_SLASHES);
|
||||
return "<%= Rsx.Route('{$class_name}', '{$method_name}', {$params_json}) %>";
|
||||
return "<%= Rsx.Route('{$class_name}::{$method_name}', {$params_json}) %>";
|
||||
}
|
||||
} else {
|
||||
// PHP version for .blade.php files
|
||||
if (empty($params)) {
|
||||
return "{{ Rsx::Route('{$class_name}', '{$method_name}') }}";
|
||||
return "{{ Rsx::Route('{$class_name}::{$method_name}') }}";
|
||||
} else {
|
||||
$params_str = $this->_format_php_array($params);
|
||||
return "{{ Rsx::Route('{$class_name}', '{$method_name}', {$params_str}) }}";
|
||||
return "{{ Rsx::Route('{$class_name}::{$method_name}', {$params_str}) }}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ use App\RSpade\CodeQuality\Rules\CodeQualityRule_Abstract;
|
||||
*
|
||||
* Example violations:
|
||||
* - Rsx::Route('Controller') // PHP
|
||||
* - Rsx.Route('Controller', 'index') // JavaScript
|
||||
* - Rsx.Route('Controller::index') // JavaScript
|
||||
*
|
||||
* Correct usage:
|
||||
* - Rsx::Route('Controller') // PHP
|
||||
|
||||
@@ -86,16 +86,36 @@ class RouteExists_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
*/
|
||||
private function route_exists(string $controller, string $method): bool
|
||||
{
|
||||
// First check if this is a SPA action (JavaScript class extending Spa_Action)
|
||||
if ($this->is_spa_action($controller)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise check PHP routes
|
||||
try {
|
||||
// Use the same validation logic as Rsx::Route()
|
||||
// If this doesn't throw an exception, the route exists
|
||||
\App\RSpade\Core\Rsx::Route($controller, $method);
|
||||
\App\RSpade\Core\Rsx::Route($controller . '::' . $method);
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a controller name is actually a SPA action class
|
||||
*/
|
||||
private function is_spa_action(string $class_name): bool
|
||||
{
|
||||
try {
|
||||
// Use manifest to check if this JavaScript class extends Spa_Action
|
||||
return \App\RSpade\Core\Manifest\Manifest::js_is_subclass_of($class_name, 'Spa_Action');
|
||||
} catch (\Exception $e) {
|
||||
// If manifest not available, class doesn't exist, or any error, return false
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check a file for violations
|
||||
@@ -114,9 +134,9 @@ class RouteExists_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
// Pattern to match Rsx::Route and Rsx.Route calls (NOT plain Route())
|
||||
// Matches both single and double parameter versions:
|
||||
// - Rsx::Route('Controller') // PHP, defaults to 'index'
|
||||
// - Rsx::Route('Controller', 'method') // PHP
|
||||
// - Rsx::Route('Controller::method') // PHP
|
||||
// - Rsx.Route('Controller') // JavaScript, defaults to 'index'
|
||||
// - Rsx.Route('Controller', 'method') // JavaScript
|
||||
// - Rsx.Route('Controller::method') // JavaScript
|
||||
|
||||
// Pattern for two parameters
|
||||
$pattern_two_params = '/(?:Rsx::Route|Rsx\.Route)\s*\(\s*[\'"]([^\'"]+)[\'"]\s*,\s*[\'"]([^\'"]+)[\'"]\s*\)/';
|
||||
@@ -190,11 +210,24 @@ class RouteExists_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
}
|
||||
|
||||
// Extract controller from ORIGINAL content, not sanitized
|
||||
$controller = $original_matches[1][$index][0] ?? $matches[1][$index][0];
|
||||
$method = 'index'; // Default to 'index'
|
||||
$controller_string = $original_matches[1][$index][0] ?? $matches[1][$index][0];
|
||||
|
||||
// Check if using Controller::method syntax
|
||||
if (str_contains($controller_string, '::')) {
|
||||
[$controller, $method] = explode('::', $controller_string, 2);
|
||||
} else {
|
||||
$controller = $controller_string;
|
||||
$method = 'index'; // Default to 'index'
|
||||
}
|
||||
|
||||
// Skip if contains template variables like {$variable}
|
||||
if (str_contains($controller, '{$') || str_contains($controller, '${')) {
|
||||
if (str_contains($controller, '{$') || str_contains($controller, '${') ||
|
||||
str_contains($method, '{$') || str_contains($method, '${')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip if method starts with '#' - indicates unimplemented route
|
||||
if (str_starts_with($method, '#')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -240,10 +273,10 @@ class RouteExists_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
$suggestions[] = " - Create the controller if it doesn't exist";
|
||||
$suggestions[] = " - Add the method with a #[Route] attribute";
|
||||
$suggestions[] = "3. Use '#' prefix for unimplemented routes (recommended):";
|
||||
$suggestions[] = " - Use Rsx::Route('Controller', '#index') for unimplemented index methods";
|
||||
$suggestions[] = " - Use Rsx::Route('Controller', '#method_name') for other unimplemented methods";
|
||||
$suggestions[] = " - Use Rsx::Route('Controller::#index') for unimplemented index methods";
|
||||
$suggestions[] = " - Use Rsx::Route('Controller::#method_name') for other unimplemented methods";
|
||||
$suggestions[] = " - Routes with '#' prefix will generate '#' URLs and bypass this validation";
|
||||
$suggestions[] = " - Example: Rsx::Route('Backend_Users_Controller', '#index')";
|
||||
$suggestions[] = " - Example: Rsx::Route('Backend_Users_Controller::#index')";
|
||||
|
||||
return implode("\n", $suggestions);
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ class SubclassNaming_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
}
|
||||
|
||||
// Also check if the parent of parent is exempt - for deeper inheritance
|
||||
// E.g., if Widget extends Jqhtml_Component, and Dynamic_Widget extends Widget
|
||||
// E.g., if Widget extends Component, and Dynamic_Widget extends Widget
|
||||
// Dynamic_Widget should match Widget's suffix
|
||||
$parent_of_parent = $this->get_parent_class($parent_class_simple);
|
||||
if ($parent_of_parent && !in_array($parent_of_parent, $suffix_exempt_classes)) {
|
||||
|
||||
@@ -53,7 +53,12 @@ class DefensiveCoding_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
|
||||
foreach ($lines as $line_num => $line) {
|
||||
$line_number = $line_num + 1;
|
||||
|
||||
|
||||
// Skip if line has exception comment
|
||||
if (str_contains($line, '@' . $this->get_id() . '-EXCEPTION')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip comments
|
||||
$trimmed_line = trim($line);
|
||||
if (str_starts_with($trimmed_line, '//') || str_starts_with($trimmed_line, '*')) {
|
||||
@@ -174,7 +179,7 @@ class DefensiveCoding_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
" if (result && result.redirect) // OK - result may have optional redirect\n" .
|
||||
" if (error && error.message) // OK - polymorphic error handling\n" .
|
||||
" if (options && options.callback) // OK - optional configuration\n\n" .
|
||||
"NOTE: Core guaranteed classes (Rsx, Modal, Jqhtml_Component, etc.) should NEVER be checked - let failures happen loudly during development.";
|
||||
"NOTE: Core guaranteed classes (Rsx, Modal, Component, etc.) should NEVER be checked - let failures happen loudly during development.";
|
||||
|
||||
$this->add_violation(
|
||||
$file_path,
|
||||
|
||||
@@ -39,7 +39,7 @@ class DirectAjaxApi_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
* Should use:
|
||||
* await Controller.action(params)
|
||||
* Or:
|
||||
* await Ajax.call(Rsx.Route('Controller', 'action'), params)
|
||||
* await Ajax.call(Rsx.Route('Controller::action'), params)
|
||||
*/
|
||||
public function check(string $file_path, string $contents, array $metadata = []): void
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ use App\RSpade\CodeQuality\RuntimeChecks\YoureDoingItWrongException;
|
||||
use App\RSpade\Core\Cache\RsxCache;
|
||||
|
||||
/**
|
||||
* Check Jqhtml_Component implementations for common AI agent mistakes
|
||||
* Check Component implementations for common AI agent mistakes
|
||||
* Validates that components follow correct patterns
|
||||
*/
|
||||
class JqhtmlComponentImplementation_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
@@ -24,7 +24,7 @@ class JqhtmlComponentImplementation_CodeQualityRule extends CodeQualityRule_Abst
|
||||
|
||||
public function get_description(): string
|
||||
{
|
||||
return 'Validates Jqhtml_Component subclasses follow correct patterns';
|
||||
return 'Validates Component subclasses follow correct patterns';
|
||||
}
|
||||
|
||||
public function get_file_patterns(): array
|
||||
@@ -47,8 +47,8 @@ class JqhtmlComponentImplementation_CodeQualityRule extends CodeQualityRule_Abst
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip if not a Jqhtml_Component subclass
|
||||
if (!isset($metadata['extends']) || $metadata['extends'] !== 'Jqhtml_Component') {
|
||||
// Skip if not a Component subclass
|
||||
if (!isset($metadata['extends']) || $metadata['extends'] !== 'Component') {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -91,10 +91,10 @@ class JqhtmlComponentImplementation_CodeQualityRule extends CodeQualityRule_Abst
|
||||
$error_message .= "Class: {$class_name}\n\n";
|
||||
$error_message .= "Jqhtml components should not define a render() method.\n\n";
|
||||
$error_message .= "PROBLEM:\n";
|
||||
$error_message .= "The render() method is not part of the Jqhtml_Component lifecycle.\n";
|
||||
$error_message .= "The render() method is not part of the Component lifecycle.\n";
|
||||
$error_message .= "Jqhtml components use template files (.jqhtml) for rendering.\n\n";
|
||||
$error_message .= "INCORRECT:\n";
|
||||
$error_message .= " class My_Component extends Jqhtml_Component {\n";
|
||||
$error_message .= " class My_Component extends Component {\n";
|
||||
$error_message .= " render() {\n";
|
||||
$error_message .= " return '<div>...</div>';\n";
|
||||
$error_message .= " }\n";
|
||||
@@ -105,7 +105,7 @@ class JqhtmlComponentImplementation_CodeQualityRule extends CodeQualityRule_Abst
|
||||
$error_message .= " <%= content() %>\n";
|
||||
$error_message .= " </div>\n\n";
|
||||
$error_message .= " // JavaScript class handles logic:\n";
|
||||
$error_message .= " class My_Component extends Jqhtml_Component {\n";
|
||||
$error_message .= " class My_Component extends Component {\n";
|
||||
$error_message .= " on_ready() {\n";
|
||||
$error_message .= " // Component logic here\n";
|
||||
$error_message .= " }\n";
|
||||
@@ -136,13 +136,13 @@ class JqhtmlComponentImplementation_CodeQualityRule extends CodeQualityRule_Abst
|
||||
$error_message .= "The method '{$method_name}()' should be 'on_{$method_name}()'.\n";
|
||||
$error_message .= "Jqhtml components use specific lifecycle method names.\n\n";
|
||||
$error_message .= "INCORRECT:\n";
|
||||
$error_message .= " class My_Component extends Jqhtml_Component {\n";
|
||||
$error_message .= " class My_Component extends Component {\n";
|
||||
$error_message .= " create() { ... } // Wrong\n";
|
||||
$error_message .= " load() { ... } // Wrong\n";
|
||||
$error_message .= " ready() { ... } // Wrong\n";
|
||||
$error_message .= " }\n\n";
|
||||
$error_message .= "CORRECT:\n";
|
||||
$error_message .= " class My_Component extends Jqhtml_Component {\n";
|
||||
$error_message .= " class My_Component extends Component {\n";
|
||||
$error_message .= " on_create() { ... } // Correct\n";
|
||||
$error_message .= " on_load() { ... } // Correct\n";
|
||||
$error_message .= " on_ready() { ... } // Correct\n";
|
||||
|
||||
@@ -158,7 +158,7 @@ const walk = require('acorn-walk');
|
||||
|
||||
// Classes that are Jqhtml components
|
||||
const JQHTML_COMPONENTS = new Set([
|
||||
'Jqhtml_Component', '_Base_Jqhtml_Component', 'Component'
|
||||
'Component', '_Base_Jqhtml_Component', 'Component'
|
||||
]);
|
||||
|
||||
function analyzeFile(filePath) {
|
||||
@@ -182,7 +182,7 @@ function analyzeFile(filePath) {
|
||||
let currentClass = null;
|
||||
let inOnCreate = false;
|
||||
|
||||
// Helper to check if a class extends Jqhtml_Component
|
||||
// Helper to check if a class extends Component
|
||||
function isJqhtmlComponent(extendsClass) {
|
||||
if (!extendsClass) return false;
|
||||
return JQHTML_COMPONENTS.has(extendsClass) ||
|
||||
|
||||
@@ -66,7 +66,7 @@ class JqhtmlOnLoadData_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
// Check each class to see if it's a JQHTML component
|
||||
foreach ($js_classes as $class_name) {
|
||||
// Use Manifest to check inheritance (handles indirect inheritance)
|
||||
if (!Manifest::js_is_subclass_of($class_name, 'Jqhtml_Component') &&
|
||||
if (!Manifest::js_is_subclass_of($class_name, 'Component') &&
|
||||
!Manifest::js_is_subclass_of($class_name, 'Component')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ class JqhtmlOnLoadDom_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for DOM access in on_load methods of Jqhtml_Component subclasses
|
||||
* Check for DOM access in on_load methods of Component subclasses
|
||||
*/
|
||||
public function check(string $file_path, string $contents, array $metadata = []): void
|
||||
{
|
||||
@@ -66,7 +66,7 @@ class JqhtmlOnLoadDom_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
// Check each class to see if it's a JQHTML component
|
||||
foreach ($js_classes as $class_name) {
|
||||
// Use Manifest to check inheritance (handles indirect inheritance)
|
||||
if (!Manifest::js_is_subclass_of($class_name, 'Jqhtml_Component') &&
|
||||
if (!Manifest::js_is_subclass_of($class_name, 'Component') &&
|
||||
!Manifest::js_is_subclass_of($class_name, 'Component')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ class JqhtmlRenderOverride_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for render() method override in Jqhtml_Component subclasses
|
||||
* Check for render() method override in Component subclasses
|
||||
*/
|
||||
public function check(string $file_path, string $contents, array $metadata = []): void
|
||||
{
|
||||
@@ -66,7 +66,7 @@ class JqhtmlRenderOverride_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
// Check each class to see if it's a JQHTML component
|
||||
foreach ($js_classes as $class_name) {
|
||||
// Use Manifest to check inheritance (handles indirect inheritance)
|
||||
if (!Manifest::js_is_subclass_of($class_name, 'Jqhtml_Component') &&
|
||||
if (!Manifest::js_is_subclass_of($class_name, 'Component') &&
|
||||
!Manifest::js_is_subclass_of($class_name, 'Component')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -91,8 +91,8 @@ class LifecycleMethodsStatic_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
// Get class name
|
||||
$class_name = $metadata['class'];
|
||||
|
||||
// Only check classes that extend Jqhtml_Component
|
||||
if (!\App\RSpade\Core\Manifest\Manifest::js_is_subclass_of($class_name, 'Jqhtml_Component')) {
|
||||
// Only check classes that extend Component
|
||||
if (!\App\RSpade\Core\Manifest\Manifest::js_is_subclass_of($class_name, 'Component')) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ class JqhtmlComponentNaming_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
$this->check_jqhtml_file($file_path, $contents);
|
||||
}
|
||||
|
||||
// Check .js files for classes extending Jqhtml_Component
|
||||
// Check .js files for classes extending Component
|
||||
if (str_ends_with($file_path, '.js')) {
|
||||
$this->check_javascript_file($file_path, $contents, $metadata);
|
||||
}
|
||||
@@ -101,7 +101,7 @@ class JqhtmlComponentNaming_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
}
|
||||
|
||||
/**
|
||||
* Check JavaScript files for Jqhtml_Component subclasses
|
||||
* Check JavaScript files for Component subclasses
|
||||
*/
|
||||
private function check_javascript_file(string $file_path, string $contents, array $metadata = []): void
|
||||
{
|
||||
@@ -131,7 +131,7 @@ class JqhtmlComponentNaming_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
// Check each class to see if it's a JQHTML component
|
||||
foreach ($class_definitions as $class_name => $line_num) {
|
||||
// Use Manifest to check if this is a JQHTML component (handles indirect inheritance)
|
||||
if (Manifest::js_is_subclass_of($class_name, 'Jqhtml_Component')) {
|
||||
if (Manifest::js_is_subclass_of($class_name, 'Component')) {
|
||||
// Check if first character is not uppercase
|
||||
if (!ctype_upper($class_name[0])) {
|
||||
$this->add_violation(
|
||||
|
||||
@@ -67,10 +67,10 @@ class JqhtmlEventPreventDefault_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the first class that extends Jqhtml_Component
|
||||
// Find the first class that extends Component
|
||||
$class_name = null;
|
||||
foreach ($js_classes as $js_class) {
|
||||
if (Manifest::js_is_subclass_of($js_class, 'Jqhtml_Component')) {
|
||||
if (Manifest::js_is_subclass_of($js_class, 'Component')) {
|
||||
$class_name = $js_class;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ class JqhtmlInlineScript_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
REQUIRED STEPS:
|
||||
1. Create a JavaScript file: {$js_path}
|
||||
2. Name the ES6 class exactly: {$class_name}
|
||||
3. Extend Jqhtml_Component base class
|
||||
3. Extend Component base class
|
||||
4. Implement lifecycle methods: on_create(), on_load(), on_ready()
|
||||
|
||||
EXAMPLE IMPLEMENTATION for {$js_filename}:
|
||||
@@ -179,7 +179,7 @@ EXAMPLE IMPLEMENTATION for {$js_filename}:
|
||||
/**
|
||||
* Component class for {$class_name}
|
||||
*/
|
||||
class {$class_name} extends Jqhtml_Component {
|
||||
class {$class_name} extends Component {
|
||||
/**
|
||||
* Called when component instance is created
|
||||
* Use for initial setup and event binding
|
||||
@@ -229,7 +229,7 @@ class {$class_name} extends Jqhtml_Component {
|
||||
|
||||
KEY CONVENTIONS:
|
||||
- Class name MUST match the <Define:{$class_name}> in the .jqhtml file
|
||||
- MUST extend Jqhtml_Component base class
|
||||
- MUST extend Component base class
|
||||
- Use lifecycle methods: on_create(), on_load(), on_ready()
|
||||
- Access component element via this.\$
|
||||
- Bind events using \$onclick, \$onchange, etc. in template
|
||||
|
||||
@@ -92,11 +92,11 @@ class FilenameClassMatch_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
{
|
||||
$filename_without_ext = pathinfo($filename, PATHINFO_FILENAME);
|
||||
|
||||
// Check if this is a JavaScript class extending Jqhtml_Component
|
||||
// Check if this is a JavaScript class extending Component
|
||||
$is_jqhtml_component = false;
|
||||
if ($extension === 'js') {
|
||||
try {
|
||||
$is_jqhtml_component = \App\RSpade\Core\Manifest\Manifest::js_is_subclass_of($class_name, 'Jqhtml_Component');
|
||||
$is_jqhtml_component = \App\RSpade\Core\Manifest\Manifest::js_is_subclass_of($class_name, 'Component');
|
||||
} catch (\Exception $e) {
|
||||
// Class not in manifest or not a JS class, treat as regular class
|
||||
$is_jqhtml_component = false;
|
||||
|
||||
@@ -12,10 +12,10 @@ use App\RSpade\CodeQuality\Rules\CodeQualityRule_Abstract;
|
||||
* to check if a class extends another, since regex can't detect indirect inheritance.
|
||||
*
|
||||
* Example of incorrect pattern:
|
||||
* preg_match('/class\s+\w+\s+extends\s+Jqhtml_Component/', $contents)
|
||||
* preg_match('/class\s+\w+\s+extends\s+Component/', $contents)
|
||||
*
|
||||
* Should be:
|
||||
* Manifest::php_is_subclass_of($class_name, 'Jqhtml_Component')
|
||||
* Manifest::php_is_subclass_of($class_name, 'Component')
|
||||
*/
|
||||
class Code_Quality_Meta_Inheritance_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
{
|
||||
@@ -92,7 +92,7 @@ class Code_Quality_Meta_Inheritance_CodeQualityRule extends CodeQualityRule_Abst
|
||||
"If checking JavaScript classes: Use Manifest::js_is_subclass_of(\$class_name, 'BaseClass')\n" .
|
||||
"Examples:\n" .
|
||||
" PHP: if (Manifest::php_is_subclass_of(\$metadata['class'], 'Rsx_Model_Abstract')) { ... }\n" .
|
||||
" JS: if (Manifest::js_is_subclass_of(\$class_name, 'Jqhtml_Component')) { ... }",
|
||||
" JS: if (Manifest::js_is_subclass_of(\$class_name, 'Component')) { ... }",
|
||||
'high'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -87,11 +87,17 @@ class DbTableUsage_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
if ($table_name === 'migrations') {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Skip Laravel's sessions table - managed by framework
|
||||
if ($table_name === 'sessions') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip framework internal tables (prefixed with underscore)
|
||||
// These are low-level system tables managed directly for performance
|
||||
if (str_starts_with($table_name, '_')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Use original line for display in error message
|
||||
$original_line = $original_lines[$line_num] ?? $sanitized_line;
|
||||
|
||||
@@ -276,10 +276,10 @@ class HardcodedUrlInRedirect_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
protected function _generate_rsx_suggestion(string $class_name, string $method_name, array $params): string
|
||||
{
|
||||
if (empty($params)) {
|
||||
return "return redirect(Rsx::Route('{$class_name}', '{$method_name}'));";
|
||||
return "return redirect(Rsx::Route('{$class_name}::{$method_name}'));";
|
||||
} else {
|
||||
$params_str = $this->_format_php_array($params);
|
||||
return "return redirect(Rsx::Route('{$class_name}', '{$method_name}', {$params_str}));";
|
||||
return "return redirect(Rsx::Route('{$class_name}::{$method_name}', {$params_str}));";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -141,9 +141,9 @@ class RouteQueryConcatenation_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
$line,
|
||||
"Query parameters should be passed as the third argument to Rsx::Route() as an array.\n\n" .
|
||||
"WRONG:\n" .
|
||||
" Rsx::Route('Controller', 'method') . '?param=value&other=test'\n\n" .
|
||||
" Rsx::Route('Controller::method') . '?param=value&other=test'\n\n" .
|
||||
"CORRECT:\n" .
|
||||
" Rsx::Route('Controller', 'method', ['param' => 'value', 'other' => 'test'])\n\n" .
|
||||
" Rsx::Route('Controller::method', ['param' => 'value', 'other' => 'test'])\n\n" .
|
||||
"The framework will automatically URL-encode the parameters and construct the query string properly."
|
||||
);
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ class ManifestErrors
|
||||
$error_message .= "❌ BAD: class MyComponent extends window.BaseComponent {}\n";
|
||||
$error_message .= "✅ GOOD: class MyComponent extends BaseComponent {}\n\n";
|
||||
$error_message .= "❌ BAD: class Widget extends jqhtml.Component {}\n";
|
||||
$error_message .= "✅ GOOD: class Widget extends Jqhtml_Component {}\n\n";
|
||||
$error_message .= "✅ GOOD: class Widget extends Component {}\n\n";
|
||||
$error_message .= "This restriction maintains consistency and enables proper class hierarchy tracking.\n";
|
||||
$error_message .= "==========================================";
|
||||
|
||||
@@ -106,7 +106,7 @@ class ManifestErrors
|
||||
int $line_num,
|
||||
string $class_name
|
||||
): void {
|
||||
$error_message = "Fatal: Incorrect Jqhtml_Component implementation detected.\n\n";
|
||||
$error_message = "Fatal: Incorrect Component implementation detected.\n\n";
|
||||
$error_message .= "File: {$file}\n";
|
||||
$error_message .= "Line {$line_num}: Found render() method\n\n";
|
||||
$error_message .= "PROBLEM: The render() method should not exist in JavaScript component classes.\n\n";
|
||||
@@ -137,10 +137,10 @@ class ManifestErrors
|
||||
int $line_num,
|
||||
string $method
|
||||
): void {
|
||||
$error_message = "Fatal: Incorrect Jqhtml_Component lifecycle method detected.\n\n";
|
||||
$error_message = "Fatal: Incorrect Component lifecycle method detected.\n\n";
|
||||
$error_message .= "File: {$file}\n";
|
||||
$error_message .= "Line {$line_num}: Found '{$method}()' method\n\n";
|
||||
$error_message .= "PROBLEM: Jqhtml_Component lifecycle methods must be prefixed with 'on_'\n\n";
|
||||
$error_message .= "PROBLEM: Component lifecycle methods must be prefixed with 'on_'\n\n";
|
||||
$error_message .= "SOLUTION: Rename the method:\n";
|
||||
$error_message .= "- '{$method}()' should be 'on_{$method}()'\n\n";
|
||||
$error_message .= "CORRECT LIFECYCLE METHODS:\n";
|
||||
|
||||
Reference in New Issue
Block a user