yaml
YAML decode + encode for authored engine content. Pure Luau, no engine dependencies — a general parsing library, not data-system plumbing.
yaml.module
YAML decode + encode for authored engine content. Pure Luau, no engine dependencies — a general parsing library, not data-system plumbing.
local Yaml = require("@builtin::modules.yaml")
local doc = Yaml.decode(vfs.read(path))
vfs.write(path, Yaml.encode(doc))
Supported subset
- Block mappings (
key: value) and block sequences (- item), nested to any depth. - Compact sequence-of-mapping entries (
- path: x/kind: y). - Flow collections —
{ a: 1, b: 2 }and[1, 2, 3]— single line. - Plain scalars with type inference:
~/null→ nil,true/false→ boolean, numeric literals → number, everything else → string. - Single- and double-quoted strings (
''escapes a literal quote inside a single-quoted string;\n\t\r\\\"inside a double-quoted one). A quote opens a quoted scalar where a scalar begins — afterkey:, after a-entry marker, or inside a flow collection — so a plain scalar carries an apostrophe as data (note: the world's rules). Quoted keys are read in flow mappings. #comments — honored outside quotes, so a#inside a quoted string is kept as data.- Literal (
|) and folded (>) block scalars — the bare indicators only. A block scalar's content is literal text: quotes (balanced or not),#,key: valueand---inside it are data. - An optional leading
---document marker.
Loud-error contract
Constructs outside the subset above raise instead of misparsing:
anchors/aliases (&, *), tags (!), directives (%),
multi-document streams (a second ---), block-scalar
chomping/indentation indicators (|-, |+, >-, |2, ...), tab
indentation, and inconsistent indentation (both block structure and
block-scalar bodies). Every error carries the offending line number
(yaml: line N: ...), so a bad config points straight at the line to
fix.
Tab indentation is rejected everywhere — including block-scalar body lines whose leading whitespace contains a tab. A tab after the first non-space character of a line is content and passes through.
API
Yaml.decode(text: string): any— decode a YAML document into a Luau value (table, scalar, or nil for an empty document). Raises on malformed input or an unsupported construct.Yaml.decodeWithComments(text: string): (any, boolean)— decode asdecodedoes, and report whether the text carries a comment by the decoder's own rule: a#at a line's start or after whitespace, outside a quoted scalar and outside a block scalar. Re-encoding the value drops such comments, so an editor that writes a document back reads this first.Yaml.encode(value: table): string— encode a Luau table as YAML (block style, two-space indent, alphabetically sorted keys). Raises on values YAML can't represent (functions, userdata, non-string mapping keys).
A top-level empty table encodes to an empty document, which decodes
back to nil (the YAML empty-document ambiguity).
Scoped to this part · feeds back into the world's score.