///|
fn parse_error_report(
input : String,
error : IcdParseError,
) -> ValidationReport {
match error {
IcdParseError::EmptyInput =>
{
input,
normalized: None,
status: Invalid,
chapter: None,
entry: None,
issues: [
parse_issue(
input, "empty ICD code", "Pass a category such as I10 or a subcategory such as A00.0.",
),
],
}
IcdParseError::InvalidCode(_) =>
{
input,
normalized: None,
status: Invalid,
chapter: None,
entry: None,
issues: [
parse_issue(
input, "invalid ICD-10 syntax", "Expected one letter, two digits, and an optional decimal subcategory.",
),
],
}
IcdParseError::UnsupportedEdition(_) =>
{
input,
normalized: None,
status: Invalid,
chapter: None,
entry: None,
issues: [
parse_issue(
input, "unsupported edition", "Use ICD-10 validation for this command.",
),
],
}
}
}
///|
pub fn validate_against(catalog : Catalog, input : String) -> ValidationReport {
try parse_icd10(input) catch {
error => parse_error_report(input, error)
} noraise {
code => {
let normalized = code.canonical()
let chapter = find_chapter(code)
let entry = catalog.lookup(normalized)
let issues = match entry {
Some(item) =>
item.excludes.map(fn(ex) {
parse_issue(
normalized,
"exclusion hint: \{ex}",
"Review whether \{ex} is a better fit for this diagnosis context.",
)
})
None =>
[
parse_issue(
normalized, "code is syntactically valid but not in the bundled sample catalog",
"Load a full licensed ICD table or use chapter/range checks for structural validation.",
),
]
}
{
input,
normalized: Some(normalized),
status: if entry is Some(_) {
Valid
} else {
Unknown
},
chapter,
entry,
issues,
}
}
}
}
///|
pub fn validate_icd10(input : String) -> ValidationReport {
validate_against(bundled_catalog(), input)
}
///|
pub fn format_report(report : ValidationReport) -> String {
let status = match report.status {
Valid => "valid"
Unknown => "unknown"
Invalid => "invalid"
}
let code = report.normalized.unwrap_or(report.input)
let chapter = match report.chapter {
Some(c) => "chapter \{c.id}: \{c.title}"
None => "chapter: not resolved"
}
let entry = match report.entry {
Some(e) => "\{e.code} \{e.title}"
None => "entry: not in bundled sample catalog"
}
let issues = if report.issues.is_empty() {
"issues: none"
} else {
"issues:\n" +
report.issues.map(fn(i) { "- \{i.message}; \{i.hint}" }).join("\n")
}
"ICD check \{status}: \{code}\n\{chapter}\n\{entry}\n\{issues}"
}