Skip to main content

Formats

Every format is its own module, imported on first use:

local config = Quark.TOML.Decode(text)
local payload = Quark.JSON.Encode({ id = Quark.UUID.V7(), score = 10 })

Data formats​

JSON, TOML, YAML, MessagePack and CBOR share one API:

Function
Format.Encode(value, options?, callback?)text (JSON, TOML, YAML) or binary string (MessagePack, CBOR)
Format.Decode(input, options?, callback?)Lua value, or nil, message for invalid input. input can be a string or a Buffer

Both run synchronously, or on a worker thread when a callback is given (or with Quark.Await). Converting between Lua tables and the format always happens on the game thread, parsing and printing happen on the worker, which keeps large documents off the game thread.

OptionApplies to
PrettyJSON, TOMLhuman readable output, JSON indented by 2 spaces
IndentJSONpretty output with this many spaces
EmptyTablesAsArraysencodingencode {} as an empty array instead of an empty object
PreserveNulldecodingdecode null as Format.Null instead of nil, keeps keys and array positions

Mapping to Lua​

FormatLua
object / maptable, keys are always sorted when encoding
arraysequence table, marked so that it encodes as an array again even when empty
string, number, booleanstring, integer or float, boolean
nullnil, or Format.Null with PreserveNull
binary (MessagePack, CBOR)string
date and time (TOML)string in RFC 3339 format

A table is encoded as an array when it is a sequence or was marked with Format.Array(table?), otherwise as an object. Tables mixing both, functions, userdata and recursive tables cannot be encoded. JSON and TOML objects need string keys, MessagePack and CBOR maps accept any keys.

Null, Array and IsNull exist in JSON, YAML, MessagePack and CBOR, the values are the same in all of them.

TOML documents have to be tables. MessagePack decoding follows rmpv, which reads the reserved byte 0xC1 as nil. Trailing bytes after a MessagePack or CBOR value are rejected.

CSV​

FunctionOptions
CSV.Decode(input, options?, callback?)Header (default true): rows become tables keyed by column name, otherwise lists. Delimiter (,), Trim (false)
CSV.Encode(rows, options?, callback?)Columns (column order, default: sorted keys of all rows), Header (default true for keyed rows), Delimiter

Fields are decoded as strings. When encoding, rows can be lists or keyed tables, values have to be strings, numbers or booleans, nil becomes an empty field. Quoting follows RFC 4180.

local rows = Quark.CSV.Decode("name,score\nalice,10\n")
-- { { name = "alice", score = "10" } }

UUID​

Function
UUID.V4()random UUID
UUID.V7()time ordered UUID, later calls always sort after earlier ones, ideal as database key
UUID.Parse(text)canonical lowercase form, accepts braces, URNs and the form without hyphens, or nil, message
UUID.IsValid(value)whether the value is a valid UUID string
UUID.GetVersion(text)version number
UUID.GetTimestamp(text)creation time in Unix milliseconds for time based versions (1, 6, 7), or nil, message
UUID.ToBytes(text) / UUID.FromBytes(bytes)16 byte binary form
UUID.Nil, UUID.Maxall zeros and all ones

URL​

Function
URL.Encode(text, form?)percent encode a component, keeps A-Z a-z 0-9 - . _ ~. With form = true spaces become +
URL.Decode(text, form?)percent decode, with form = true + becomes a space
URL.EncodeQuery(parameters)a=1&b=2 with sorted keys, lists become repeated keys
URL.DecodeQuery(query)table of parameters, repeated keys become lists, a leading ? is ignored
URL.Parse(url){ Scheme, Username, Password, Host, Port, Path, Query, Fragment, Origin } (the port falls back to the scheme default), or nil, message
URL.Join(base, relative)resolved URL, or nil, message
local url = "https://api.example.com/search?" .. Quark.URL.EncodeQuery({ q = "hello world", page = 2 })
-- https://api.example.com/search?page=2&q=hello+world

XML​

Function
XML.Decode(input, options?, callback?)root element, or nil, message. Option PreserveWhitespace keeps text nodes that only contain whitespace
XML.Encode(element, options?, callback?)XML text, options Pretty, Indent and Declaration (default true, writes <?xml version="1.0" encoding="UTF-8"?>)
XML.Find(element, name)first child element with that name, or nil
XML.FindAll(element, name?)all child elements, optionally only those with that name
XML.GetText(element)text content of the element and all descendants

An element is a table { Name, Attributes = { name = value }, Children = { ... } }, children are elements or strings. Entities and CDATA sections are resolved, comments, processing instructions and the document type are dropped. Names keep their namespace prefix ("soap:Body"). Attribute values are written in sorted order, numbers and booleans become text.

local root = Quark.XML.Decode('<server port="7777"><motd>Hello</motd></server>')
local port = tonumber(root.Attributes.port)
local motd = Quark.XML.GetText(Quark.XML.Find(root, "motd"))

INI​

Function
INI.Decode(input, options?, callback?)table of sections, keys before the first section are stored at the top level
INI.Encode(document)INI text, scalar values at the top level form the general section, tables become sections

Values are decoded as strings. Sections cannot be nested.

JSON Schema​

Function
JSON.Validate(value, schema)true, or false and a list of { Path, Message } errors
JSON.Schema(schema)compiled validator with :Validate(value) and :IsValid(value), compile once when validating many values

The schema is a Lua table or JSON text. Drafts 4, 6, 7, 2019-09 and 2020-12 are supported, the draft is taken from $schema and defaults to 2020-12. Error paths are JSON pointers (/items/0/name), so array positions count from 0. References to other documents are not fetched, neither over the network nor from files, a schema using them fails to compile.

local Player = Quark.JSON.Schema({
type = "object",
required = { "name" },
properties = { name = { type = "string", minLength = 3 } },
})

local valid, errors = Player:Validate(request)