Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.6.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Tomlyn.Extensions.Configuration\Tomlyn.Extensions.Configuration.csproj" />
</ItemGroup>

<ItemGroup>
<None Update="sample.toml" CopyToOutputDirectory="PreserveNewest" />
<None Update="sample_with_underscores.toml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0;net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<OutputType>Exe</OutputType>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="8.9.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.6" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.4.0" />
<PackageReference Include="xunit.v3" Version="3.2.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Tomlyn.Extensions.Configuration\Tomlyn.Extensions.Configuration.csproj" />
</ItemGroup>

<ItemGroup>
<None Update="sample.toml" CopyToOutputDirectory="PreserveNewest" />
<None Update="sample_with_underscores.toml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
26 changes: 0 additions & 26 deletions Tomlyn.Extensions.Configuration.sln

This file was deleted.

4 changes: 4 additions & 0 deletions Tomlyn.Extensions.Configuration.slnx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<Solution>
<Project Path="Tomlyn.Extensions.Configuration\Tomlyn.Extensions.Configuration.csproj" />
<Project Path="Tomlyn.Extensions.Configuration.Tests\Tomlyn.Extensions.Configuration.Tests.csproj" />
</Solution>
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ public static IConfigurationBuilder AddTomlStream(this IConfigurationBuilder bui
{
throw new ArgumentNullException(nameof(builder));
}
if (stream == null)
{
throw new ArgumentNullException(nameof(stream));
}

return builder.Add<TomlStreamConfigurationSource>(s => s.Stream = stream);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ public static IDictionary<string, string> Parse(Stream input)
private IDictionary<string, string> ParseStream(Stream input)
{
using var reader = new StreamReader(input);
var doc = Toml.Parse(reader.ReadToEnd());
VisitObject(doc.ToModel());
var model = TomlSerializer.Deserialize<TomlTable>(reader.ReadToEnd())
?? throw new FormatException("TOML deserialization returned null");
VisitObject(model);
return _data;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;net461</TargetFrameworks>
<TargetFrameworks>netstandard2.0;net8.0;net10.0</TargetFrameworks>
<Description>TomlConfigurationProvider using Tomlyn</Description>
<RepositoryUrl>https://github.com/bugproof/Tomlyn.Extensions.Configuration</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageVersion>1.0.6</PackageVersion>
<PackageVersion>2.0.0</PackageVersion>
<PackageTags>toml;configuration</PackageTags>
<PackageIconUrl>https://raw.githubusercontent.com/xoofx/Tomlyn/master/img/logo.png</PackageIconUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<LangVersion>default</LangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="5.0.0" />
<PackageReference Include="Tomlyn" Version="0.14.3" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="10.0.6" />
<PackageReference Include="Tomlyn" Version="2.3.0" />
</ItemGroup>

</Project>
258 changes: 258 additions & 0 deletions docs/superpowers/plans/2026-04-16-modernization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
# Tomlyn.Extensions.Configuration Modernization Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Modernize the solution to .slnx, target net8.0/net10.0/netstandard2.0, upgrade Tomlyn to v2.3.0, and migrate tests to xUnit v3.

**Architecture:** Replace legacy .sln with .slnx XML format. Update target frameworks (drop net461, add net8.0 and net10.0). Migrate Tomlyn API from `Toml.Parse().ToModel()` to `Toml.ToModel()`. Migrate test framework from xUnit v2 to xUnit v3.

**Tech Stack:** .NET 10 SDK, Tomlyn 2.3.0, Microsoft.Extensions.Configuration 10.0.6, xUnit v3 (3.2.2), FluentAssertions 8.9.0

---

## File Map

| File | Action | Responsibility |
|------|--------|----------------|
| `Tomlyn.Extensions.Configuration.sln` | Delete | Legacy solution format |
| `Tomlyn.Extensions.Configuration.slnx` | Create | New XML solution format |
| `Tomlyn.Extensions.Configuration/Tomlyn.Extensions.Configuration.csproj` | Modify | TFMs, version, deps |
| `Tomlyn.Extensions.Configuration/TomlConfigurationFileParser.cs` | Modify | Tomlyn v2 API migration |
| `Tomlyn.Extensions.Configuration.Tests/Tomlyn.Extensions.Configuration.Tests.csproj` | Modify | TFMs, xUnit v3, deps |

---

### Task 1: Convert solution file from .sln to .slnx

**Files:**
- Delete: `Tomlyn.Extensions.Configuration.sln`
- Create: `Tomlyn.Extensions.Configuration.slnx`

- [ ] **Step 1: Create the new .slnx file**

Create `Tomlyn.Extensions.Configuration.slnx` with:

```xml
<Solution>
<Project Path="Tomlyn.Extensions.Configuration\Tomlyn.Extensions.Configuration.csproj" />
<Project Path="Tomlyn.Extensions.Configuration.Tests\Tomlyn.Extensions.Configuration.Tests.csproj" />
</Solution>
```

- [ ] **Step 2: Delete the old .sln file**

```bash
rtk git rm Tomlyn.Extensions.Configuration.sln
```

- [ ] **Step 3: Verify the new solution loads**

```bash
rtk dotnet sln Tomlyn.Extensions.Configuration.slnx list
```

Expected: Both projects listed.

---

### Task 2: Update main project (.csproj)

**Files:**
- Modify: `Tomlyn.Extensions.Configuration/Tomlyn.Extensions.Configuration.csproj`

- [ ] **Step 1: Update the .csproj file**

Replace the entire contents of `Tomlyn.Extensions.Configuration/Tomlyn.Extensions.Configuration.csproj` with:

```xml
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;net8.0;net10.0</TargetFrameworks>
<Description>TomlConfigurationProvider using Tomlyn</Description>
<RepositoryUrl>https://github.com/bugproof/Tomlyn.Extensions.Configuration</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageVersion>2.0.0</PackageVersion>
<PackageTags>toml;configuration</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<LangVersion>default</LangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="10.0.6" />
<PackageReference Include="Tomlyn" Version="2.3.0" />
</ItemGroup>

</Project>
```

Changes from original:
- `TargetFrameworks`: `netstandard2.0;net461` → `netstandard2.0;net8.0;net10.0`
- `PackageVersion`: `1.0.6` → `2.0.0`
- `PackageIconUrl` removed (deprecated NuGet property)
- `Tomlyn`: `0.14.3` → `2.3.0`
- `Microsoft.Extensions.Configuration.FileExtensions`: `5.0.0` → `10.0.6`

- [ ] **Step 2: Verify the project restores**

```bash
rtk dotnet restore Tomlyn.Extensions.Configuration/Tomlyn.Extensions.Configuration.csproj
```

Expected: Restore succeeds for all three TFMs.

---

### Task 3: Migrate Tomlyn v2 API in TomlConfigurationFileParser.cs

**Files:**
- Modify: `Tomlyn.Extensions.Configuration/TomlConfigurationFileParser.cs:20-25`

- [ ] **Step 1: Update the ParseStream method**

In `Tomlyn.Extensions.Configuration/TomlConfigurationFileParser.cs`, replace lines 20-26:

```csharp
private IDictionary<string, string> ParseStream(Stream input)
{
using var reader = new StreamReader(input);
var doc = Toml.Parse(reader.ReadToEnd());
VisitObject(doc.ToModel());
return _data;
}
```

With:

```csharp
private IDictionary<string, string> ParseStream(Stream input)
{
using var reader = new StreamReader(input);
var model = Toml.ToModel(reader.ReadToEnd());
VisitObject(model);
return _data;
}
```

This changes the Tomlyn API call from the removed `Toml.Parse().ToModel()` (legacy v0.x) to `Toml.ToModel()` (v1.0+/v2.x). The return type is still `TomlTable`. Parse errors now throw `TomlException` instead of setting `doc.HasErrors`, but the caller (`TomlConfigurationProvider.Load`) already catches all exceptions and wraps them as `FormatException`.

- [ ] **Step 2: Verify the main project builds for all TFMs**

```bash
rtk dotnet build Tomlyn.Extensions.Configuration/Tomlyn.Extensions.Configuration.csproj
```

Expected: Build succeeds for netstandard2.0, net8.0, and net10.0.

---

### Task 4: Update test project (.csproj) for xUnit v3

**Files:**
- Modify: `Tomlyn.Extensions.Configuration.Tests/Tomlyn.Extensions.Configuration.Tests.csproj`

- [ ] **Step 1: Update the test .csproj file**

Replace the entire contents of `Tomlyn.Extensions.Configuration.Tests/Tomlyn.Extensions.Configuration.Tests.csproj` with:

```xml
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0;net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<OutputType>Exe</OutputType>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="8.9.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.6" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.4.0" />
<PackageReference Include="xunit.v3" Version="3.2.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Tomlyn.Extensions.Configuration\Tomlyn.Extensions.Configuration.csproj" />
</ItemGroup>

<ItemGroup>
<None Update="sample.toml" CopyToOutputDirectory="PreserveNewest" />
<None Update="sample_with_underscores.toml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
```

Changes from original:
- `TargetFramework`: `net6.0` → `TargetFrameworks`: `net8.0;net10.0` (multi-target)
- Added `<OutputType>Exe</OutputType>` (required for xUnit v3)
- `xunit` 2.4.1 → `xunit.v3` 3.2.2
- `xunit.runner.visualstudio` 2.4.5 → 3.1.5
- `FluentAssertions` 6.6.0 → 8.9.0
- `Microsoft.Extensions.Configuration.Binder` 6.0.0 → 10.0.6
- `Microsoft.NET.Test.Sdk` 17.1.0 → 18.4.0

- [ ] **Step 2: Verify the test project restores**

```bash
rtk dotnet restore Tomlyn.Extensions.Configuration.Tests/Tomlyn.Extensions.Configuration.Tests.csproj
```

Expected: Restore succeeds for net8.0 and net10.0.

---

### Task 5: Build the full solution and run tests

**Files:** None (verification only)

- [ ] **Step 1: Build the full solution**

```bash
rtk dotnet build Tomlyn.Extensions.Configuration.slnx
```

Expected: Build succeeds with 0 errors. Warnings about nullable reference types are acceptable.

- [ ] **Step 2: Run all tests**

```bash
rtk dotnet test Tomlyn.Extensions.Configuration.slnx
```

Expected: All tests pass on both net8.0 and net10.0 TFMs:
- `TomlConfigurationExtensionsTest.Bind` - PASS
- `TomlToSnakeCaseModifierTest.BindCorrect` - PASS

- [ ] **Step 3: Troubleshoot if tests fail**

If tests fail due to FluentAssertions 8.x API changes, check the error message. Common changes:
- `BeEquivalentTo` options API may have changed
- Some assertion methods may have been renamed

If tests fail due to Tomlyn v2 type changes, check whether `TomlTableArray` is still used or if arrays of tables are now represented differently.

---

### Task 6: Commit all changes

- [ ] **Step 1: Stage and commit**

```bash
rtk git add Tomlyn.Extensions.Configuration.slnx Tomlyn.Extensions.Configuration/Tomlyn.Extensions.Configuration.csproj Tomlyn.Extensions.Configuration/TomlConfigurationFileParser.cs Tomlyn.Extensions.Configuration.Tests/Tomlyn.Extensions.Configuration.Tests.csproj
rtk git rm Tomlyn.Extensions.Configuration.sln
rtk git commit -m "Modernize solution: slnx, net8.0/net10.0, Tomlyn v2.3.0, xUnit v3

- Convert .sln to .slnx format
- Target netstandard2.0, net8.0, net10.0 (drop net461)
- Upgrade Tomlyn from 0.14.3 to 2.3.0
- Migrate Toml.Parse().ToModel() to Toml.ToModel()
- Upgrade test framework to xUnit v3 (3.2.2)
- Update all NuGet dependencies to latest stable
- Bump package version to 2.0.0"
```
Loading