///|
/// Fully prepared canonical document and its audit metadata.
pub(all) struct CanonicalDocument {
canonical : String
digest : String
byte_length : Int
stats : JsonStats
issue_count : Int
}
///|
/// Parse, normalize, hash, and collect metrics once for repeated consumers.
pub fn prepare_document(input : String) -> Result[CanonicalDocument, String] {
let value = match parse(input) {
Ok(value) => value
Err(error) => return Err(error.message())
}
inspect_value(value)
}
///|
/// Prepare a document while enforcing limits before collecting audit data.
pub fn prepare_document_with_limits(
input : String,
limits : DocumentLimits,
) -> Result[CanonicalDocument, String] {
let value = match parse_with_limits(input, limits) {
Ok(value) => value
Err(error) => return Err(error)
}
inspect_value(value)
}
///|
fn inspect_value(value : JsonValue) -> Result[CanonicalDocument, String] {
let stats = JsonStats::empty()
collect_stats(value, 0, stats)
let canonical = match canonicalize(value) {
Ok(canonical) => canonical
Err(error) => return Err(error.message())
}
let digest = match canonical_digest(value) {
Ok(digest) => digest
Err(error) => return Err(error.message())
}
let issue_count = canonical_issues(value).length()
Ok({
canonical,
digest,
byte_length: @utf8.encode(canonical).length(),
stats,
issue_count,
})
}
///|
pub fn CanonicalDocument::to_json(self : CanonicalDocument) -> String {
"{\"canonical\":" +
canonical_string(self.canonical) +
",\"digest\":" +
canonical_string(self.digest) +
",\"byte_length\":" +
self.byte_length.to_string() +
",\"issue_count\":" +
self.issue_count.to_string() +
",\"stats\":" +
self.stats.to_json() +
"}"
}
///|
pub fn CanonicalDocument::summary(self : CanonicalDocument) -> String {
"bytes=" +
self.byte_length.to_string() +
",sha256=" +
self.digest +
",values=" +
self.stats.value_count.to_string() +
",issues=" +
self.issue_count.to_string()
}