///|
/// Immutable query parameters for filtering a DoctorReport.
pub(all) struct DiagnosticQuery {
severity : Severity?
category : RuleCategory?
path_prefix : String?
include_unlocated : Bool
} derive(Debug, Eq)
///|
pub fn DiagnosticQuery::all() -> DiagnosticQuery {
{ severity: None, category: None, path_prefix: None, include_unlocated: true }
}
///|
pub fn DiagnosticQuery::matches(
self : DiagnosticQuery,
diagnostic : Diagnostic,
) -> Bool {
let severity_matches = match self.severity {
Some(expected) => diagnostic.severity == expected
None => true
}
let category_matches = match self.category {
Some(expected) =>
match find_rule_definition(diagnostic.code) {
Some(rule) => rule.category == expected
None => false
}
None => true
}
let location_matches = match self.path_prefix {
Some(prefix) =>
match diagnostic.location {
Some(location) => location.path.has_prefix(prefix)
None => self.include_unlocated
}
None => self.include_unlocated || diagnostic.location is Some(_)
}
severity_matches && category_matches && location_matches
}
///|
pub fn DiagnosticQuery::filter(
self : DiagnosticQuery,
report : DoctorReport,
) -> Array[Diagnostic] {
let matches : Array[Diagnostic] = []
for diagnostic in report.diagnostics {
if self.matches(diagnostic) {
matches.push(diagnostic)
}
}
matches
}
///|
pub fn DiagnosticQuery::count(
self : DiagnosticQuery,
report : DoctorReport,
) -> Int {
self.filter(report).length()
}
///|
pub fn diagnostic_counts_by_category(report : DoctorReport) -> Map[String, Int] {
let counts : Map[String, Int] = {}
for diagnostic in report.diagnostics {
let category = match find_rule_definition(diagnostic.code) {
Some(rule) => rule.category.label()
None => "release"
}
let current = match counts.get(category) {
Some(value) => value
None => 0
}
counts[category] = current + 1
}
counts
}
///|
pub fn diagnostic_counts_by_severity(report : DoctorReport) -> Map[String, Int] {
let counts : Map[String, Int] = { "ERROR": 0, "WARN": 0, "INFO": 0 }
for diagnostic in report.diagnostics {
let key = diagnostic.severity.label()
counts[key] = counts[key] + 1
}
counts
}
///|
pub fn diagnostic_query_to_json(
report : DoctorReport,
query : DiagnosticQuery,
) -> Json {
let diagnostics = query
.filter(report)
.map(diagnostic => {
Json::object({
"severity": Json::string(diagnostic.severity.label()),
"code": Json::string(diagnostic.code),
"message": Json::string(diagnostic.message),
"detail": Json::string(diagnostic.detail),
})
})
Json::object({
"project": Json::string(report.root),
"count": Json::number(diagnostics.length().to_double()),
"diagnostics": Json::array(diagnostics),
})
}
///|
pub fn diagnostic_query_summary(
report : DoctorReport,
query : DiagnosticQuery,
) -> String {
let diagnostics = query.filter(report)
let error_count = diagnostics.filter(item => item.severity == Error).length()
let warning_count = diagnostics.filter(item => item.severity == Warn).length()
let info_count = diagnostics.filter(item => item.severity == Info).length()
"\{diagnostics.length()} findings: \{error_count} errors, \{warning_count} warnings, \{info_count} info"
}
///|
pub fn render_diagnostic_query(
report : DoctorReport,
query : DiagnosticQuery,
) -> String {
let builder = StringBuilder()
let diagnostics = query.filter(report)
builder.write_string(
"Moon Doctor diagnostic query: \{diagnostics.length()} matches\n",
)
for diagnostic in diagnostics {
builder.write_string(
"[" +
diagnostic.severity.label() +
"] " +
diagnostic.code +
": " +
diagnostic.message +
"\n",
)
}
builder.to_string()
}