$line) { $actual_line_number = $line_num + 1; $trimmed = trim($line); // Skip comments if (str_starts_with($trimmed, '//') || str_starts_with($trimmed, '/*')) { continue; } // Check for exception comment on same line or previous line if (str_contains($line, '@' . $this->get_id() . '-EXCEPTION')) { continue; } if ($line_num > 0 && str_contains($lines[$line_num - 1], '@' . $this->get_id() . '-EXCEPTION')) { continue; } // Look for [data-sid= pattern (with or without quotes) if (preg_match('/\[data-sid\s*[=~\|\^\$\*]/', $line, $matches)) { // Extract the selector context for better error message $code_snippet = trim($line); if (strlen($code_snippet) > 80) { $code_snippet = substr($code_snippet, 0, 77) . '...'; } // Try to extract the sid name for the suggestion $sid_name = ''; if (preg_match('/\[data-sid\s*=\s*["\']?([^"\'\]]+)/', $line, $sid_match)) { $sid_name = $sid_match[1]; } $suggestion = $this->get_suggestion($sid_name); $this->add_violation( $file_path, $actual_line_number, "Targeting [data-sid] in CSS is PROHIBITED", $code_snippet, $suggestion, 'critical' ); } } } /** * Generate the fix suggestion with example */ private function get_suggestion(string $sid_name): string { $example_class = $sid_name ? "__$sid_name" : '__element_name'; return << BEM child classes are semantic, documented, and part of the component's public API. \$sid attributes are internal implementation that should never leak into CSS. SUGGESTION; } }