//// Tiny text-extraction helpers shared by the credential providers //// and the runtime's error parser. Both shapes — XML `X` //// and JSON `"key": "value"` — appear in places where dragging in a //// full XML / JSON parser would be over-investment. //// //// `xml_tag_text` and `json_string_after_key` each scan once with two //// `split_once` calls; neither validates the surrounding document. Use //// them only on inputs whose structure you trust (STS / SSO responses, //// error envelopes), never on arbitrary user-supplied text. import gleam/result import gleam/string /// Pull the text content between the first `` and its matching /// ``. Returns `Error(Nil)` if either tag is absent. Used by the /// STS providers (`...`) and the runtime's /// restXml error path (`NoSuchBucket`). pub fn xml_tag_text(text: String, tag: String) -> Result(String, Nil) { let open = "<" <> tag <> ">" let close = " tag <> ">" use #(_, after_open) <- result.try(string.split_once(text, open)) use #(content, _) <- result.try(string.split_once(after_open, close)) Ok(content) } /// Pull the string value that follows a quoted JSON `"key"`. Skips the /// first quote after the key (i.e. tolerates `"key": "value"`, /// `"key":"value"`, `"key" : "value"`), then reads the next two /// quotes as the value's delimiters. Returns `Error(Nil)` if the key /// is absent or the value isn't a string-typed JSON field. /// /// The function deliberately doesn't unescape backslash sequences in /// the value — callers either don't expect them (STS tokens, error /// codes) or do their own decoding. pub fn json_string_after_key(text: String, key: String) -> Result(String, Nil) { let needle = "\"" <> key <> "\"" use #(_, after_key) <- result.try(string.split_once(text, needle)) use #(_, after_first_quote) <- result.try(string.split_once(after_key, "\"")) use #(value, _) <- result.try(string.split_once(after_first_quote, "\"")) Ok(value) }