lib/pretty/core/src/json/format.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 
  3 pub const Style = enum {
  4     minified,
  5     indent_2,
  6 };
  7 
  8 pub fn stringifyOptions(style: Style) std.json.Stringify.Options {
  9     return switch (style) {
 10         .minified => .{},
 11         .indent_2 => .{ .whitespace = .indent_2 },
 12     };
 13 }
 14 
 15 pub fn writeMinified(writer: anytype, value: anytype) !void {
 16     try std.json.Stringify.value(value, stringifyOptions(.minified), writer);
 17 }
 18 
 19 pub fn writeMinifiedLine(writer: anytype, value: anytype) !void {
 20     try writeMinified(writer, value);
 21     try writer.writeByte('\n');
 22 }
 23 
 24 pub fn renderMinifiedAlloc(
 25     allocator: std.mem.Allocator,
 26     value: anytype,
 27 ) std.mem.Allocator.Error![]u8 {
 28     var out: std.Io.Writer.Allocating = .init(allocator);
 29     errdefer out.deinit();
 30     writeMinified(&out.writer, value) catch return error.OutOfMemory;
 31     return try out.toOwnedSlice();
 32 }
 33 
 34 pub fn renderMinifiedLineAlloc(
 35     allocator: std.mem.Allocator,
 36     value: anytype,
 37 ) std.mem.Allocator.Error![]u8 {
 38     var out: std.Io.Writer.Allocating = .init(allocator);
 39     errdefer out.deinit();
 40     writeMinifiedLine(&out.writer, value) catch return error.OutOfMemory;
 41     return try out.toOwnedSlice();
 42 }
 43 
 44 pub fn writeIndented(writer: anytype, value: anytype) !void {
 45     try std.json.Stringify.value(value, stringifyOptions(.indent_2), writer);
 46 }
 47 
 48 pub fn renderIndentedAlloc(allocator: std.mem.Allocator, value: anytype) ![]u8 {
 49     var out: std.Io.Writer.Allocating = .init(allocator);
 50     errdefer out.deinit();
 51     try writeIndented(&out.writer, value);
 52     return try out.toOwnedSlice();
 53 }
 54 
 55 test "writeMinified serializes byte-stable machine JSON" {
 56     const allocator = std.testing.allocator;
 57     var parsed = try std.json.parseFromSlice(std.json.Value, allocator, "{\"name\":\"alpha\",\"items\":[1,true,null]}", .{});
 58     defer parsed.deinit();
 59 
 60     var out = std.Io.Writer.Allocating.init(allocator);
 61     defer out.deinit();
 62     try writeMinified(&out.writer, parsed.value);
 63     try std.testing.expectEqualStrings("{\"name\":\"alpha\",\"items\":[1,true,null]}", out.written());
 64 
 65     const rendered = try renderMinifiedAlloc(allocator, .{ .status = "ok", .count = @as(u8, 2) });
 66     defer allocator.free(rendered);
 67     try std.testing.expectEqualStrings("{\"status\":\"ok\",\"count\":2}", rendered);
 68 }
 69 
 70 test "writeMinifiedLine serializes independent escaped JSONL records" {
 71     var out = std.Io.Writer.Allocating.init(std.testing.allocator);
 72     defer out.deinit();
 73 
 74     try writeMinifiedLine(&out.writer, .{ .event = "first\"\n", .count = @as(u8, 1) });
 75     try writeMinifiedLine(&out.writer, .{ .event = "second", .count = @as(u8, 2) });
 76 
 77     try std.testing.expectEqualStrings(
 78         "{\"event\":\"first\\\"\\n\",\"count\":1}\n" ++
 79             "{\"event\":\"second\",\"count\":2}\n",
 80         out.written(),
 81     );
 82 
 83     const rendered = try renderMinifiedLineAlloc(
 84         std.testing.allocator,
 85         .{ .event = "owned", .count = @as(u8, 3) },
 86     );
 87     defer std.testing.allocator.free(rendered);
 88     try std.testing.expectEqualStrings(
 89         "{\"event\":\"owned\",\"count\":3}\n",
 90         rendered,
 91     );
 92 }
 93 
 94 test "allocated renders expose allocator failures" {
 95     var failing = std.testing.FailingAllocator.init(
 96         std.testing.allocator,
 97         .{ .fail_index = 0 },
 98     );
 99     try std.testing.expectError(
100         error.OutOfMemory,
101         renderMinifiedAlloc(failing.allocator(), .{ .status = "ok" }),
102     );
103     try std.testing.expectError(
104         error.OutOfMemory,
105         renderMinifiedLineAlloc(failing.allocator(), .{ .status = "ok" }),
106     );
107 }
108 
109 test "writeIndented serializes two-space machine JSON" {
110     const allocator = std.testing.allocator;
111     const rendered = try renderIndentedAlloc(allocator, .{ .status = "ok", .count = @as(u8, 2) });
112     defer allocator.free(rendered);
113     try std.testing.expectEqualStrings(
114         "{\n  \"status\": \"ok\",\n  \"count\": 2\n}",
115         rendered,
116     );
117 }