// What happens when Slack sends something this version does not model.
//
// Parsing is TOTAL: `parse_blocks` never fails, and anything unrecognised
// becomes an `Unknown*` variant that carries the original JSON. Strictness is a
// separate walk over the result, so there is exactly one parser rather than a
// lenient one and a strict one that can drift apart.
//
// That split is also what makes the round-trip property testable: a strict
// parser would refuse the very payloads the corpus is full of, so the property
// could only ever be checked on the lenient path.
///|
/// What to do with a `"type"` this version does not model.
///
/// Slack ships new block types faster than any SDK adopts them, and a bot that
/// breaks because a coworker used a block released last Tuesday is a worse
/// outcome than one that renders it as an opaque payload. So the default is
/// lenient, and strict is opt-in for the cases where refusing is the point: a
/// linter, a test, a validating endpoint.
///
/// java-slack-sdk offers the same choice as
/// `createSnakeCaseWithoutUnknownPropertyDetection(true|false)`, and its
/// BlockKitTest tests every unknown-type payload twice, once per policy. So
/// does unknown_test.mbt here.
pub(all) enum UnknownPolicy {
Lenient
Strict
} derive(Eq, Debug)
///|
/// Why a strict parse refused a payload.
///
/// The message text is java-slack-sdk's, verbatim, so its BlockKitTest
/// assertions port literally and so that an operator who has seen one SDK's
/// message recognises the other's.
pub(all) suberror BlockParseError {
UnsupportedLayoutBlock(String)
UnknownBlockElement(String)
UnknownContextBlockElement(String)
UnknownTextObject(String)
UnknownRichTextElement(String)
} derive(Eq, Debug)
///|
pub impl Show for BlockParseError with fn output(self, logger) {
logger.write_string(self.describe_error())
}
///|
pub fn BlockParseError::describe_error(self : Self) -> String {
match self {
UnsupportedLayoutBlock(t) => "Unsupported layout block type: \{t}"
UnknownBlockElement(t) => "Unknown block element type: \{t}"
UnknownContextBlockElement(t) => "Unknown context block element type: \{t}"
UnknownTextObject(t) => "Unknown text object type: \{t}"
UnknownRichTextElement(t) => "Unknown rich text element type: \{t}"
}
}
///|
/// The `type` field of a JSON value, for error messages and dispatch.
///
/// `""` when there is none -- which is not only a missing-field case: Slack's
/// scrubbed fixtures contain literal `"type": ""`, so the empty string is real
/// data and not a sentinel.
fn type_tag_of(j : Json) -> String {
match j {
Object(o) =>
match o.get("type") {
Some(String(s)) => s
_ => ""
}
_ => ""
}
}