$line) { $actual_line_number = $line_number + 1; // Use sanitized line to check if this is a comment $sanitized_line = $sanitized_lines[$line_number] ?? ''; $trimmed = trim($sanitized_line); // Skip comments (check sanitized version which preserves comment markers) if (str_starts_with($trimmed, '//') || str_starts_with($trimmed, '*')) { continue; } // Check for exception comment on this line or previous line (use original) if (str_contains($line, '@' . $this->get_id() . '-EXCEPTION')) { continue; } if ($line_number > 0 && str_contains($original_lines[$line_number - 1], '@' . $this->get_id() . '-EXCEPTION')) { continue; } // Match patterns like: this.$.trigger( or that.$.trigger( // Also match: this.$sid('x').trigger( or that.$sid('x').trigger( if (preg_match('/(this|that)\.\$(?:sid\s*\([^)]+\))?\s*\.\s*trigger\s*\(\s*[\'"]([^\'"]+)[\'"]/', $line, $matches)) { $event_name = $matches[2]; // Check if it's an allowed standard event if (in_array(strtolower($event_name), self::ALLOWED_EVENTS, true)) { continue; } $this->add_violation( $file_path, $actual_line_number, "Custom event '{$event_name}' triggered via jQuery .trigger() in Component class '{$class_name}'. " . 'Use the jqhtml event bus instead.', trim($line), "Use jqhtml event system for custom events:\n\n" . "FIRING EVENTS:\n" . " Instead of: this.\$.trigger('{$event_name}', data)\n" . " Use: this.trigger('{$event_name}', data)\n\n" . "LISTENING FROM PARENT (using \$sid):\n" . " Instead of: this.\$sid('child').on('{$event_name}', handler)\n" . " Use: this.sid('child').on('{$event_name}', handler)\n\n" . "LISTENING FROM EXTERNAL CODE:\n" . " Instead of: \$(element).on('{$event_name}', handler)\n" . " Use: \$(element).component().on('{$event_name}', handler)\n\n" . "WHY: The jqhtml event bus fires callbacks for events that occurred before the handler " . "was registered. This is critical for component lifecycle - parent components may " . "register handlers after child components have already fired their events during initialization.", 'high' ); } } } } }