///|
pub(all) struct QualityScore {
score : Int
grade : String
notes : Array[String]
} derive(Eq, Debug)
///|
pub fn score_archive(archive : HarArchive) -> QualityScore {
let summary = analyze_archive(archive)
let diagnostics = validate_archive(archive)
let notes : Array[String] = []
let mut score = 100
let errors = diagnostics.count_if(d => d.severity == Error)
let warnings = diagnostics.count_if(d => d.severity == Warning)
if errors > 0 {
score = score - errors * 20
notes.push("validation errors: " + errors.to_string())
}
if warnings > 0 {
score = score - warnings * 5
notes.push("validation warnings: " + warnings.to_string())
}
if summary.failed_count > 0 {
score = score - summary.failed_count * 15
notes.push("failed requests: " + summary.failed_count.to_string())
}
if summary.average_time > 500 {
score = score - 10
notes.push("average request time above 500ms")
}
if summary.longest_time > 2000 {
score = score - 10
notes.push("slowest request above 2000ms")
}
if summary.total_bytes > 5_000_000 {
score = score - 10
notes.push("total bytes above 5MB")
}
let final_score = clamp_score(score)
QualityScore::{
score: final_score,
grade: grade_for_score(final_score),
notes,
}
}
///|
fn clamp_score(score : Int) -> Int {
if score < 0 {
0
} else if score > 100 {
100
} else {
score
}
}
///|
pub fn grade_for_score(score : Int) -> String {
if score >= 90 {
"A"
} else if score >= 80 {
"B"
} else if score >= 70 {
"C"
} else if score >= 60 {
"D"
} else {
"F"
}
}
///|
pub fn render_quality(score : QualityScore) -> String {
let mut out = "quality: " +
score.score.to_string() +
" (" +
score.grade +
")\n"
for i = 0; i < score.notes.length(); i = i + 1 {
out = out + "- " + score.notes[i] + "\n"
}
out
}
///|
pub fn quality_badges(score : QualityScore) -> Array[String] {
let badges : Array[String] = []
if score.score >= 90 {
badges.push("budget-friendly")
}
if score.notes.is_empty() {
badges.push("clean")
}
if score.grade == "F" {
badges.push("needs-attention")
}
badges
}
///|
pub fn recommendation_for_summary(summary : HarSummary) -> Array[String] {
let out : Array[String] = []
if summary.failed_count > 0 {
out.push("fix failing HTTP responses first")
}
if summary.redirected_count > 3 {
out.push("reduce redirect chains")
}
if summary.average_time > 500 {
out.push("investigate slow average request time")
}
if summary.longest_time > 2000 {
out.push("profile the slowest request")
}
if summary.total_bytes > 5_000_000 {
out.push("reduce transferred bytes")
}
if out.is_empty() {
out.push("archive is within the default quality envelope")
}
out
}
///|
pub fn render_recommendations(summary : HarSummary) -> String {
let recs = recommendation_for_summary(summary)
let mut out = ""
for i = 0; i < recs.length(); i = i + 1 {
out = out + "- " + recs[i] + "\n"
}
out
}