YAML for MoonBit.
let config = @moonyaml.loads(
#|server:
#| host: 0.0.0.0
#| port: 12000
#|limits: &shared { files: 1000, bytes: 1048576 }
#|upload: *shared
)
@moonyaml.dumps(config) // back to YAML, block style
@moonyaml.loads_all(stream) // every document in a `---` streamlet doc = @moonyaml.parse(src) // keeps the comments too
@moonyaml.emit(doc) // and writes them back
doc.to_json() // what it means, for a caller who wants a valuemoon add moonbitstack/moonyaml| Package | What it is |
|---|---|
| moonbitstack/moonyaml | YAML 1.2.2's core schema, the writer, the document model, and the typed codec |
| moonbitstack/moonyaml/yaml11 | YAML 1.1: yes/no/on/off as booleans, 014 as octal, sexagesimals, 1_000, and the << merge key |
| moonbitstack/moonyaml/yaml10 | YAML 1.0's types, which 1.1 inherited but did not always keep |
| moonbitstack/moonyaml/strict | StrictYAML: block structure only, every scalar a string, no flow style, no anchors, no tags, no duplicate keys |
| moonbitstack/moonyaml/any | Reads the version a document asks for with %YAML, and 1.2.2 when it asks for nothing |
| Function | Gives back |
|---|---|
| loads(src) / loads_all(src) | Json — the one document, or every document in the stream |
| load(bytes) / load_all(bytes) | The same, decoding UTF-8 and skipping a leading BOM |
| loads_as[T](src) / load_as[T](bytes) | A typed value, through @json.FromJson |
| dumps(value) / dumps_all(values) | YAML text |
| dump(value) / dump_all(values) | The same, as Bytes |
| dumps_of[T](value) / dumps_of_all[T](values) | The same, through @json.ToJson |
| round_trip[T](src, adjust~) | A typed value written back, for checking that a decode is a decode |
| parse(src) / parse_all(src) | Node — the document, comments and all |
| emit(node) | YAML text that reads back as the same document |
| Collections | Block mappings and sequences, flow {} and [], nested in either direction, a sequence in its parent key's own column |
| Scalars | Plain over several lines (breaks fold, blank lines do not), single- and double-quoted with the escapes of §5.7, literal \| and folded > with chomping and explicit indentation |
| Structure | Anchors and aliases, tags including %TAG handles and verbatim !<…>, %YAML, --- and ... markers, ? key explicit pairs, complex keys |
| Resolution | The core schema of §10.2: null/~, booleans, decimal, 0o and 0x integers, floats with exponents, .inf and .nan |
| Version | Same as 1.2.2 | Reads differently | Refused by both | Refused only here | Read only here |
|---|---|---|---|---|---|
| 1.2.2 (core) | 292 | 0 | 110 | 0 | 0 |
| 1.1 | 291 | 1 | 110 | 0 | 0 |
| 1.0 | 290 | 2 | 110 | 0 | 0 |
| StrictYAML | 155 | 25 | 110 | 112 | 0 |
| Case | Why |
|---|---|
| DK95/2 | A tab where a continuation line's indentation belongs |
| Y79Y/4 | A tab-only line at the head of a block scalar |
@moonyaml.loads(src, flavor=@moonyaml.Flavor::new(duplicates=Reject))
@moonyaml.loads(src, flavor={ ..@moonyaml.strict, budget: 1000 })
@moonyaml.dumps(value, style=@moonyaml.flow)
@moonyaml.dumps(value, indent=4, sort=true)| Flavor | Preset | Where the number comes from |
|---|---|---|
| depth | 500 | Between Jackson's 1000 and serde_json's 128, and the same as this family's JSON reader |
| duplicates | Last | What every loader in reach does. First and Reject are there because a key written twice is usually a mistake |
| aliases | true | An alias is part of the language; false refuses one outright |
| budget | 10 000 000 | An alias can name a node holding aliases, so a dozen lines can expand to billions — the "billion laughs", which libyaml and PyYAML's safe_load both still perform faithfully. There is no common value to follow, so this takes the safe side |
| Style | Preset | Where the number comes from |
|---|---|---|
| indent | 2 | What Kubernetes manifests and Compose files use; the value kubectl writes |
| width | 80 | Where a flow collection stops fitting on a line — the width every formatter has used since the terminal |
| layout | Block | Block style reads better in a diff; Flow writes JSON's own shape, Auto decides per collection by width |
| quotes | Minimal | Quote only what has to be quoted, which is what a person writing YAML does |
| anchors | true | A collection that appears twice is written once and referenced, which is what PyYAML and ruamel.yaml do with a shared object |
| sort | false | A document keeps the order it was written in; a caller who wants a stable file turns this on |
a: [1, 2 => 1:4: ends mid-document
a: *nope => 1:4: no anchor named `nope`
a: 1, a: 2 => 2:1: the key `a` is written twice| PyYAML 6 | ruamel.yaml | libyaml (C) | moonyaml | |
|---|---|---|---|---|
| yes, on | boolean | boolean (1.1 mode) | boolean | string in moonyaml, boolean in yaml11 |
| 014 | 12 | 12 | 12 | 14 in moonyaml (§10.2 makes it decimal), 12 in yaml11 |
| 0o14 | string | string | string | 12 in moonyaml, string in yaml11 |
| Duplicate keys | last wins, silently | warning, then last wins | last wins | last wins, or First/Reject — a choice |
| Unknown tag | ConstructorError | ConstructorError | accepted, tag ignored | accepted, resolved untagged (§10.4); parse keeps it |
| Alias expansion | unbounded | unbounded | unbounded | capped at 10 000 000 nodes |
| A collection as a key | tuple key | tuple key | accepted | refused by loads, kept by parse |
| Comments, style | dropped | kept | dropped | dropped by loads, kept by parse |
| Repeats on write | anchor + alias | anchor + alias | — | anchor + alias, or anchors: false |
| --- on write | between documents | between documents | — | before every document |
| Tabs in indentation | read as separation | read as separation | read as separation | read as separation |
moon test --target all # 61 tests, four backendsmoon run src/examples/tour # everything it reads, in one file
moon run src/examples/versions # one document, read five ways
moon run src/examples/document # the document model, and a round trippub(all) struct Flavor {
depth : Int
duplicates : Duplicates
aliases : Bool
budget : Int
} derive(Eq, Debug)pub(all) struct Node {
kind : Kind
text : String
style : ScalarStyle
flow : Bool
anchor : String?
tag : String?
before : Array[String]
after : String?
}let budget : Intfn declared_version(src : StringView) -> (Int, Int)?let depth : Intlet indent : Intlet config : Config = @moonyaml.loads_as(src)let width : Int