### Install and Use Lunet Source: https://github.com/xoofx/tomlyn/blob/main/site/AGENTS.md Install Lunet as a .NET global tool. Then, use `lunet build` for a production build or `lunet serve` for a development server with live reload. ```sh # Prerequisite: install lunet as a .NET global tool (once) dotnet tool install -g lunet # From this directory (site/) lunet build # production build -> .lunet/build/www/ lunet serve # dev server with live reload at http://localhost:4000 ``` -------------------------------- ### Configure Naming Policies Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/getting-started.md Customize TOML key names using PropertyNamingPolicy for snake_case or camelCase. This example uses SnakeCaseLower. ```csharp using System.Text.Json; using Tomlyn; var options = new TomlSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower, }; var toml = TomlSerializer.Serialize(new ServerConfig { Host = "example.com", Port = 443 }, options); // host = "example.com" // port = 443 ``` -------------------------------- ### TOML Input with Integer Discriminator Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md Example TOML structure using an integer discriminator, which is represented as a string in the TOML file. ```toml type = "1" Color = "red" Radius = 5.0 ``` -------------------------------- ### Customizing Serialization Options Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md Provides an example of configuring TomlSerializerOptions to customize serialization behavior, such as property naming policy, object creation handling, and indentation. ```csharp using System.Text.Json; using Tomlyn; var options = new TomlSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower, PreferredObjectCreationHandling = JsonObjectCreationHandling.Replace, WriteIndented = true, IndentSize = 4, MaxDepth = 64, DefaultIgnoreCondition = TomlIgnoreCondition.WhenWritingNull, }; var toml = TomlSerializer.Serialize(config, options); ``` -------------------------------- ### JSON Polymorphic Attribute Equivalent Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md Demonstrates the equivalent setup using System.Text.Json's JsonPolymorphicAttribute and JsonDerivedTypeAttribute for compatibility. ```csharp using System.Text.Json.Serialization; [JsonPolymorphic] [JsonDerivedType(typeof(Cat), "cat")] [JsonDerivedType(typeof(Dog), "dog")] public abstract class Animal { /* ... */ } ``` -------------------------------- ### TOML Examples with Default Derived Type Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md Illustrates TOML serialization for a default derived type (Circle) and a named derived type (Square), showing the presence or absence of the discriminator key. ```toml # Serialized Circle (default) - no "type" key Color = "red" Radius = 5.0 # Serialized Square - "type" key is present type = "square" Color = "blue" Side = 3.0 ``` -------------------------------- ### Custom TOML Converter Implementation Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md Implement `TomlConverter` to customize how specific types are read from or written to TOML. This example converts strings to uppercase on read and lowercase on write. ```csharp using Tomlyn.Serialization; public sealed class UpperCaseStringConverter : TomlConverter { public override string? Read(TomlReader reader) => reader.GetString().ToUpperInvariant(); public override void Write(TomlWriter writer, string value) => writer.WriteStringValue(value.ToLowerInvariant()); } ``` -------------------------------- ### Add Tomlyn Package Source: https://github.com/xoofx/tomlyn/blob/main/site/readme.md Install the Tomlyn NuGet package using the .NET CLI. This package is available for .NET 8.0, .NET 10.0, and .NET Standard 2.0. ```shell dotnet add package Tomlyn ``` -------------------------------- ### TOML Input for Polymorphic Animals Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md Example TOML structure demonstrating the use of the '$type' discriminator to serialize different animal types. ```toml [[ animals ]] "$type" = "cat" Name = "Whiskers" Indoor = true [[ animals ]] "$type" = "dog" Name = "Rex" Breed = "Labrador" ``` -------------------------------- ### Implement Custom Syntax Visitor Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/low-level.md Shows how to implement a custom visitor by inheriting from SyntaxVisitor and overriding Visit methods. This is useful for collecting specific node types, like string values. ```csharp using Tomlyn.Syntax; public sealed class StringCollector : SyntaxVisitor { public List Strings { get; } = new(); protected override void Visit(StringValueSyntax node) { if (node.Value is not null) Strings.Add(node.Value); base.Visit(node); } } var collector = new StringCollector(); collector.Visit(doc); ``` -------------------------------- ### Traverse Tomlyn Syntax Tree Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/low-level.md Demonstrates using the visitor pattern and enumerable extensions to traverse the syntax tree. Use the visitor pattern for structured traversal or enumerable extensions for iterating over descendants or tokens. ```csharp using Tomlyn.Syntax; // Visitor pattern var visitor = new MyVisitor(); visitor.Visit(doc); // Enumerable extensions foreach (var node in doc.Descendants()) { if (node is StringValueSyntax str) Console.WriteLine(str.Value); } foreach (var token in doc.Tokens(includeCommentsAndWhitespaces: true)) { // Process every token } ``` -------------------------------- ### Source Generation with TomlSerializerContext Source: https://github.com/xoofx/tomlyn/blob/main/readme.md Demonstrates how to use source generation with TomlSerializerContext and the [TomlSerializable] attribute for NativeAOT and trimming compatibility. This approach generates serialization logic at compile time. ```csharp using System.Text.Json.Serialization; using Tomlyn.Serialization; public sealed class MyConfig { public string? Global { get; set; } } [TomlSourceGenerationOptions( PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, PreferredObjectCreationHandling = JsonObjectCreationHandling.Replace)] [TomlSerializable(typeof(MyConfig))] internal partial class MyTomlContext : TomlSerializerContext { } var config = TomlSerializer.Deserialize(toml, MyTomlContext.Default.MyConfig); var tomlOut = TomlSerializer.Serialize(config, MyTomlContext.Default.MyConfig); ``` -------------------------------- ### Using Source-Generated Context for Serialization Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md Demonstrates how to use a source-generated TomlSerializerContext for serialization and deserialization, which is recommended for NativeAOT and trimming. ```csharp using Tomlyn; using Tomlyn.Serialization; [TomlSerializable(typeof(MyConfig))] internal partial class MyTomlContext : TomlSerializerContext { } var context = MyTomlContext.Default; var toml = TomlSerializer.Serialize(config, context.MyConfig); var roundTrip = TomlSerializer.Deserialize(toml, context.MyConfig); ``` -------------------------------- ### Basic TOML Serialization and Deserialization Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md Demonstrates the basic usage of TomlSerializer for serializing a record to TOML and deserializing it back. ```csharp using Tomlyn; public sealed record Person(string Name, int Age); var toml = TomlSerializer.Serialize(new Person("Ada", 37)); var person = TomlSerializer.Deserialize(toml)!; ``` -------------------------------- ### Serialize and Deserialize TOML with Tomlyn Source: https://github.com/xoofx/tomlyn/blob/main/site/readme.md Demonstrates basic TOML serialization and deserialization using Tomlyn, mirroring the API style of System.Text.Json. Options like PropertyNamingPolicy can be configured. ```csharp using System.Text.Json; using Tomlyn; public sealed record Person(string Name, int Age); var options = new TomlSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; var toml = TomlSerializer.Serialize(new Person("Ada", 37), options); // name = "Ada" // age = 37 var person = TomlSerializer.Deserialize(toml, options); ``` -------------------------------- ### Registering Custom Converters via Options Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md Register custom converters at runtime by providing a list of converter instances to the `TomlSerializerOptions`. ```csharp var options = new TomlSerializerOptions { Converters = [new UpperCaseStringConverter()] }; ``` -------------------------------- ### Basic Serialization and Deserialization Source: https://github.com/xoofx/tomlyn/blob/main/readme.md Demonstrates the fundamental usage of TomlSerializer for converting C# objects to TOML strings and vice versa. ```csharp using Tomlyn; // Serialize var toml = TomlSerializer.Serialize(new { Name = "Ada", Age = 37 }); // Deserialize var person = TomlSerializer.Deserialize(toml); ``` -------------------------------- ### Configuring TomlSerializer Options Source: https://github.com/xoofx/tomlyn/blob/main/readme.md Illustrates how to customize serialization and deserialization behavior using TomlSerializerOptions. This includes property naming policies, object creation handling, indentation, and depth limits. ```csharp using System.Text.Json; using Tomlyn; var options = new TomlSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, PreferredObjectCreationHandling = JsonObjectCreationHandling.Replace, WriteIndented = true, IndentSize = 4, MaxDepth = 64, DefaultIgnoreCondition = TomlIgnoreCondition.WhenWritingNull, }; var toml = TomlSerializer.Serialize(config, options); var model = TomlSerializer.Deserialize(toml, options); ``` -------------------------------- ### Serialization with Type and Context Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md Shows how to serialize and deserialize using a specific type and a provided context when the type is not generic. ```csharp var toml = TomlSerializer.Serialize(value, typeof(MyConfig), context); var roundTrip = TomlSerializer.Deserialize(toml, typeof(MyConfig), context); ``` -------------------------------- ### Serialization to and from Streams/Writers Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md Shows how to serialize TOML to a TextWriter and deserialize from a file stream using TomlSerializer. ```csharp // From a file stream (UTF-8) using var stream = File.OpenRead("config.toml"); var config = TomlSerializer.Deserialize(stream); // To a TextWriter using var writer = new StreamWriter("output.toml"); TomlSerializer.Serialize(writer, config); ``` -------------------------------- ### Registering Custom Converters via Source Generation Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md Use `TomlSourceGenerationOptions` and `TomlSerializable` attributes to configure converters at compile time for improved performance. ```csharp [TomlSourceGenerationOptions(Converters = [typeof(UpperCaseStringConverter)])] [TomlSerializable(typeof(Config))] internal partial class MyTomlContext : TomlSerializerContext { } ``` -------------------------------- ### Configure TomlSerializerOptions Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/getting-started.md Set various serialization and deserialization options like naming policy, indentation, ignore conditions, and duplicate key handling. ```csharp using System.Text.Json; using Tomlyn; var options = new TomlSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = true, IndentSize = 2, DefaultIgnoreCondition = TomlIgnoreCondition.WhenWritingNull, DuplicateKeyHandling = TomlDuplicateKeyHandling.Error, }; var toml = TomlSerializer.Serialize(config, options); var roundTrip = TomlSerializer.Deserialize(toml, options); ``` -------------------------------- ### Serialize and Deserialize with TomlSerializer Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/migration.md Use the TomlSerializer for basic TOML serialization and deserialization, similar to System.Text.Json. ```csharp using Tomlyn; var toml = TomlSerializer.Serialize(value); var model = TomlSerializer.Deserialize(toml); ``` -------------------------------- ### Serialize with Custom Options Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/migration.md Apply custom serialization options, such as indentation, using TomlSerializerOptions. ```csharp var options = new TomlSerializerOptions { WriteIndented = true }; var toml = TomlSerializer.Serialize(value, options); ``` -------------------------------- ### Tomlyn Serializer Options Reference Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md This table details the available options for configuring the Tomlyn serializer, allowing for fine-grained control over TOML output and input processing. ```APIDOC ## Tomlyn Serializer Options This section details the configurable options for the Tomlyn serializer. ### Options | Option | Type | Default | Description | | --- | --- | --- | --- | | [`PropertyNamingPolicy`](xref:Tomlyn.TomlSerializerOptions.PropertyNamingPolicy) | [`JsonNamingPolicy?`](xref:System.Text.Json.JsonNamingPolicy) | `null` | Naming policy for CLR member names (e.g. `CamelCase`, `SnakeCaseLower`). | | [`DictionaryKeyPolicy`](xref:Tomlyn.TomlSerializerOptions.DictionaryKeyPolicy) | [`JsonNamingPolicy?`](xref:System.Text.Json.JsonNamingPolicy) | `null` | Naming policy for dictionary keys during serialization. | | [`PreferredObjectCreationHandling`](xref:Tomlyn.TomlSerializerOptions.PreferredObjectCreationHandling) | [`JsonObjectCreationHandling`](xref:System.Text.Json.Serialization.JsonObjectCreationHandling) | `Replace` | Controls whether nested object and collection members are replaced or populated during deserialization. | | [`PropertyNameCaseInsensitive`](xref:Tomlyn.TomlSerializerOptions.PropertyNameCaseInsensitive) | `bool` | `false` | Case-insensitive property matching when reading. | | [`MaxDepth`](xref:Tomlyn.TomlSerializerOptions.MaxDepth) | `int` | `0` (`64` effective) | Maximum nesting depth when reading or writing TOML containers. | | [`DefaultIgnoreCondition`](xref:Tomlyn.TomlSerializerOptions.DefaultIgnoreCondition) | [`TomlIgnoreCondition`](xref:Tomlyn.TomlIgnoreCondition) | `WhenWritingNull` | Skips null/default values when writing. | | [`WriteIndented`](xref:Tomlyn.TomlSerializerOptions.WriteIndented) | `bool` | `true` | Enables indentation for nested tables. | | [`IndentSize`](xref:Tomlyn.TomlSerializerOptions.IndentSize) | `int` | `2` | Spaces per indent level. | | [`NewLine`](xref:Tomlyn.TomlSerializerOptions.NewLine) | [`TomlNewLineKind`](xref:Tomlyn.TomlNewLineKind) | `Lf` | Line ending style (`Lf` or `CrLf`). | | [`MappingOrder`](xref:Tomlyn.TomlSerializerOptions.MappingOrder) | [`TomlMappingOrderPolicy`](xref:Tomlyn.TomlMappingOrderPolicy) | `Declaration` | Property ordering within tables. | | [`DuplicateKeyHandling`](xref:Tomlyn.TomlSerializerOptions.DuplicateKeyHandling) | [`TomlDuplicateKeyHandling`](xref:Tomlyn.TomlDuplicateKeyHandling) | `Error` | Behavior when duplicate keys are encountered. | | [`DottedKeyHandling`](xref:Tomlyn.TomlSerializerOptions.DottedKeyHandling) | [`TomlDottedKeyHandling`](xref:Tomlyn.TomlDottedKeyHandling) | `Literal` | How dotted keys are emitted (`Literal` or `Expand`). | | [`RootValueHandling`](xref:Tomlyn.TomlSerializerOptions.RootValueHandling) | [`TomlRootValueHandling`](xref:Tomlyn.TomlRootValueHandling) | `Error` | Behavior for root-level non-table values. | | [`RootValueKeyName`](xref:Tomlyn.TomlSerializerOptions.RootValueKeyName) | `string` | `"value"` | Key name used when `RootValueHandling` is `WrapInRootKey`. | | [`InlineTablePolicy`](xref:Tomlyn.TomlSerializerOptions.InlineTablePolicy) | [`TomlInlineTablePolicy`](xref:Tomlyn.TomlInlineTablePolicy) | `Never` | When to emit inline tables (`Never`, `WhenSmall`, `Always`). | | [`TableArrayStyle`](xref:Tomlyn.TomlSerializerOptions.TableArrayStyle) | [`TomlTableArrayStyle`](xref:Tomlyn.TomlTableArrayStyle) | `Headers` | Array-of-tables style (`Headers` = `[[a]]`, `InlineArrayOfTables` = `a = [{...}]`). | | [`StringStylePreferences`](xref:Tomlyn.TomlSerializerOptions.StringStylePreferences) | [`TomlStringStylePreferences`](xref:Tomlyn.TomlStringStylePreferences) | *(see below)* | Controls string emission style (basic, literal, multiline). | | [`PolymorphismOptions`](xref:Tomlyn.TomlSerializerOptions.PolymorphismOptions) | [`TomlPolymorphismOptions`](xref:Tomlyn.TomlPolymorphismOptions) | *(see below)* | Polymorphism discriminator settings. | | [`MetadataStore`](xref:Tomlyn.TomlSerializerOptions.MetadataStore) | [`ITomlMetadataStore?`](xref:Tomlyn.Serialization.ITomlMetadataStore) | `null` | Captures trivia (comments, source spans) during deserialization. | | [`SourceName`](xref:Tomlyn.TomlSerializerOptions.SourceName) | `string?` | `null` | File/path name included in [`TomlException`](xref:Tomlyn.TomlException) messages. | | [`TypeInfoResolver`](xref:Tomlyn.TomlSerializerOptions.TypeInfoResolver) | [`ITomlTypeInfoResolver?`](xref:Tomlyn.ITomlTypeInfoResolver) | `null` | Custom metadata resolver (advanced). | | [`Converters`](xref:Tomlyn.TomlSerializerOptions.Converters) | `IReadOnlyList` | empty | Custom converters for type mapping. | ### Naming Policy Defaults By default, [`PropertyNamingPolicy`](xref:Tomlyn.TomlSerializerOptions.PropertyNamingPolicy) is `null`, so CLR member names are used as-is. This matches [`System.Text.Json.JsonSerializer`](xref:System.Text.Json.JsonSerializer) default behavior. Common policies: - [`JsonNamingPolicy.CamelCase`](xref:System.Text.Json.JsonNamingPolicy.CamelCase) → `myProperty` - [`JsonNamingPolicy.SnakeCaseLower`](xref:System.Text.Json.JsonNamingPolicy.SnakeCaseLower) → `my_property` - [`JsonNamingPolicy.KebabCaseLower`](xref:System.Text.Json.JsonNamingPolicy.KebabCaseLower) → `my-property` ``` -------------------------------- ### Configure Polymorphism with Reflection Path Source: https://github.com/xoofx/tomlyn/blob/main/readme.md Use TomlPolymorphismOptions.DerivedTypeMappings to register derived types when the base type is in a different project. This configuration is for the reflection path. ```csharp using Tomlyn; var options = new TomlSerializerOptions { PolymorphismOptions = new TomlPolymorphismOptions { TypeDiscriminatorPropertyName = "kind", DerivedTypeMappings = new Dictionary> { [typeof(Animal)] = [ new(typeof(Cat), "cat"), new(typeof(Dog), "dog"), ], }, }, }; ``` -------------------------------- ### Source Generation for NativeAOT Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/getting-started.md Declare a TomlSerializerContext and use generated metadata for NativeAOT compatibility and trimming. ```csharp using Tomlyn; using Tomlyn.Serialization; [TomlSerializable(typeof(ServerConfig))] internal partial class MyTomlContext : TomlSerializerContext { } var toml = TomlSerializer.Serialize(config, MyTomlContext.Default.ServerConfig); var roundTrip = TomlSerializer.Deserialize(toml, MyTomlContext.Default.ServerConfig); ``` -------------------------------- ### Configure TOML Parser Options Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/low-level.md Set parser options to control behavior like error handling, scalar decoding, trivia capture, and string materialization. Serializer options like MaxDepth are also configured here. ```csharp var parserOptions = new TomlParserOptions { Mode = TomlParserMode.Tolerant, // collect errors instead of throwing DecodeScalars = true, // decode escape sequences CaptureTrivia = true, // include comments/whitespace in events EagerStringValues = false, // defer string materialization }; var serializerOptions = new TomlSerializerOptions { MaxDepth = 64, }; var parser = TomlParser.Create(toml, parserOptions, serializerOptions); ``` -------------------------------- ### Define Source Generation Context Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/migration.md Define a partial class inheriting from TomlSerializerContext and mark it with TomlSerializable for source generation. ```csharp using Tomlyn.Serialization; [TomlSerializable(typeof(MyType))] internal partial class MyTomlContext : TomlSerializerContext { } ``` -------------------------------- ### Build and Serialize a DOM Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/dom.md Construct a TomlTable object programmatically and then serialize it into a TOML string. This is useful for generating TOML configuration files dynamically. ```csharp using Tomlyn; using Tomlyn.Model; var table = new TomlTable { ["title"] = "My App", ["database"] = new TomlTable { ["host"] = "localhost", ["port"] = 5432L, ["enabled"] = true, ["ports"] = new TomlArray { 8000L, 8001L, 8002L }, } }; var toml = TomlSerializer.Serialize(table); ``` -------------------------------- ### Deserialize TOML with Metadata Store Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/dom.md Deserialize TOML content while capturing metadata like comments and source spans using a `TomlMetadataStore`. This allows for later retrieval of trivia and formatting information associated with specific TOML properties. ```csharp using Tomlyn; using Tomlyn.Model; using Tomlyn.Serialization; var toml = """ # Application title title = "My App" # Database settings [database] host = "localhost" # primary host """; var store = new TomlMetadataStore(); var options = new TomlSerializerOptions { MetadataStore = store }; var table = TomlSerializer.Deserialize(toml, options)!; // Retrieve metadata for a specific object if (store.TryGetProperties(table, out var metadata) && metadata is not null) { if (metadata.TryGetProperty("title", out var prop) && prop is not null) { // prop.LeadingTrivia - comments before the key ("# Application title") // prop.TrailingTrivia - comments after the value // prop.Span - source location (line, column, offset) // prop.DisplayKind - how the value was written in the source } } ``` -------------------------------- ### Configure Object Creation Handling Globally Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md Set the default object creation handling for all deserialization using TomlSerializerOptions. This applies globally unless overridden by type or member attributes. ```csharp var options = new TomlSerializerOptions { PreferredObjectCreationHandling = JsonObjectCreationHandling.Populate, }; ``` -------------------------------- ### Create Parser from TextReader Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/low-level.md Instantiate a TOML parser using a TextReader, commonly used when reading from a file stream. ```csharp // From a file stream using var reader = new StreamReader("config.toml"); var parser = TomlParser.Create(reader); ``` -------------------------------- ### Serialize and Deserialize TOML Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/getting-started.md Use TomlSerializer to convert .NET objects to TOML strings and vice versa. Ensure the ServerConfig class is defined. ```csharp using Tomlyn; public sealed class ServerConfig { public string Host { get; set; } = "localhost"; public int Port { get; set; } = 8080; public bool Ssl { get; set; } } // Serialize to TOML var config = new ServerConfig { Host = "example.com", Port = 443, Ssl = true }; var toml = TomlSerializer.Serialize(config); // Deserialize from TOML var roundTrip = TomlSerializer.Deserialize(toml)!; ``` ```toml Host = "example.com" Port = 443 Ssl = true ``` -------------------------------- ### TomlLexer (tokenization) Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/low-level.md The TomlLexer produces a flat stream of tokens, useful for syntax highlighting, quick validation, or building custom parsers. It offers minimal allocations by using struct-based iteration. ```APIDOC ## TomlLexer (tokenization) [`TomlLexer`](xref:Tomlyn.Parsing.TomlLexer) produces a flat stream of tokens. Use it for syntax highlighting, quick validation, or building custom parsers. ```csharp using Tomlyn.Parsing; var lexer = TomlLexer.Create("name = \"Ada\"", sourceName: "config.toml"); while (lexer.MoveNext()) { var token = lexer.Current; Console.WriteLine($"{token.Kind} = {token.StringValue} @ {lexer.CurrentSpan}"); } ``` ### Token kinds Tokens are identified by [`TokenKind`](xref:Tomlyn.Syntax.TokenKind): | Category | Kinds | | --- | --- | | Structure | `OpenBracket`, `CloseBracket`, `OpenBracketDouble`, `CloseBracketDouble`, `OpenBrace`, `CloseBrace`, `Equal`, `Comma`, `Dot` | | Strings | `String`, `StringMulti`, `StringLiteral`, `StringLiteralMulti` | | Numbers | `Integer`, `IntegerHexa`, `IntegerOctal`, `IntegerBinary`, `Float` | | Booleans | `True`, `False` | | Date/time | `OffsetDateTimeByZ`, `OffsetDateTimeByNumber`, `LocalDateTime`, `LocalDate`, `LocalTime` | | Special | `Infinite`, `PositiveInfinite`, `NegativeInfinite`, `Nan`, `PositiveNan`, `NegativeNan` | | Trivia | `Whitespaces`, `NewLine`, `Comment` | | Meta | `BasicKey`, `Invalid`, `Eof` | ### Lexer options [`TomlLexerOptions`](xref:Tomlyn.Parsing.TomlLexerOptions) controls decoding behavior: ```csharp var options = new TomlLexerOptions { DecodeScalars = true }; var lexer = TomlLexer.Create(toml, options, sourceName: "config.toml"); ``` When `DecodeScalars` is `true`, escape sequences in strings are decoded during tokenization. ``` -------------------------------- ### Configure String Style Preferences Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md Customize how strings are emitted during serialization using TomlStringStylePreferences. This allows control over default styles, literal preferences, and escape character usage. ```csharp var options = new TomlSerializerOptions { StringStylePreferences = new TomlStringStylePreferences { DefaultStyle = TomlStringStyle.Basic, // default PreferLiteralWhenNoEscapes = true, // default AllowHexEscapes = true, // default } }; ``` -------------------------------- ### Represent Inline Tables Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/dom.md Create inline tables by passing `inline: true` to the TomlTable constructor. This results in TOML output where tables are defined on a single line, like `point = { x = 1, y = 2 }`. ```csharp var table = new TomlTable { ["point"] = new TomlTable(inline: true) { ["x"] = 1L, ["y"] = 2L, } }; var toml = TomlSerializer.Serialize(table); ``` -------------------------------- ### Configure Polymorphism with Source Generation Path Source: https://github.com/xoofx/tomlyn/blob/main/readme.md Use TomlDerivedTypeMapping attributes to register derived types when the base type is in a different project. This configuration is for the source generation path. ```csharp using Tomlyn.Serialization; [TomlSerializable(typeof(Animal))] [TomlDerivedTypeMapping(typeof(Animal), typeof(Cat), "cat")] [TomlDerivedTypeMapping(typeof(Animal), typeof(Dog), "dog")] internal partial class MyTomlContext : TomlSerializerContext { } ``` -------------------------------- ### Configure Source Generation Options Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/source-generation.md Use [TomlSourceGenerationOptionsAttribute] to fix serialization options at build time, such as property naming policy, object creation handling, indentation, and ignore conditions. This ensures consistent serialization behavior. ```csharp using System.Text.Json; using System.Text.Json.Serialization; using Tomlyn; using Tomlyn.Serialization; [TomlSourceGenerationOptions( PropertyNamingPolicy = JsonKnownNamingPolicy.SnakeCaseLower, PreferredObjectCreationHandling = JsonObjectCreationHandling.Replace, WriteIndented = true, IndentSize = 2, MaxDepth = 64, DefaultIgnoreCondition = TomlIgnoreCondition.WhenWritingNull)] [TomlSerializable(typeof(ServerConfig))] internal partial class MyTomlContext : TomlSerializerContext { } ``` -------------------------------- ### Enable Reflection with NativeAOT Source: https://github.com/xoofx/tomlyn/blob/main/readme.md When publishing with NativeAOT, Tomlyn disables reflection-based serialization by default. Override this by setting the MSBuild property true. ```xml true ``` -------------------------------- ### Parse TOML with SyntaxParser Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/low-level.md Use SyntaxParser.Parse to create a full-fidelity syntax tree, preserving all characters including comments and whitespace. This is suitable for formatters and analyzers. The ToString() method on the document can reproduce the exact original text. ```csharp using Tomlyn.Parsing; var doc = SyntaxParser.Parse("# config\nname = \"Ada\"\nage = 37", sourceName: "config.toml"); if (doc.HasErrors) { foreach (var diag in doc.Diagnostics) Console.WriteLine(diag); } // Round-trip: ToString() reproduces the exact original text Console.WriteLine(doc.ToString()); ``` -------------------------------- ### Define a Tomlyn Serializer Context Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/source-generation.md Declare a partial class inheriting from TomlSerializerContext and annotate it with [TomlSerializable] for each root type. This sets up the context for source generation. ```csharp using Tomlyn.Serialization; public sealed class ServerConfig { public string Host { get; set; } = "localhost"; public int Port { get; set; } = 8080; } [TomlSerializable(typeof(ServerConfig))] internal partial class MyTomlContext : TomlSerializerContext { } ``` -------------------------------- ### Configure Object Creation Handling at Type Level Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md Use the JsonObjectCreationHandlingAttribute on a class to specify how objects of that type should be created during deserialization. This overrides global options. ```csharp [JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)] public sealed class ReleaserConfiguration { public List Channels { get; } = ["stable"]; } ``` -------------------------------- ### Registering Custom Converters via Attribute Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md Apply the `TomlConverter` attribute to a property to associate a specific converter with that property. This method relies on reflection. ```csharp using Tomlyn.Serialization; public sealed class Config { [TomlConverter(typeof(UpperCaseStringConverter))] public string Name { get; set; } = ""; } ``` -------------------------------- ### Use Generated TypeInfo for Serialization Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/source-generation.md Access the generated TomlTypeInfo property directly from the context's Default singleton for efficient serialization and deserialization. This is the recommended approach. ```csharp using Tomlyn; var context = MyTomlContext.Default; var toml = TomlSerializer.Serialize(config, context.ServerConfig); var roundTrip = TomlSerializer.Deserialize(toml, context.ServerConfig); ``` -------------------------------- ### Preserve Comments with Metadata Store Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/migration.md Utilize TomlMetadataStore with TomlSerializerOptions to preserve comments and trivia during deserialization and serialization. ```csharp using Tomlyn; using Tomlyn.Serialization; var store = new TomlMetadataStore(); var options = new TomlSerializerOptions { MetadataStore = store }; var model = TomlSerializer.Deserialize(toml, options)!; var tomlOut = TomlSerializer.Serialize(model, options); ``` -------------------------------- ### Tokenize TOML string with TomlLexer Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/low-level.md Use TomlLexer to produce a flat stream of tokens from a TOML string. This is useful for syntax highlighting, quick validation, or building custom parsers. The loop iterates through each token, printing its kind, string value, and span. ```csharp using Tomlyn.Parsing; var lexer = TomlLexer.Create("name = \"Ada\"", sourceName: "config.toml"); while (lexer.MoveNext()) { var token = lexer.Current; Console.WriteLine($"{token.Kind} = {token.StringValue} @ {lexer.CurrentSpan}"); } ``` -------------------------------- ### Define Multiple Tomlyn Contexts Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/source-generation.md Define multiple contexts for different parts of your application to manage serialization configurations independently. This allows for better organization and modularity. ```csharp [TomlSerializable(typeof(ServerConfig))] internal partial class ServerContext : TomlSerializerContext { } ``` ```csharp [TomlSerializable(typeof(DatabaseConfig))] internal partial class DatabaseContext : TomlSerializerContext { } ``` -------------------------------- ### Safe Deserialization with TryDeserialize Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md Use the TryDeserialize method for scenarios where invalid TOML input is expected, such as user-provided configuration. This avoids exception overhead for expected failures. ```csharp ```csharp if (!TomlSerializer.TryDeserialize(toml, out var config)) { // config is null/default - parsing or mapping failed } ``` ``` -------------------------------- ### Constructor-Based Deserialization with JsonConstructor Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md Use `JsonConstructor` to specify which constructor should be used for deserialization, particularly useful for immutable objects. ```csharp using System.Text.Json.Serialization; public sealed class Endpoint { [JsonConstructor] public Endpoint(string host, int port) { Host = host; Port = port; } public string Host { get; } public int Port { get; } } ``` -------------------------------- ### Converter Factory for Open Generic Types Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md Implement `TomlConverterFactory` to create converters for open generic types or types requiring runtime inspection. The `CanConvert` method determines if the factory can handle the type. ```csharp using Tomlyn.Serialization; public sealed class MyConverterFactory : TomlConverterFactory { public override bool CanConvert(Type typeToConvert) => typeToConvert.IsEnum; public override TomlConverter CreateConverter(Type typeToConvert, TomlSerializerOptions options) => /* return a concrete TomlConverter for the enum type */; } ``` -------------------------------- ### Parse TOML strictly Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/migration.md Use `SyntaxParser.ParseStrict` for strict parsing that throws an exception on the first error. Ensure you include the necessary using directive for `Tomlyn.Parsing`. ```csharp using Tomlyn.Parsing; var doc = SyntaxParser.ParseStrict(toml, sourceName: "config.toml"); ``` -------------------------------- ### Deserialize and Serialize Dynamic TOML Model Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/migration.md Use TomlSerializer to deserialize TOML into a dynamic TomlTable model and then serialize it back. ```csharp using Tomlyn; using Tomlyn.Model; var table = TomlSerializer.Deserialize(toml)!; var tomlOut = TomlSerializer.Serialize(table); ``` -------------------------------- ### Global Unknown Discriminator Handling Options Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md Set the default behavior for handling unknown derived types globally via TomlSerializerOptions. This is applied if no attribute-level setting is specified. ```csharp ```csharp var options = new TomlSerializerOptions { PolymorphismOptions = new TomlPolymorphismOptions { UnknownDerivedTypeHandling = TomlUnknownDerivedTypeHandling.FallBackToBaseType, }, }; ``` ``` -------------------------------- ### TomlParser (incremental parse events) Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/low-level.md The TomlParser produces a sequence of TomlParseEvent values without building an intermediate DOM, making it ideal for custom readers or streaming processors. ```APIDOC ## TomlParser (incremental parse events) [`TomlParser`](xref:Tomlyn.Parsing.TomlParser) produces a sequence of [`TomlParseEvent`](xref:Tomlyn.Parsing.TomlParseEvent) values via `MoveNext()` without building an intermediate DOM. This is ideal for building custom readers or streaming processors. ```csharp using Tomlyn.Parsing; var parser = TomlParser.Create("[server]\nhost = \"localhost\"\nport = 8080"); while (parser.MoveNext()) { ref readonly var evt = ref parser.Current; switch (evt.Kind) { case TomlParseEventKind.PropertyName: Console.Write($"{evt.GetString()} = "); break; case TomlParseEventKind.String: Console.WriteLine($"\"{evt.GetString() saraf}"); break; case TomlParseEventKind.Integer: Console.WriteLine(evt.GetInt64()); break; case TomlParseEventKind.StartTable: Console.WriteLine($"[table depth={parser.Depth}]"); break; } } ``` ### Parse events | Kind | Description | | --- | --- | | [`StartDocument`](xref:Tomlyn.Parsing.TomlParseEventKind.StartDocument) / [`EndDocument`](xref:Tomlyn.Parsing.TomlParseEventKind.EndDocument) | Document boundaries. | | [`StartTable`](xref:Tomlyn.Parsing.TomlParseEventKind.StartTable) / [`EndTable`](xref:Tomlyn.Parsing.TomlParseEventKind.EndTable) | Table boundaries (including inline tables). | | [`StartArray`](xref:Tomlyn.Parsing.TomlParseEventKind.StartArray) / [`EndArray`](xref:Tomlyn.Parsing.TomlParseEventKind.EndArray) | Array boundaries (including table arrays). | | [`PropertyName`](xref:Tomlyn.Parsing.TomlParseEventKind.PropertyName) | A TOML key - use `evt.GetString()` to read it. | | [`String`](xref:Tomlyn.Parsing.TomlParseEventKind.String) | A string value - use `evt.GetString()`. | | [`Integer`](xref:Tomlyn.Parsing.TomlParseEventKind.Integer) | An integer value - use `evt.GetInt64()`. | | [`Float`](xref:Tomlyn.Parsing.TomlParseEventKind.Float) | A float value - use `evt.GetDouble()`. | | [`Boolean`](xref:Tomlyn.Parsing.TomlParseEventKind.Boolean) | A boolean value - use `evt.GetBoolean()`. | | [`DateTime`](xref:Tomlyn.Parsing.TomlParseEventKind.DateTime) | A date/time value - use `evt.GetTomlDateTime()`. | ``` -------------------------------- ### Use TryDeserialize Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/getting-started.md Use the non-throwing TryDeserialize method for a boolean result indicating success or failure of deserialization. ```csharp if (!TomlSerializer.TryDeserialize(toml, out var value)) { // value is null/default when parsing fails } ``` -------------------------------- ### Serialize to Stream Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/getting-started.md Write TOML data directly to a file stream using the Stream overload of Serialize. ```csharp using System.IO; using Tomlyn; // Write to a file stream using var output = File.Create("config_out.toml"); TomlSerializer.Serialize(output, config); ``` -------------------------------- ### Deserializing and Serializing Untyped TOML Model Source: https://github.com/xoofx/tomlyn/blob/main/readme.md Shows how to deserialize TOML content into an untyped TomlTable model and then serialize it back. This is useful for inspecting or manipulating TOML data without predefined C# classes. ```csharp using Tomlyn; using Tomlyn.Model; var toml = @"global = ""this is a string"" # This is a comment of a table [my_table] key = 1 # Comment a key value = true list = [4, 5, 6] "; var model = TomlSerializer.Deserialize(toml)!; var global = (string)model["global"]!; Console.WriteLine(global); Console.WriteLine(TomlSerializer.Serialize(model)); ``` -------------------------------- ### Extension Data with TomlExtensionDataAttribute Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md Capture unmapped TOML keys during deserialization into a dictionary using `TomlExtensionDataAttribute`. This is useful for handling unknown or optional fields. ```csharp using Tomlyn.Serialization; public sealed class Config { public string Name { get; set; } = ""; [TomlExtensionData] public IDictionary? Extra { get; set; } } ``` -------------------------------- ### Access Tomlyn Diagnostics Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/low-level.md Illustrates how to iterate through diagnostic messages associated with a document. Each diagnostic contains its kind (Error/Warning), source location (Span), and a descriptive message. ```csharp foreach (var diag in doc.Diagnostics) { // diag.Kind - Error or Warning // diag.Span - source location // diag.Message - description Console.WriteLine($"{diag.Kind}: {diag.Message} at {diag.Span}"); } ``` -------------------------------- ### Property Naming with JsonPropertyName Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/serialization.md Use `JsonPropertyName` to map C# properties to different names in TOML, supporting case-insensitive or snake_case conventions. ```csharp using System.Text.Json.Serialization; public sealed class Person { [JsonPropertyName("first_name")] public string FirstName { get; set; } = ""; [JsonPropertyName("last_name")] public string LastName { get; set; } = ""; [JsonIgnore] public string FullName => $"{FirstName} {LastName}"; } ``` -------------------------------- ### Represent Date/Time Values Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/dom.md Use TomlDateTime to precisely represent TOML's various date and time formats, including offset date-time, local date-time, local date, and local time. Specify the kind of date-time using TomlDateTimeKind. ```csharp using Tomlyn; // Offset date-time var odt = new TomlDateTime(new DateTimeOffset(2023, 7, 15, 12, 0, 0, TimeSpan.FromHours(2)), 0, TomlDateTimeKind.OffsetDateTimeByNumber); // Local date-time (no timezone) var ldt = new TomlDateTime(new DateTime(2023, 7, 15, 12, 0, 0), 0, TomlDateTimeKind.LocalDateTime); // Local date var ld = new TomlDateTime(2023, 7, 15); // Local time var lt = new TomlDateTime(new DateTimeOffset(1, 1, 1, 12, 30, 0, TimeSpan.Zero), 0, TomlDateTimeKind.LocalTime); ``` -------------------------------- ### Parse TOML incrementally with TomlParser events Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/low-level.md Use TomlParser to process TOML content by iterating through a sequence of parse events. This approach avoids building an intermediate DOM and is suitable for custom readers or streaming processors. The switch statement handles different event kinds to extract values. ```csharp using Tomlyn.Parsing; var parser = TomlParser.Create("[server]\nhost = \"localhost\"\nport = 8080"); while (parser.MoveNext()) { ref readonly var evt = ref parser.Current; switch (evt.Kind) { case TomlParseEventKind.PropertyName: Console.Write($"{evt.GetString()} = "); break; case TomlParseEventKind.String: Console.WriteLine($"\"{evt.GetString()}\""); break; case TomlParseEventKind.Integer: Console.WriteLine(evt.GetInt64()); break; case TomlParseEventKind.StartTable: Console.WriteLine($"[table depth={parser.Depth}]"); break; } } ``` -------------------------------- ### Configure TomlLexer options for scalar decoding Source: https://github.com/xoofx/tomlyn/blob/main/site/docs/low-level.md Configure TomlLexer options to enable scalar decoding. When DecodeScalars is true, escape sequences within strings are decoded during the tokenization process. ```csharp var options = new TomlLexerOptions { DecodeScalars = true }; var lexer = TomlLexer.Create(toml, options, sourceName: "config.toml"); ```