use serde_json::Value;
use crate::analysis::findings::{Finding, Severity};
use crate::languages::runner::ToolOutputError;
use crate::languages::spec::ToolSpec;
use super::{expect_keyed_object, json_payload};
pub(super) fn parse_phpcs(spec: &ToolSpec, output: &str) -> Result<Vec<Finding>, ToolOutputError> {
let Some(payload) = json_payload(spec, output)? else {
return Ok(Vec::new());
};
let files = expect_keyed_object(spec, &payload, "files")?;
let mut findings = Vec::new();
for (path, file) in files {
for message in file
.get("messages")
.and_then(Value::as_array)
.into_iter()
.flatten()
{
findings.push(Finding::deterministic(
message
.get("source")
.and_then(Value::as_str)
.map(str::to_owned)
.unwrap_or_else(|| spec.name.to_owned()),
phpcs_severity(message.get("type").and_then(Value::as_str)),
path.clone(),
message
.get("line")
.and_then(Value::as_u64)
.map(|n| n as u32)
.unwrap_or(1),
message
.get("column")
.and_then(Value::as_u64)
.map(|n| n as u32),
message
.get("message")
.and_then(Value::as_str)
.unwrap_or("")
.to_owned(),
None,
));
}
}
Ok(findings)
}
fn phpcs_severity(kind: Option<&str>) -> Severity {
match kind {
Some(value) if value.eq_ignore_ascii_case("error") => Severity::Error,
_ => Severity::Warning,
}
}