Skip to main content

c_src/glazer_json_format.hpp

// Standalone JSON prettify / minify
#pragma once

#include <string>
#include <string_view>
#include <vector>

namespace glz {

// Returns a prettified copy of `in` (2-space indent, assumes valid JSON).
inline std::string prettify_json(std::string_view in)
{
  std::string out;
  out.reserve(in.size() * 2);

  int  indent   = 0;
  bool in_str   = false;
  bool escape   = false;

  auto newline = [&] {
    out += '\n';
    for (int i = 0; i < indent * 3; ++i) out += ' ';
  };

  for (size_t i = 0; i < in.size(); ++i) {
    char c = in[i];

    if (escape) { out += c; escape = false; continue; }
    if (in_str) {
      out += c;
      if (c == '\\') escape = true;
      else if (c == '"') in_str = false;
      continue;
    }

    switch (c) {
      case '"':
        out += c; in_str = true;
        break;
      case '{': case '[':
        out += c;
        // peek: if immediately closed, emit on same line (e.g. `[]`, `{}`)
        {
          size_t j = i + 1;
          while (j < in.size() && (in[j] == ' ' || in[j] == '\t' || in[j] == '\r' || in[j] == '\n')) ++j;
          if (j < in.size() && (in[j] == '}' || in[j] == ']')) break;
        }
        ++indent;
        newline();
        break;
      case '}': case ']':
        // empty collection (e.g. `[]`, `{}`): closing bracket immediately
        // follows the opening one, already emitted on the same line
        if (!out.empty() && (out.back() == '{' || out.back() == '[')) {
          out += c;
          break;
        }
        --indent;
        newline();
        out += c;
        break;
      case ',':
        out += c;
        newline();
        break;
      case ':':
        out += ':'; out += ' ';
        break;
      case ' ': case '\t': case '\r': case '\n':
        // strip existing whitespace outside strings
        break;
      default:
        out += c;
        break;
    }
  }
  return out;
}

// Returns a minified copy of `in` (assumes valid JSON).
inline std::string minify_json(std::string in)
{
  std::string out;
  out.reserve(in.size());

  bool in_str = false;
  bool escape = false;

  for (char c : in) {
    if (escape) { out += c; escape = false; continue; }
    if (in_str) {
      out += c;
      if (c == '\\') escape = true;
      else if (c == '"') in_str = false;
      continue;
    }
    if (c == '"') { out += c; in_str = true; continue; }
    if (c == ' ' || c == '\t' || c == '\r' || c == '\n') continue;
    out += c;
  }
  return out;
}

} // namespace glz