to_snake_case($class_name) . '.jqhtml', // Check without _component suffix if present $dir . '/' . str_replace('_component', '', $this->to_snake_case($class_name)) . '.jqhtml', ]; $template_content = null; $template_path = null; foreach ($possible_templates as $template_file) { if (file_exists($template_file)) { $template_content = file_get_contents($template_file); $template_path = $template_file; break; } } if (!$template_content) { // No template found, can't verify usage return; } // Find all methods that use event.preventDefault() $lines = explode("\n", $contents); $in_method = false; $method_name = null; $method_start_line = 0; $method_param = null; $brace_count = 0; foreach ($lines as $line_num => $line) { $line_number = $line_num + 1; // Check for method definition with single parameter if (preg_match('/^\s*(\w+)\s*\(\s*(\w+)\s*\)\s*{/', $line, $method_match)) { $in_method = true; $method_name = $method_match[1]; $method_param = $method_match[2]; $method_start_line = $line_number; $brace_count = 1; } elseif ($in_method) { // Count braces to track method boundaries $brace_count += substr_count($line, '{'); $brace_count -= substr_count($line, '}'); if ($brace_count <= 0) { $in_method = false; $method_name = null; $method_param = null; continue; } // Check if this line calls preventDefault on the parameter if ($method_param && preg_match('/\b' . preg_quote($method_param, '/') . '\s*\.\s*preventDefault\s*\(/', $line)) { // Found preventDefault usage, now check if this method is used in template if ($this->method_used_in_template($template_content, $method_name)) { $this->add_violation( $file_path, $line_number, "JQHTML event handlers should not use event.preventDefault() - Method '{$method_name}()' is called from JQHTML template but tries to use event.preventDefault(). " . "JQHTML automatically handles preventDefault and doesn't pass event objects.", trim($line), "Remove '{$method_param}' parameter and '{$method_param}.preventDefault()' call", 'high' ); } } } } } /** * Check if a method is referenced in JQHTML template event attributes */ private function method_used_in_template(string $template_content, string $method_name): bool { // Look for @event=this.method_name or @event=method_name patterns // Common events: @click, @change, @submit, @keyup, @keydown, @focus, @blur $pattern = '/@\w+\s*=\s*(?:this\.)?' . preg_quote($method_name, '/') . '\b/'; return preg_match($pattern, $template_content) > 0; } /** * Convert CamelCase/PascalCase to snake_case */ private function to_snake_case(string $str): string { $str = preg_replace('/([a-z])([A-Z])/', '$1_$2', $str); return strtolower($str); } }