Fix bin/publish: use correct .env path for rspade_system Fix bin/publish script: prevent grep exit code 1 from terminating script 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
191 lines
5.8 KiB
PHP
Executable File
191 lines
5.8 KiB
PHP
Executable File
<?php
|
|
|
|
namespace App\RSpade\CodeQuality\Rules;
|
|
|
|
use App\RSpade\CodeQuality\CodeQuality_Violation;
|
|
use App\RSpade\CodeQuality\Support\ViolationCollector;
|
|
|
|
#[Instantiatable]
|
|
abstract class CodeQualityRule_Abstract
|
|
{
|
|
protected ViolationCollector $collector;
|
|
protected array $config = [];
|
|
protected bool $enabled = true;
|
|
|
|
public function __construct(ViolationCollector $collector, array $config = [])
|
|
{
|
|
$this->collector = $collector;
|
|
$this->config = $config;
|
|
$this->enabled = $config['enabled'] ?? true;
|
|
}
|
|
|
|
/**
|
|
* Get the unique rule identifier (e.g., 'PHP-SC-001')
|
|
*/
|
|
abstract public function get_id(): string;
|
|
|
|
/**
|
|
* Get human-readable rule name
|
|
*/
|
|
abstract public function get_name(): string;
|
|
|
|
/**
|
|
* Get rule description
|
|
*/
|
|
abstract public function get_description(): string;
|
|
|
|
/**
|
|
* Get file patterns this rule applies to (e.g., ['*.php', '*.js'])
|
|
*/
|
|
abstract public function get_file_patterns(): array;
|
|
|
|
/**
|
|
* Check a file for violations
|
|
*
|
|
* @param string $file_path Absolute path to file
|
|
* @param string $contents File contents (may be sanitized)
|
|
* @param array $metadata Additional metadata from manifest
|
|
*/
|
|
abstract public function check(string $file_path, string $contents, array $metadata = []): void;
|
|
|
|
/**
|
|
* Whether this rule supports checking Console Commands
|
|
*
|
|
* Rules that return true here will be given Console Command files to check
|
|
* when using default paths or when a specific Console Command file is provided.
|
|
* Rules supporting Console Commands MUST NOT rely on manifest metadata as
|
|
* Console Commands are not indexed in the manifest.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function supports_console_commands(): bool
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if this rule is enabled
|
|
*/
|
|
public function is_enabled(): bool
|
|
{
|
|
return $this->enabled;
|
|
}
|
|
|
|
/**
|
|
* Check if this rule should be called during manifest scan
|
|
*
|
|
* IMPORTANT: This method should ALWAYS return false unless explicitly requested
|
|
* by the framework developer. Manifest-time checks are reserved for critical
|
|
* framework convention violations that need immediate developer attention.
|
|
*
|
|
* Rules executed during manifest scan will run on every file change in development,
|
|
* potentially impacting performance. Only enable this for rules that:
|
|
* - Enforce critical framework conventions that would break the application
|
|
* - Need to provide immediate feedback before code execution
|
|
* - Have been specifically requested to run at manifest-time by framework maintainers
|
|
*
|
|
* DEFAULT: Always return false unless you have explicit permission to do otherwise.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function is_called_during_manifest_scan(): bool
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get default severity for this rule
|
|
*/
|
|
public function get_default_severity(): string
|
|
{
|
|
return 'medium';
|
|
}
|
|
|
|
/**
|
|
* Add a violation
|
|
*/
|
|
protected function add_violation(
|
|
string $file_path,
|
|
int $line_number,
|
|
string $message,
|
|
?string $code_snippet = null,
|
|
?string $suggestion = null,
|
|
?string $severity = null
|
|
): void {
|
|
$violation = new CodeQuality_Violation(
|
|
rule_id: $this->get_id(),
|
|
file_path: $file_path,
|
|
line_number: $line_number,
|
|
message: $message,
|
|
severity: $severity ?? $this->get_default_severity(),
|
|
code_snippet: $code_snippet,
|
|
suggestion: $suggestion
|
|
);
|
|
|
|
$this->collector->add($violation);
|
|
}
|
|
|
|
/**
|
|
* Extract code snippet around a line
|
|
*/
|
|
protected function get_code_snippet(array $lines, int $line_index, int $context = 2): string
|
|
{
|
|
$start = max(0, $line_index - $context);
|
|
$end = min(count($lines) - 1, $line_index + $context);
|
|
|
|
$snippet = [];
|
|
for ($i = $start; $i <= $end; $i++) {
|
|
$prefix = $i === $line_index ? '>>> ' : ' ';
|
|
$snippet[] = $prefix . ($i + 1) . ': ' . $lines[$i];
|
|
}
|
|
|
|
return implode("\n", $snippet);
|
|
}
|
|
|
|
/**
|
|
* Get all PHP files in the Console Commands directory
|
|
*
|
|
* This helper allows rules to optionally include Console Commands in their checks
|
|
* without requiring these files to be in the manifest. Rules using this helper
|
|
* MUST NOT rely on manifest metadata since Console Commands are not indexed.
|
|
*
|
|
* @return array Array of absolute file paths to PHP files in app/Console/Commands
|
|
*/
|
|
protected static function get_console_command_files(): array
|
|
{
|
|
$commands_dir = base_path('app/Console/Commands');
|
|
|
|
if (!is_dir($commands_dir)) {
|
|
return [];
|
|
}
|
|
|
|
$files = [];
|
|
$iterator = new \RecursiveIteratorIterator(
|
|
new \RecursiveDirectoryIterator($commands_dir, \RecursiveDirectoryIterator::SKIP_DOTS),
|
|
\RecursiveIteratorIterator::SELF_FIRST
|
|
);
|
|
|
|
foreach ($iterator as $file) {
|
|
if ($file->isFile() && $file->getExtension() === 'php') {
|
|
$files[] = $file->getPathname();
|
|
}
|
|
}
|
|
|
|
return $files;
|
|
}
|
|
|
|
/**
|
|
* Check if a file is a Console Command
|
|
*
|
|
* @param string $file_path The file path to check
|
|
* @return bool True if the file is in app/Console/Commands
|
|
*/
|
|
protected static function is_console_command(string $file_path): bool
|
|
{
|
|
$commands_dir = base_path('app/Console/Commands');
|
|
$normalized_path = str_replace('\\', '/', $file_path);
|
|
$normalized_commands_dir = str_replace('\\', '/', $commands_dir);
|
|
|
|
return str_starts_with($normalized_path, $normalized_commands_dir);
|
|
}
|
|
} |