///|
/// JS StringBuilder concatenation retains deep ropes until a host consumes them.
/// Collect complete JSON fragments and flatten once; no analysis runs in the FFI.
priv struct JsonText {
chunks : Array[String]
}
///|
fn json_text() -> JsonText {
{ chunks: [], }
}
///|
fn JsonText::write_string(self : JsonText, value : String) -> Unit {
self.chunks.push(value)
}
///|
fn JsonText::write_char(self : JsonText, value : Char) -> Unit {
self.chunks.push(value.to_string())
}
///|
fn JsonText::to_string(self : JsonText) -> String {
join_json_chunks(FixedArray::makei(self.chunks.length(), i => self.chunks[i]))
}
///|
#cfg(target="js")
extern "js" fn join_json_chunks(parts : FixedArray[String]) -> String =
#| (parts) => parts.join("")
///|
#cfg(not(target="js"))
fn join_json_chunks(parts : FixedArray[String]) -> String {
let b = StringBuilder()
for part in parts {
b.write_string(part)
}
b.to_string()
}