Sign in

    yaml

    A simple YAML parsing and stringifying library for MoonBit, support a simplified YAML subset which can be convert to JSON.

    Download zip
    Version
    0.0.8
    License
    MIT
    Last updated
    2 days ago
    Downloads
    91K

    #YAML

    A simple YAML parsing and stringifying library for MoonBit, support a simplified YAML subset which can be convert to JSON.

    This library is ported from yaml-rust2.

    #Usage

    #Basic Example

    ///|
    test {
    let source =
    #|%YAML 1.2
    #|---
    #|YAML: YAML Ain't Markup Language™
    #|
    #|What It Is:
    #| YAML is a human-friendly data serialization
    #| language for all programming languages.
    #|
    #|YAML Resources:
    #| YAML Specifications:
    #| - YAML 1.2:
    #| - Revision 1.2.2 # Oct 1, 2021 *New*
    #| - Revision 1.2.1 # Oct 1, 2009
    #| - Revision 1.2.0 # Jul 21, 2009
    #| - YAML 1.1
    #| - YAML 1.0
    json_inspect(@yaml.Yaml::load_from_string(source), content=[
    {
    "YAML": "YAML Ain't Markup Language™",
    "What It Is": "YAML is a human-friendly data serialization language for all programming languages.",
    "YAML Resources": {
    "YAML Specifications": [
    { "YAML 1.2": ["Revision 1.2.2", "Revision 1.2.1", "Revision 1.2.0"] },
    "YAML 1.1",
    "YAML 1.0",
    ],
    },
    },
    ])
    }

    #js-yaml compatibility: under-indented quoted scalars

    By default the parser follows YAML 1.2, which requires the continuation lines of a multi-line quoted scalar in a block collection to be indented (s-flow-line-prefix(n) in nb-double-multi-line(n) and nb-single-multi-line(n); yaml-test-suite case QB6E is an error). js-yaml, used by mermaid and many other tools, does not check that indentation. The opt-in lenient_quoted_scalar_indentation setting accepts such documents as js-yaml does: the continuation lines of single- and double-quoted scalars, including the line of the closing quote, may be indented less than the enclosing block, down to column 0, also inside a flow collection nested in a block collection. Leading white space of those lines is still not content, and line folding and escapes are unchanged. A document marker (---, ...) at the start of a line inside the scalar and an unterminated scalar remain errors, and plain and block scalars are not affected.

    ///|
    test {
    let source =
    #|config:
    #| themeCSS: "a
    #| b"
    // strict YAML 1.2
    let strict = try @yaml.Yaml::load_from_string(source) catch {
    YamlError(info~, ..) => info
    } noraise {
    _ => "loaded"
    }
    inspect(strict, content="invalid indentation in quoted scalar")
    // js-yaml compatible
    json_inspect(
    @yaml.Yaml::load_from_string(source, lenient_quoted_scalar_indentation=true),
    content=[{ "config": { "themeCSS": "a b" } }],
    )
    // or on a `Parser`, for event-level use
    let parser = @yaml.Parser(source, lenient_quoted_scalar_indentation=true)
    json_inspect(@yaml.Yaml::load_from_parser(parser), content=[
    { "config": { "themeCSS": "a b" } },
    ])
    }

    #YAML

    A simple YAML parsing and stringifying library for MoonBit, support a simplified YAML subset which can be convert to JSON.

    This library is ported from yaml-rust2.

    #Usage

    #Basic Example

    ///|
    test {
    let source =
    #|%YAML 1.2
    #|---
    #|YAML: YAML Ain't Markup Language™
    #|
    #|What It Is:
    #| YAML is a human-friendly data serialization
    #| language for all programming languages.
    #|
    #|YAML Resources:
    #| YAML Specifications:
    #| - YAML 1.2:
    #| - Revision 1.2.2 # Oct 1, 2021 *New*
    #| - Revision 1.2.1 # Oct 1, 2009
    #| - Revision 1.2.0 # Jul 21, 2009
    #| - YAML 1.1
    #| - YAML 1.0
    json_inspect(@yaml.Yaml::load_from_string(source), content=[
    {
    "YAML": "YAML Ain't Markup Language™",
    "What It Is": "YAML is a human-friendly data serialization language for all programming languages.",
    "YAML Resources": {
    "YAML Specifications": [
    { "YAML 1.2": ["Revision 1.2.2", "Revision 1.2.1", "Revision 1.2.0"] },
    "YAML 1.1",
    "YAML 1.0",
    ],
    },
    },
    ])
    }

    #js-yaml compatibility: under-indented quoted scalars

    By default the parser follows YAML 1.2, which requires the continuation lines of a multi-line quoted scalar in a block collection to be indented (s-flow-line-prefix(n) in nb-double-multi-line(n) and nb-single-multi-line(n); yaml-test-suite case QB6E is an error). js-yaml, used by mermaid and many other tools, does not check that indentation. The opt-in lenient_quoted_scalar_indentation setting accepts such documents as js-yaml does: the continuation lines of single- and double-quoted scalars, including the line of the closing quote, may be indented less than the enclosing block, down to column 0, also inside a flow collection nested in a block collection. Leading white space of those lines is still not content, and line folding and escapes are unchanged. A document marker (---, ...) at the start of a line inside the scalar and an unterminated scalar remain errors, and plain and block scalars are not affected.

    ///|
    test {
    let source =
    #|config:
    #| themeCSS: "a
    #| b"
    // strict YAML 1.2
    let strict = try @yaml.Yaml::load_from_string(source) catch {
    YamlError(info~, ..) => info
    } noraise {
    _ => "loaded"
    }
    inspect(strict, content="invalid indentation in quoted scalar")
    // js-yaml compatible
    json_inspect(
    @yaml.Yaml::load_from_string(source, lenient_quoted_scalar_indentation=true),
    content=[{ "config": { "themeCSS": "a b" } }],
    )
    // or on a `Parser`, for event-level use
    let parser = @yaml.Parser(source, lenient_quoted_scalar_indentation=true)
    json_inspect(@yaml.Yaml::load_from_parser(parser), content=[
    { "config": { "themeCSS": "a b" } },
    ])
    }

    EventReceiver

    pub(open) trait EventReceiver {
    fn on_event(Self, event : Event) -> Unit
    }

    Trait to be implemented in order to use the low-level parsing API.

    The low-level parsing API is event-based (a push parser), calling EventReceiver::on_event for each YAML Event that occurs. The EventReceiver trait only receives events. In order to receive both events and their location in the source, use MarkedEventReceiver. Parser::load takes a MarkedEventReceiver; MoonBit has no blanket implementations, so to use an EventReceiver there, wrap it in a type whose MarkedEventReceiver::on_event forwards the event and ignores the marker.

    Event hierarchy

    The event stream starts with an Event::StreamStart event followed by an Event::DocumentStart event. If the YAML document starts with a mapping (an object), an Event::MappingStart event is emitted. If it starts with a sequence (an array), an Event::SequenceStart event is emitted. Otherwise, an Event::Scalar event is emitted.

    In a mapping, key-values are sent as consecutive events. The first event after an Event::MappingStart will be the key, and following its value. If the mapping contains no sub-mapping or sub-sequence, then even events (starting from 0) will always be keys and odd ones will always be values. The mapping ends when an Event::MappingEnd event is received.

    In a sequence, values are sent consecutively until the Event::SequenceEnd event.

    If a value is a sub-mapping or a sub-sequence, an Event::MappingStart or Event::SequenceStart event will be sent respectively. Following events until the associated Event::MappingStart or Event::SequenceEnd (beware of nested mappings or sequences) will be part of the value and not another key-value pair or element in the sequence.

    For instance, the following yaml:
    a: b c: d: e f: - g - h
    will emit (indented and commented for lisibility):
    StreamStart, DocumentStart, MappingStart, Scalar("a", ..), Scalar("b", ..) Scalar("c", ..), MappingStart, Scalar("d", ..), Scalar("e", ..), MappingEnd, Scalar("f", ..), SequenceStart, Scalar("g", ..), Scalar("h", ..), SequenceEnd, MappingEnd, DocumentEnd, StreamEnd

    MarkedEventReceiver

    pub(open) trait MarkedEventReceiver {
    fn on_event(Self, event : Event, _mark : Marker) -> Unit
    }

    YamlError

    pub suberror YamlError {
    YamlError(mark~ : Marker, info~ : String)
    } derive(
    Debug
    )

    Event

    pub enum Event {
    StreamStart
    StreamEnd
    DocumentStart
    DocumentEnd
    Alias(id~ : Int)
    Scalar(value~ : String, style~ : TScalarStyle, id~ : Int, tag~ : Tag?)
    SequenceStart(id~ : Int, tag~ : Tag?)
    SequenceEnd
    MappingStart(id~ : Int, tag~ : Tag?)
    MappingEnd
    } derive(Eq,
    Debug
    )

    Event::equal

    fn Event::equal(Event, Event) -> Bool

    Event::not_equal

    fn Event::not_equal(x : Event, y : Event) -> Bool

    Event::to_repr

    Marker

    pub struct Marker {
    index : Int
    line : Int
    col : Int
    } derive(Eq,
    Debug
    )

    Marker::equal

    fn Marker::equal(Marker, Marker) -> Bool

    Marker::not_equal

    fn Marker::not_equal(x : Marker, y : Marker) -> Bool

    Marker::to_repr

    Parser

    type Parser

    Parser::Parser

    #alias(new, deprecated="`new` is deprecated, use `Parser` instead")
    fn Parser::Parser(str : StringView, lenient_quoted_scalar_indentation? : Bool) -> Parser

    Create a parser for str.

    lenient_quoted_scalar_indentation, an opt-in js-yaml compatibility setting, accepts multi-line single- and double-quoted scalars whose continuation lines are not indented enough, as js-yaml does.

    In block context, the continuation lines of a quoted (flow) scalar must be indented: nb-double-multi-line(n) and nb-single-multi-line(n) fold their lines with s-flow-line-prefix(n), which starts with s-indent(n), and the value of a block mapping is a node at indentation n+1. This is therefore an error, as in test QB6E of the yaml-test-suite:

    config: themeCSS: "a b"

    js-yaml (used by mermaid and many other tools) does not check the indentation of these lines and accepts such documents. With lenient_quoted_scalar_indentation=true, so does this parser: themeCSS above is "a b". Exactly one thing is relaxed: the indentation of the continuation lines of single- and double-quoted scalars, including the line holding the closing quote, may be anything, down to column 0. The leading white space of such a line (spaces, and also tabs, since there is no indentation left for them to break) is still not content, and line folding, escapes and the stripping of white space around line breaks are unchanged. The scalar may be the value of a block collection entry or sit inside a flow collection nested in one (js-yaml accepts both); the indentation of the tokens following the closing quote on its last line is not checked either, as it is the indentation of that line. Everything else keeps the YAML 1.2 rules:
    • a document marker (--- or ... followed by a blank) at the start of a line inside a quoted scalar is still an error, as is the end of input before the closing quote (js-yaml rejects both too);
    • plain and block (|, >) scalars must be indented as before (js-yaml rejects under-indented plain scalars too);
    • a flow collection line that starts with a new entry or with a closing bracket must be indented as before.

    Folding follows YAML in both modes, also where js-yaml differs: js-yaml keeps the white space before a line break of a quoted scalar ("a \n b" is "a b" there, "a b" here), and drops the empty lines following an escaped line break (a \ at the end of a line followed by an empty line is "" there, a line feed here, as l-empty in s-double-escaped(n)).

    The default is false: strict YAML 1.2. The setting is fixed for the life of the parser, since it changes how the input is scanned.

    Parser::keep_tags

    fn Parser::keep_tags(self : Parser, value : Bool) -> Unit

    Whether to keep tags across multiple documents when parsing.

    This behavior is non-standard as per the YAML specification but can be encountered in the wild. This boolean allows enabling this non-standard extension. This would result in the parser accepting input from test QLJ7 of the yaml-test-suite:

    %TAG !prefix! tag:example.com,2011: --- !prefix!A a: b --- !prefix!B c: d --- !prefix!C e: f

    With keep_tags set to false, the above YAML is rejected. As per the specification, tags only apply to the document immediately following them. This would error on !prefix!B.

    With keep_tags set to true, the above YAML is accepted by the parser.

    Parser::load

    fn[R : MarkedEventReceiver] Parser::load(self : Parser, recv : R, multi : Bool) -> Unit raise YamlError

    Load the YAML from the stream in self, pushing events into recv.

    The contents of the stream are parsed and the corresponding events are sent into the recveiver. For detailed explanations about how events work, see EventReceiver.

    If multi is set to true, the parser will allow parsing of multiple YAML documents inside the stream.

    The receiver must implement MarkedEventReceiver. An EventReceiver can be used by wrapping it in a type that implements MarkedEventReceiver and forwards each event, ignoring its marker.

    Errors

    Returns YamlError when loading fails.

    TScalarStyle

    pub enum TScalarStyle {
    Plain
    SingleQuoted
    DoubleQuoted
    Literal
    Folded
    } derive(Eq,
    Debug
    )

    TScalarStyle::equal

    TScalarStyle::not_equal

    fn TScalarStyle::not_equal(x : TScalarStyle, y : TScalarStyle) -> Bool

    Tag

    pub struct Tag {
    handle : String
    suffix : String
    } derive(Eq,
    Debug
    )

    Tag::equal

    fn Tag::equal(Tag, Tag) -> Bool

    Tag::not_equal

    fn Tag::not_equal(x : Tag, y : Tag) -> Bool

    Tag::to_repr

    Yaml

    pub(all) enum Yaml {
    Real(Double, repr~ : String)
    Integer(Int64)
    String(String)
    Boolean(Bool)
    Array(Array[Yaml])
    Map(Map[String, Yaml])
    Null
    BadValue
    } derive(Eq,
    Debug
    )

    YAML data structure representation
    impl ToJson for Yaml

    Yaml::dump

    fn Yaml::dump(self : Yaml) -> String

    Convenience helper to dump a Yaml value into a string using default settings.

    Yaml::equal

    fn Yaml::equal(Yaml, Yaml) -> Bool

    Yaml::load_from_parser

    fn Yaml::load_from_parser(parser : Parser) -> Array[Yaml] raise YamlError

    Yaml::load_from_string

    fn Yaml::load_from_string(source : StringView, lenient_quoted_scalar_indentation? : Bool) -> Array[Yaml] raise YamlError

    Load all the documents of source.

    lenient_quoted_scalar_indentation accepts quoted scalars whose continuation lines are not indented enough, as js-yaml does; see Parser::Parser. The default is strict YAML 1.2.

    Yaml::not_equal

    fn Yaml::not_equal(x : Yaml, y : Yaml) -> Bool

    Yaml::to_json

    fn Yaml::to_json(self : Yaml) -> Json

    Yaml::to_repr

    YamlEmitter

    type YamlEmitter

    The YAML serializer.

    This is a simplified emitter that matches the parser features supported by this package.

    Example

    let input = "a: b\nc: d"
    let docs = Yaml::load_from_string(input)
    let emitter = YamlEmitter::new()
    emitter.dump(docs[0])
    let output = emitter.to_string()
    // output == "---\na: b\nc: d"

    YamlEmitter::compact

    fn YamlEmitter::compact(self : YamlEmitter, compact : Bool) -> Unit

    Set "compact inline notation" on or off for block sequences and mappings.

    In this form, blocks cannot have any properties (such as anchors or tags), which should be OK, because this emitter doesn't emit those anyways.

    YamlEmitter::dump

    fn YamlEmitter::dump(self : YamlEmitter, doc : Yaml) -> Unit

    Dump a YAML document into the internal buffer.

    YamlEmitter::multiline_strings

    fn YamlEmitter::multiline_strings(self : YamlEmitter, multiline_strings : Bool) -> Unit

    Render strings containing multiple lines in literal block style.

    Example

    let input = "{foo: \"bar!\\nbar!\", baz: 42}"
    let parsed = Yaml::load_from_string(input)
    let emitter = YamlEmitter::new()
    emitter.multiline_strings(true)
    emitter.dump(parsed[0])
    let output = emitter.to_string()
    // output is:
    // ---
    // foo: |-
    // bar!
    // bar!
    // baz: 42

    YamlEmitter::new

    fn YamlEmitter::new(writer? : StringBuilder) -> YamlEmitter

    Create a new emitter serializing into writer.

    YamlEmitter::to_string

    fn YamlEmitter::to_string(self : YamlEmitter) -> String

    Get the current emitted output as a string.