SharpYaml Documentation

repository·main·Indexed 19 days ago

https://github.com/xoofx/sharpyaml

A high-performance, NativeAOT-ready YAML parser, emitter, and object serializer for .NET. It features a System.Text.Json-style API via YamlSerializer and supports source generation using YamlSerializerContext to minimize reflection. The library provides a two-layer architecture: a high-level object mapping layer for standard serialization and a low-level infrastructure layer for lossless parsing, syntax trees, and tooling development.

Tokens
23.4K
Snippets
72
Records
121
Agent score
60%

What's inside SharpYaml

  1. Serialize and deserialize YAML with YamlSerializer

    main

    Use YamlSerializer to map YAML documents to .NET objects. The API is designed to be familiar to developers who have used System.Text.Json.JsonSerializer.

    // Use YamlSerializer to map YAML documents to .NET objects
    // Similar to System.Text.Json.JsonSerializer
  2. Use SharpYaml with NativeAOT and trimming

    main
    SharpYaml is NativeAOT ready. To support NativeAOT and trimming, you should disable reflection fallback and instead use generated metadata. This is achieved by using YamlSerializerContext and YamlTypeInfo<T> via source generation.
  3. Use the low-level event model for YAML processing

    main

    SharpYaml provides a low-level event model that allows you to process YAML as a stream of parsing events. This is useful when you need to inspect or manipulate YAML content without the overhead of building a full Document Object Model (DOM) or mapping the YAML structure to specific .NET objects.

    The parser produces a stream of events including, but not limited to:

    • Stream start/end
    • Document start/end
    • Mappings
    • Sequences
    • Scalars

    These events can be produced by the parser and subsequently consumed by the emitter.

  4. Understand YAML data types in SharpYaml

    main

    SharpYaml supports the standard YAML data structures used for configuration. Most data models will consist of one or more of the following:

    • Scalars: Basic values including strings, numbers, booleans, and null.
    • Mappings: Key/value pairs, equivalent to JSON objects.
    • Sequences: Ordered lists, equivalent to JSON arrays.
    • Documents: A single YAML stream can contain multiple documents separated by the --- delimiter.
  5. Understand YAML schema flavors in SharpYaml

    main

    SharpYaml provides several schema flavors to control how plain scalars (such as booleans, integers, and nulls) are interpreted and how tags are resolved during parsing and deserialization.

    Depending on your requirements for YAML 1.2 compliance or specific data formats, you can choose from the following schema flavors:

    • Failsafe: A standard schema for general purpose use.
    • JSON: A schema optimized for JSON compatibility.
    • Core: A schema providing core YAML types.
    • Extended: A schema providing extended YAML types.

    Schemas are the primary mechanism for controlling scalar resolution and tag handling during the parsing process.

  6. Perform low-level YAML processing with Scanner, Parser, and Emitter

    main

    For fine-grained control over YAML processing, SharpYaml provides low-level types that operate on tokens and events rather than high-level objects:

    • Scanner: Handles the initial lexical analysis of the YAML stream.
    • Parser: Converts scanned tokens into a stream of YAML events.
    • Emitter: Converts YAML events back into a formatted YAML stream.
  7. Use YAML merge keys (<<)

    main

    SharpYaml supports the YAML merge key (<<) when deserializing into .NET objects or Dictionary<string, TValue>.

    Important: Merge key support is only enabled when using the following schemas:

    • YamlSchemaKind.Core
    • YamlSchemaKind.Extended

    Merge keys are ignored if you use YamlSchemaKind.Json or YamlSchemaKind.Failsafe.

  8. Register custom converters in SharpYaml

    main

    SharpYaml allows you to define custom serialization and deserialization logic for specific CLR types using converters. You can register these converters at three different levels of granularity, which determine their scope and priority:

    1. Member-level attribute (Highest Priority): Apply [YamlConverter(typeof(YourConverter))] directly to a specific property or field. This overrides all other settings for that specific member.
    2. Options-level (High Priority): Add converters to the Converters list in YamlSerializerOptions. This applies the converter globally to all instances of the supported type.
    3. Type-level attribute (Medium Priority): Apply [YamlConverter(typeof(YourConverter))] to the class or struct definition. This applies to all instances of that type throughout the serialization process.

    If no custom converter is matched, SharpYaml falls back to built-in converters, then to .NET 7+ IParsable<T> implementations, and finally to the default reflection-based object converter.

    // 1. Member-level
    public class Config {
        [YamlConverter(typeof(HexIntConverter))]
        public int Color { get; set; }
    }
    
    // 2. Options-level
    var options = new YamlSerializerOptions {
        Converters = [ new IPAddressConverter() ]
    };
    
    // 3. Type-level
    [YamlConverter(typeof(TemperatureConverter))]
    public struct Temperature { ... }
  9. Use JSON attributes for YAML serialization

    main

    SharpYaml 3 supports System.Text.Json attributes out of the box. This allows you to reuse existing models without adding YAML-specific dependencies. The mapping follows these rules:

    JSON AttributeYAML Behavior
    [JsonPropertyName]Same as [YamlPropertyName]
    [JsonIgnore]Same as [YamlIgnore]
    [JsonInclude]Same as [YamlInclude]
    [JsonPropertyOrder]Maps to YAML property order
    [JsonConstructor]Selects constructor for deserialization
    [JsonDerivedType] / [JsonPolymorphic]Maps to YAML polymorphism model
    [JsonExtensionData]Maps to extra mapping members

    Precedence Order:

    1. YAML-specific attributes
    2. JSON attributes
    3. Options policies (e.g., PropertyNamingPolicy)
  10. Use the SharpYaml syntax layer for lossless YAML processing

    main

    The syntax layer provides APIs for working with a lossless YAML syntax tree. Unlike the object serializer, which focuses on mapping YAML to C# objects, the syntax layer preserves the exact structure and formatting of the original document.

    Use the syntax layer when you need to:

    • Access exact source spans (line and column numbers) for diagnostics, error reporting, or building editor tooling.
    • Perform roundtripping (parsing and then re-emitting) without losing structural or formatting details of the original YAML file.
  11. How to choose between Syntax and Model APIs

    main

    SharpYaml provides two different ways to interact with YAML data depending on your requirements:

    1. Syntax APIs (e.g., YamlSyntaxTree): Use these when you need a lossless representation that preserves 'trivia' (comments, whitespace) and exact character spans. This is ideal for tools like formatters or linters.
    2. Model APIs (e.g., YamlStream): Use these when you need a structured node representation for dynamic manipulation, such as reading, modifying, or programmatically constructing YAML data.
  12. Handle unknown discriminators

    main

    By default, an unrecognized discriminator value causes deserialization to throw an error. You can change this behavior using YamlPolymorphicAttribute.UnknownDerivedTypeHandling.

    Options include:

    • YamlUnknownDerivedTypeHandling.FallBackToBase: Fall back to the base type instead of throwing.
    // Per-type: fall back to the base type on unknown discriminators
    [YamlPolymorphic(UnknownDerivedTypeHandling = YamlUnknownDerivedTypeHandling.FallBackToBase)]
    [YamlDerivedType(typeof(Circle), "circle")]
    public class Shape { }