An open API service indexing awesome lists of open source software.

https://github.com/xoofx/tomlyn

Tomlyn is a TOML parser, validator and authoring library for .NET Framework and .NET Core
https://github.com/xoofx/tomlyn

csharp dotnet dotnet-core toml toml-parser toml-validation

Last synced: 3 months ago
JSON representation

Tomlyn is a TOML parser, validator and authoring library for .NET Framework and .NET Core

Awesome Lists containing this project

README

          

# Tomlyn [![ci](https://github.com/xoofx/Tomlyn/actions/workflows/ci.yml/badge.svg)](https://github.com/xoofx/Tomlyn/actions/workflows/ci.yml) [![Coverage Status](https://coveralls.io/repos/github/xoofx/Tomlyn/badge.svg?branch=main)](https://coveralls.io/github/xoofx/Tomlyn?branch=main) [![NuGet](https://img.shields.io/nuget/v/Tomlyn.svg)](https://www.nuget.org/packages/Tomlyn/)

Tomlyn is a high-performance .NET [TOML](https://toml.io/en/) 1.1 parser, round-trippable syntax tree, and `System.Text.Json`-style object serializer - NativeAOT ready.

#### SharpYaml Looking for YAML support? Check out [SharpYaml](https://xoofx.github.io/SharpYaml/).

> **Note**: Tomlyn v1 is a major redesign with breaking changes from earlier versions. It uses a **`System.Text.Json`-style API** with `TomlSerializer`, `TomlSerializerOptions`, and resolver-based metadata (`ITomlTypeInfoResolver`). See the [migration guide](https://xoofx.github.io/Tomlyn/docs/migration) for details.

## ✨ Features

- **`System.Text.Json`-style API**: familiar surface with `TomlSerializer`, `TomlSerializerOptions`, `TomlTypeInfo`
- **TOML 1.1.0 only**: Tomlyn v1 targets [TOML 1.1.0](https://toml.io/en/v1.1.0) and does **not** support TOML 1.0
- **Source generation**: NativeAOT / trimming friendly via `TomlSerializerContext` and `[TomlSerializable]` roots
- **Cross-project polymorphism**: register derived types at runtime or on a source-generated context when base and derived types live in different assemblies
- **`System.Text.Json` attribute interop**: reuse `[JsonPropertyName]`, `[JsonIgnore]`, `[JsonRequired]`, `[JsonConstructor]`, `[JsonObjectCreationHandling]`, and polymorphism attributes
- **Flexible collection input**: opt a collection member into accepting either a single TOML value or an array via `[TomlSingleOrArray]`
- **Allocation-free parsing pipeline**: incremental `TomlLexer` → `TomlParser` with precise spans for errors
- **Low-level access**: full lexer/parser API plus a lossless, trivia-preserving syntax tree (`SyntaxParser` → `DocumentSyntax`)
- **Reflection control**: reflection-based POCO mapping is available, but can be disabled for NativeAOT via a feature switch / MSBuild property

## 📐 Requirements

Tomlyn targets `net8.0`, `net10.0`, and `netstandard2.0`.

- Consuming the NuGet package works on any runtime that supports `netstandard2.0` (including .NET Framework) or modern .NET (`net8.0+`).
- Building Tomlyn from source requires the .NET 10 SDK.

## 📦 Install

```sh
dotnet add package Tomlyn
```

Tomlyn ships the source generator in-package (`analyzers/dotnet/cs`) - no extra package needed.

## 🚀 Quick Start

```csharp
using Tomlyn;

// Serialize
var toml = TomlSerializer.Serialize(new { Name = "Ada", Age = 37 });

// Deserialize
var person = TomlSerializer.Deserialize(toml);
```

### Untyped model (`TomlTable`)

```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));
```

### Options

```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);
```

By default, `PropertyNamingPolicy` is `null`, meaning CLR member names are used as-is for TOML mapping keys (same default as `System.Text.Json`).
`MaxDepth = 0` uses the built-in default of `64`.
`PreferredObjectCreationHandling = JsonObjectCreationHandling.Replace` matches `System.Text.Json`: read-only properties are not populated unless you opt into `Populate` via options or `[JsonObjectCreationHandling]`.

### Source Generation

```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);
```

### Cross-Project Polymorphism

When a base type lives in one project and derived types live in another, you can register derived types without putting `[TomlDerivedType]` on the base type.

**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 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
{
}
```

Use `TomlPolymorphismOptions.DerivedTypeMappings` and `[TomlDerivedTypeMapping]` additively with existing base-type attributes. Base-type registrations still take precedence when the same discriminator or derived type is registered more than once.

### Single Value Or Array Collections

```csharp
using System.Text.Json.Serialization;
using Tomlyn.Serialization;

public sealed class PackagingConfiguration
{
public PackagingConfiguration()
{
RuntimeIdentifiers = new List();
}

[TomlSingleOrArray]
[JsonPropertyName("rid")]
public List RuntimeIdentifiers { get; }
}
```

With `[TomlSingleOrArray]`, both of these TOML payloads are valid:

```toml
rid = "win-x64"
```

```toml
rid = ["win-x64", "linux-x64"]
```

For mutable read-only collection members, Tomlyn appends into the existing collection instance. Without `[TomlSingleOrArray]`, collection members still require a TOML array.

### Reflection Control

Reflection fallback can be disabled globally before first serializer use:

```csharp
AppContext.SetSwitch("Tomlyn.TomlSerializer.IsReflectionEnabledByDefault", false);
```

When publishing with NativeAOT (`PublishAot=true`), the Tomlyn NuGet package disables reflection-based serialization by default.
You can override the default by setting the following MSBuild property in your app project:

```xml

true

```

## 📖 Documentation

- [User guide](site/readme.md)
- Website (Lunet): https://xoofx.github.io/Tomlyn

## 🪪 License

This software is released under the [BSD-Clause 2 license](https://opensource.org/licenses/BSD-2-Clause).

## 🤗 Author

Alexandre Mutel aka [xoofx](http://xoofx.github.io).