$line) { $line_number = $line_num + 1; // Skip comments $trimmed_line = trim($line); if (str_starts_with($trimmed_line, '//') || str_starts_with($trimmed_line, '*')) { continue; } // Pattern 1: typeof variable checks (!== undefined, === undefined, == 'function', etc.) // Match: typeof SomeVar !== 'undefined' or typeof SomeVar == 'function' if (preg_match('/typeof\s+(\w+)\s*([!=]=+)\s*[\'"]?(undefined|function)[\'"]?/i', $line, $matches)) { $variable = $matches[1]; // Skip if it's a property check (contains dot) if (!str_contains($variable, '.')) { $this->add_violation( $file_path, $line_number, "Defensive coding violation: Checking if '{$variable}' exists. All classes and variables must be assumed to exist. Code should fail loudly if something is undefined.", trim($line), "Remove the existence check. Let the code fail if '{$variable}' is not defined.", 'high' ); } } // Pattern 2: typeof window.variable checks if (preg_match('/typeof\s+window\.(\w+)\s*([!=]=+)\s*[\'"]?undefined[\'"]?/i', $line, $matches)) { $variable = 'window.' . $matches[1]; $this->add_violation( $file_path, $line_number, "Defensive coding violation: Checking if '{$variable}' exists. All global variables must be assumed to exist. Code should fail loudly if something is undefined.", trim($line), "Remove the existence check. Let the code fail if '{$variable}' is not defined.", 'high' ); } // Pattern 3: if (variable) or if (!variable) existence checks (more careful pattern) // Only match simple variables, not property access if (preg_match('/if\s*\(\s*(!)?(\w+)\s*\)/', $line, $matches)) { $variable = $matches[2]; // Skip if it's a property or array access or a boolean-like variable name if (!str_contains($line, '.' . $variable) && !str_contains($line, '[' . $variable) && !str_contains($line, $variable . '.') && !str_contains($line, $variable . '[') && !preg_match('/^(is|has|can|should|will|did|was)[A-Z]/', $variable) && // Skip boolean-named vars !in_array(strtolower($variable), ['true', 'false', 'null', 'undefined'])) { // Skip literals // Check if this looks like an existence check by looking at context if (preg_match('/if\s*\(\s*(!)?typeof\s+' . preg_quote($variable, '/') . '/i', $line) || preg_match('/if\s*\(\s*' . preg_quote($variable, '/') . '\s*&&\s*' . preg_quote($variable, '/') . '\./i', $line)) { $this->add_violation( $file_path, $line_number, "Defensive coding violation: Checking if '{$variable}' exists. All classes and variables must be assumed to exist. Code should fail loudly if something is undefined.", trim($line), "Remove the existence check. Let the code fail if '{$variable}' is not defined.", 'high' ); } } } // Pattern 4: Guard clauses like: Rsx && Rsx.method() if (preg_match('/(\w+)\s*&&\s*\1\.\w+/i', $line, $matches)) { $variable = $matches[1]; // Skip common boolean variable patterns if (!preg_match('/^(is|has|can|should|will|did|was)[A-Z]/', $variable)) { $this->add_violation( $file_path, $line_number, "Defensive coding violation: Guard clause checking if '{$variable}' exists. All classes and variables must be assumed to exist. Code should fail loudly if something is undefined.", trim($line), "Remove the guard clause. Use '{$variable}.method()' directly.", 'high' ); } } // Pattern 5: try/catch used for existence checking (simplified detection) if (preg_match('/try\s*\{.*?(\w+).*?\}\s*catch/i', $line, $matches)) { // This is a simplified check - in reality you'd need multi-line parsing // Skip for now as it's complex to detect intent } } } }