json5 API reference Changelog View on GitHub

API reference

JSON5 in Zig: unquoted keys, single quotes, hex numbers, NaN, and comments.

parseFromSlice reads one JSON5 value into a std.json.Value tree, built from the same Value, ObjectMap, and Array types as std.json, so a tree moves between the two parsers. Given a destination type, it decodes that tree through std.json.parseFromValue. Stringify writes either form as strict JSON.

Name characters are an approximation: ASCII IdentifierStart and IdentifierPart, plus any non-ASCII code point. The exact ES5.1 categories would need a Unicode property table this package does not vendor.

A \uXXXX escape or a surrogate pair decodes before the check, so \uD801\uDC00 and U+10400 are the same name character. A lone surrogate is an error.

A number is .integer when its literal has no fraction and no exponent, fits i64, and is not a negative zero. Every other number is .float, including a hexadecimal value past i64. .number_string is never produced.

pub const Value = std.json.Value

src

A JSON5 value. It is std.json.Value, so the tags, the object map, and the array are the ones in std.json.

pub const Array = std.json.Array

src

An array of values, the std.json one.

pub const ObjectMap = std.json.ObjectMap

src

An object's member map, the std.json one. Member order is insertion order, and a repeated name keeps its first position.

module Diagnostics

src

Where a parse failed: the bytes, the position, and a message. The caller owns this struct and passes it in ParseOptions.

Constants

pub const init: Diagnostics = …

src
value
.{
    .span = .{ .start = 0, .end = 0 },
    .line = 1,
    .column = 1,
    .len = 0,
    .buf = undefined,
}

The state before a parse writes into it: an empty span at the start of the source, on line 1, column 1, with no message.

Functions

pub fn message(self: *const Diagnostics) []const u8

src

The explanation, for example "a name cannot start with 10".

The bytes live in this struct, so the message stays valid after the parser that made it is gone.

pub fn setMessage(self: *Diagnostics, comptime fmt: []const u8, args: anytype) void

src

Render a message into the diagnostic, truncating on a character boundary when it does not fit.

Types

struct Span

src

Byte offsets into the source. start is the first byte the message refers to, and end is one past the last byte.

Fields

start: u32
end: u32

struct Span

src
pub const Span = Diagnostics.Span

Byte offsets into the source: the first offending byte and one past the last.

Fields

start: u32
end: u32

module Stringify

src

Writes a std.json.Value as strict JSON. See Stringify.Options.

Constants

pub const Error = Writer.Error || error{ NonFiniteFloat, NestingTooDeep }

src

Functions

pub fn init(writer: *Writer, options: Options) Stringify

src

A writer at the start of a document: no indentation, no nesting, and the first value ready.

pub fn beginArray(self: *Stringify) Error!void

src

pub fn beginObject(self: *Stringify) Error!void

src

pub fn endArray(self: *Stringify) Error!void

src

pub fn endObject(self: *Stringify) Error!void

src

pub fn print(self: *Stringify, comptime fmt: []const u8, args: anytype) Error!void

src

An alternative to calling write that formats a value with std.fmt. This function does the usual punctuation and indentation formatting assuming the resulting formatted string represents a single complete value; e.g. "1", "[]", "[1,2]", not "1,2". This function may be useful for doing your own number formatting.

pub fn beginWriteRaw(self: *Stringify) !void

src

An alternative to calling write that allows you to write directly to the .writer field, e.g. with .writer.writeAll(). Call beginWriteRaw(), then write a complete value (including any quotes if necessary) directly to the .writer field, then call endWriteRaw(). This can be useful for streaming very long strings into the output without needing it all buffered in memory.

pub fn endWriteRaw(self: *Stringify) void

src

See beginWriteRaw.

pub fn objectField(self: *Stringify, key: []const u8) Error!void

src

See Stringify for when to call this method. key is the string content of the property name. Surrounding quotes will be added and any special characters will be escaped. See also objectFieldRaw.

pub fn objectFieldRaw(self: *Stringify, quoted_key: []const u8) Error!void

src

See Stringify for when to call this method. quoted_key is the complete bytes of the key including quotes and any necessary escape sequences. A few assertions are performed on the given value to ensure that the caller of this function understands the API contract. See also objectField.

pub fn beginObjectFieldRaw(self: *Stringify) !void

src

In the rare case that you need to write very long object field names, this is an alternative to objectField and objectFieldRaw that allows you to write directly to the .writer field similar to beginWriteRaw. Call endObjectFieldRaw() when you're done.

pub fn endObjectFieldRaw(self: *Stringify) void

src

See beginObjectFieldRaw.

pub fn write(self: *Stringify, v: anytype) Error!void

src

Renders the given Zig value as JSON.

more

Supported types:

  • Zig bool -> JSON true or false.
  • Zig ?T -> null or the rendering of T.
  • Zig i32, u64, etc. -> JSON number or string.
    • When option emit_nonportable_numbers_as_strings is true, if the value is outside the range +-1<<53 (the precise integer range of f64), it is rendered as a JSON string in base 10. Otherwise, it is rendered as JSON number.
  • Zig floats -> JSON number or string.
    • If the value cannot be precisely represented by an f64, it is rendered as a JSON string. Otherwise, it is rendered as JSON number.
    • TODO: Float rendering will likely change in the future, e.g. to remove the unnecessary "e+00".
  • Zig []const u8, []u8, *[N]u8, @Vector(N, u8), and similar -> JSON string.
    • See Options.emit_strings_as_arrays.
    • If the content is not valid UTF-8, rendered as an array of numbers instead.
  • Zig []T, [N]T, *[N]T, @Vector(N, T), and similar -> JSON array of the rendering of each item.
  • Zig tuple -> JSON array of the rendering of each item.
  • Zig struct -> JSON object with each field in declaration order.
    • If the struct declares a method pub fn jsonStringify(self: *@This(), jw: anytype) !void, it is called to do the serialization instead of the default behavior. The given jw is a pointer to this Stringify. See std.json.Value for an example.
    • See Options.emit_null_optional_fields.
  • Zig union(enum) -> JSON object with one field named for the active tag and a value representing the payload.
    • If the payload is void, then the emitted value is {}.
    • If the union declares a method pub fn jsonStringify(self: *@This(), jw: anytype) !void, it is called to do the serialization instead of the default behavior. The given jw is a pointer to this Stringify.
  • Zig enum -> JSON string naming the active tag.
    • If the enum declares a method pub fn jsonStringify(self: *@This(), jw: anytype) !void, it is called to do the serialization instead of the default behavior. The given jw is a pointer to this Stringify.
    • If the enum is non-exhaustive, unnamed values are rendered as integers.
  • Zig untyped enum literal -> JSON string naming the active tag.
  • Zig error -> JSON string naming the error.
  • Zig *T -> the rendering of T. Note there is no guard against circular-reference infinite recursion.

See also alternative functions print and beginWriteRaw. For writing object field names, use objectField instead.

pub fn value(v: anytype, options: Options, writer: *Writer) Error!void

src

Writes the given value to the Writer writer. See Stringify for how the given value is serialized into JSON. The maximum nesting depth of the output JSON document is 256.

pub fn valueAlloc(gpa: Allocator, v: anytype, options: Options) error{OutOfMemory}![]u8

src

Calls value and stores the result in dynamically allocated memory instead of taking a writer.

Caller owns returned memory.

pub fn encodeJsonString(string: []const u8, options: Options, writer: *Writer) Error!void

src

Write string to writer as a JSON encoded string.

pub fn encodeJsonStringChars(chars: []const u8, options: Options, writer: *Writer) Error!void

src

Write chars to writer as JSON encoded string characters.

Types

struct Options

src

Fields

allow_nonfinite: bool = true

false makes NaN and Infinity fail instead of being written as the JSON5 spelling.

whitespace: enum { minified, indent_1, indent_2, indent_3, indent_4, indent_8, indent_tab, } = .minified

Controls the whitespace emitted. The default .minified is a compact encoding with no whitespace between tokens. Any setting other than .minified will use newlines, indentation, and a space after each ':'. .indent_1 means 1 space for each indentation level, .indent_2 means 2 spaces, etc. .indent_tab uses a tab for each indentation level.

emit_null_optional_fields: bool = true

Should optional fields with null value be written?

emit_strings_as_arrays: bool = false

Arrays/slices of u8 are typically encoded as JSON strings. This option emits them as arrays of numbers instead. Does not affect calls to objectField*().

escape_unicode: bool = false

Should unicode characters be escaped in strings?

emit_nonportable_numbers_as_strings: bool = false

When true, renders numbers outside the range +-1<<53 (the precise integer range of f64) as JSON strings in base 10.

pub const ParseError = Allocator.Error || std.json.ParseFromValueError || error{SyntaxError}

src

What a parse can return: the source breaks the grammar, the allocator failed, or the typed pass rejected the tree. On error.SyntaxError, options.diagnostics says where.

struct ParseOptions

src

How to parse a document.

Fields

diagnostics: ?*Diagnostics = null

Filled on error.SyntaxError. Untouched when the parse succeeds, and on error.OutOfMemory. Null means the caller wants only the error.

json: std.json.ParseOptions = .{}

The std.json options, used when T is not std.json.Value: duplicate fields, unknown fields, string allocation, and numbers.

type fn Parsed

src
pub fn Parsed(comptime T: type) type

A parsed value and the memory that holds it.

Fields

arena: *ArenaAllocator

The arena that owns every string, object, and array in value.

It is heap-allocated on purpose. std.json.Array is a managed list that carries the allocator it was built with, and that allocator's pointer is this arena. A value field would move with Parsed, and every array in the tree would point at a dead stack slot.

value: T

The root value.

Functions

pub fn deinit(self: Self) void

src

Free the arena and everything the value points at. Takes self by value, like std.json.Parsed.

pub fn parseFromSlice( comptime T: type, allocator: Allocator, source: []const u8, options: ParseOptions, ) ParseError!Parsed(T)

src

Parse one JSON5 document into T.

more

T is any type std.json.parseFromValue accepts: a struct, a union, an enum, a slice, or std.json.Value for the tree. Every string, object, and array the value points at is copied into an arena that the returned Parsed owns, so the source may be freed as soon as this returns.

When T is std.json.Value, the tree comes back as it was parsed. For anything else, the parser builds the tree first and std.json turns it into T with options.json. A document that breaks the grammar is error.SyntaxError, and options.diagnostics says where.

pub fn parseFromSliceLeaky( comptime T: type, allocator: Allocator, source: []const u8, options: ParseOptions, ) ParseError!T

src

Parse one JSON5 document into T, in memory the caller already owns.

more

Use this when the caller has an arena whose lifetime is known, such as a request or a configuration load. The returned value owns nothing, and freeing it is the caller's problem. The source is still copied, so it may be freed as soon as this returns. The arena must stay at the same address while the value lives, because a std.json.Value tree's arrays hold the allocator built from it.