use serde::Serialize;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(rename_all = "kebab-case")]
pub enum FocusLabel {
ReviewHere,
NotPrioritized,
Skip,
}
impl FocusLabel {
#[must_use]
pub const fn token(self) -> &'static str {
match self {
Self::ReviewHere => "review-here",
Self::NotPrioritized => "not-prioritized",
Self::Skip => "skip",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(rename_all = "kebab-case")]
pub enum ConfidenceFlag {
DynamicDispatch,
ReExportIndirection,
}
impl ConfidenceFlag {
#[must_use]
pub const fn message(self) -> &'static str {
match self {
Self::DynamicDispatch => "low: dynamic dispatch detected",
Self::ReExportIndirection => "low: re-export indirection",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub struct FocusScore {
pub fan_io: u32,
pub security_taint: u32,
pub risk_zone: u32,
pub change_shape: u32,
#[serde(default, skip_serializing_if = "is_zero")]
#[cfg_attr(feature = "schema", schemars(default))]
pub runtime: u32,
pub total: u32,
}
#[expect(
clippy::trivially_copy_pass_by_ref,
reason = "serde skip predicate signature"
)]
fn is_zero(value: &u32) -> bool {
*value == 0
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub struct FocusUnit {
pub file: String,
pub score: FocusScore,
pub label: FocusLabel,
pub reason: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub confidence: Vec<ConfidenceFlag>,
}
#[derive(Debug, Clone, Default, Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub struct FocusMap {
pub review_here: Vec<FocusUnit>,
pub deprioritized: Vec<FocusUnit>,
}
impl FocusMap {
#[must_use]
pub fn total_units(&self) -> usize {
self.review_here.len() + self.deprioritized.len()
}
}