A MoonBit implementation of the Amazon Ion data format and Ion Schema.
Dependencies
Status: early. The core data model, the Ion text and Ion binary encodings, Ion Hash (Ion Hash 1.0 over SHA-256), Ion Schema 1.0 and 2.0 validation, and JSON interoperability are implemented and tested, with asynchronous streaming readers and writers for both encodings over moonbitlang/async.
moon add moonrockz/ion| Package | Source | Import path | Purpose |
|---|---|---|---|
| @ion (core) | pkgs/ion | moonrockz/ion/ion | Core data model: Ion types, values, annotations, decimals, timestamps, symbol tokens |
| @text | pkgs/text | moonrockz/ion/text | Ion text reader and writer |
| @text/stream | pkgs/text/stream | moonrockz/ion/text/stream | Ion text readers and writers over asynchronous IO (moonbitlang/async) |
| @hash | pkgs/hash | moonrockz/ion/hash | Ion Hash 1.0: an encoding-independent hash of an Ion value |
| @binary | pkgs/binary | moonrockz/ion/binary | Ion binary codec: values, containers, annotations, and local symbol tables |
| @binary/stream | pkgs/binary/stream | moonrockz/ion/binary/stream | The Ion binary codec over asynchronous IO (moonbitlang/async) |
| @schema | pkgs/schema | moonrockz/ion/schema | Ion Schema model, loader, and validator |
| @json | pkgs/json | moonrockz/ion/json | JSON interoperability: IonValue ⇄ core Json |
| @cli | pkgs/cli | moonrockz/ion/cli | The command line's commands, runnable with any streams |
| ion CLI | pkgs | moonrockz/ion | ion print, ion json, ion fromjson, ion hash, ion validate — the module root package is the executable |
let value = @text.read_ion("{ name: \"ion\", tags: [a, b] }")
println(@text.write_ion(value)) // {name: "ion", tags: [a, b]}let values = @text.read_ion_datagram("{ name: \"ion\" } 42")
let bytes = @binary.write_binary(values) // Ion binary, with a local symbol table
let decoded = @binary.read_binary(bytes) // back to the same valueslet value = @text.read_ion("{ name: \"ion\", tags: [a, b] }")
let json = @json.to_json(value) // {"name":"ion","tags":["a","b"]}
let ion = @json.to_ion(json) // back to the Ion data modellet value = @ion.IonValue::from_fields([
@ion.Field::new("name", @ion.IonValue::string("ion")),
@ion.Field::new("tags", @ion.IonValue::list([
@ion.IonValue::symbol("a"),
@ion.IonValue::symbol("b"),
])),
])let schema = @schema.Schema::load_from_text(
"type::{ name: person, fields: { name: { type: string, occurs: required } } }",
)
let value = @text.read_ion("{ name: \"Ada\" }")
if schema.is_valid("person", value) {
println("valid")
}printf '%s\n' '{name: "Ada"}' | moonx moonrockz/ion print
moonx moonrockz/ion print data.ion
moonx moonrockz/ion print --binary data.ion > data.10n
moonx moonrockz/ion hash data.ion
moonx moonrockz/ion validate schema.isl person data.ionprintf '%s\n' '{name: "Ada"}' | ion print
ion print data.ion
ion validate schema.isl person data.ion'{name: "Ada"}' | moonx moonrockz/ion print
moonx moonrockz/ion print data.ion
cmd /c "moonx moonrockz/ion print --binary data.ion > data.10n"
moonx moonrockz/ion hash data.ion
moonx moonrockz/ion validate schema.isl person data.ion'{name: "Ada"}' | ion print
ion print data.ion
ion validate schema.isl person data.ion| API | Entry points | Description |
|---|---|---|
| CST | @text.tokenize, @text.parse_cst | A lossless token stream, and a syntax tree that keeps tokens and source spans |
| DOM (AST) | @text.read_ion, @text.read_ion_datagram | Build the IonValue tree for random access |
| Visitor | @ion.IonVisitor + IonValue::accept | Depth-first traversal; override only what you need |
| Fold | @ion.IonFold + IonValue::fold | Thread an accumulator with Continue / SkipChildren / Stop |
| SAX | @text.IonReader (pull) and @text.IonHandler + @text.parse_with_handler (push) | A flat IonEvent stream without building the DOM |
| Binary | @binary.read_binary, @binary.write_binary, @binary/stream | The Ion binary codec, with local symbol tables and an async streaming reader and writer |
| Streaming text | @text/stream.TextReader (values), @text/stream.TextEventReader (events), @text/stream.TextWriter | Ion text over async byte sources and sinks, one top-level value at a time |
let value = @text.read_ion("{a: 1}") // DOM / AST
value.accept(visitor) // visitor
let total = value.fold(0, @ion.IonFold::default()) // fold
let tokens = @text.tokenize("int32::12") // CST tokens
@text.parse_with_handler("1 2 3", handler) // SAX (push)let reader = @stream.TextReader::new(source) // moonrockz/ion/text/stream; any &@io.Reader
while reader.next() is Some(value) {
println(@text.write_ion(value))
}
let writer = @stream.TextWriter::new(sink) // any &@io.Writer
writer.write(value) // one value per line
@stream.write_all(sink, values, pretty=true)let value = @text.read_ion("{ name: \"ion\", tags: [a, b] }")
let digest = @hash.ion_hash_hex(value) // lowercase SHA-256
let bytes = @hash.ion_hash(value) // 32 raw byteslet value = @text.read_ion("{ data: annot::{time: 1969-07-20T20:18Z}, n: 1.50 }")
let json = @json.to_json(value) // {"data":{"time":"1969-07-20T20:18Z"},"n":1.50}
let ion = @json.to_ion(json) // back into the Ion data modellet value = @json.read_json("{\"a\": [1, 2]}") // {a: [1, 2]}
let text = @json.write_json(value) // {"a":[1,2]}mise run setup # fetch the test-data submodules and install dependencies
mise run hooks:install # install the git hooks (lefthook)
mise run test:check # moon check
mise run test:unit # moon test (unit, doc, snapshot, conformance, QuickCheck)
mise run test:all # check + test
mise run test:coverage # instrumented wasm tests, HTML and machine-readable coverage
mise run build:native
mise run bench # native release benchmarks and CLI peak RSS
moon fmt # format
moon info # regenerate package interfaces (*.mbti)
moon test --update # refresh the golden fixtures' recorded outpution print [--binary | --pretty] [file] Ion text or binary in; Ion text, pretty text, or binary out
ion json [file] Ion text or binary in, JSON out
ion fromjson [file] JSON in, Ion text out
ion hash [file] Ion Hash (SHA-256) of each value
ion validate <schema-file> <type-name> [file] validate each value
ion version also `ion --version` or `ion -V`
ion help [command] also `ion --help` or `ion <command> --help`'{name: "Ada"}' | ion print
'{"a": [1, 2.5]}' | ion fromjson
cmd /c "ion print --binary people.ion > people.10n"
ion print people.10n$ cat people.ion
{ name: "Ada", born: 1815 } { name: 42 }
$ ion print people.ion
{name: "Ada", born: 1815}
{name: 42}
$ printf '%s\n' '{name: "Ada"}' | ion print
{name: "Ada"}
$ ion print --binary people.ion > people.10n
$ ion print people.10n
{name: "Ada", born: 1815}
{name: 42}
$ ion json people.ion
{"name":"Ada","born":1815}
{"name":42}
$ echo '{"a": [1, 2.5]}' | ion fromjson
{a: [1, 25d-1]}
$ ion hash people.ion
5d2dbea37f03297ad83be8aa10f162c10e0c1e90fd950ce7b4972093774cdf2a
be93d3daaf4fe159a03cfe8e4b0c02394de41c4b2a690257f4d194e0ba1fc21e
$ cat person.isl
$ion_schema_2_0
type::{ name: person, type: struct, fields: { name: { type: string, occurs: required }, born: int } }
$ ion validate person.isl person people.ion
value 1: $.name: expected one of [string] but found int
1 of 2 value(s) failed validation
$ echo $?
1Install
Download zipA MoonBit implementation of the Amazon Ion data format and Ion Schema.
Dependencies