| 97 | // ── JSON helpers ──────────────────────────────────────────────────────── |
| 98 | |
| 99 | static std::string JsonEscape(const std::string& s) { |
| 100 | std::ostringstream out; |
| 101 | for (char c : s) { |
| 102 | switch (c) { |
| 103 | case '"': out << "\\\""; break; |
| 104 | case '\\': out << "\\\\"; break; |
| 105 | case '\n': out << "\\n"; break; |
| 106 | case '\r': out << "\\r"; break; |
| 107 | case '\t': out << "\\t"; break; |
| 108 | default: out << c; |
| 109 | } |
| 110 | } |
| 111 | return out.str(); |
| 112 | } |
| 113 | |
| 114 | static std::string JsonObject(std::initializer_list<std::pair<std::string, std::string>> fields) { |
| 115 | std::ostringstream out; |