Skip to content

Conversation

@syedrizwanmy
Copy link

Retarget to .NET Standard 2.0

Motivation

This PR retargets the toon-dotnet library from .NET 8.0/9.0 to .NET Standard 2.0, significantly expanding compatibility to include:

  • .NET Framework 4.6.1+
  • .NET Core 2.0+
  • .NET 5+
  • .NET 6+
  • .NET 7+
  • .NET 8+
  • .NET 9+

This change makes the library accessible to a much broader range of .NET applications, including legacy projects and enterprise environments that may not have upgraded to the latest .NET versions.

Benefits

Maximum Compatibility: Works with .NET Framework 4.6.1+ and all modern .NET versions
Enterprise Ready: Supports legacy systems that haven't migrated to .NET 8/9
Broader Adoption: Enables usage in projects constrained to older .NET versions
No Breaking Changes: API remains identical, only the target framework changes

Technical Details

Framework Changes

  • Main Library (ToonFormat.csproj): Retargeted from net8.0;net9.0 to netstandard2.0
  • Test Project (ToonFormat.Tests.csproj): Retargeted from net9.0 to netcoreapp3.1 (compatible with .NET Standard 2.0)
  • SpecGenerator (ToonFormat.SpecGenerator.csproj): Kept at net9.0 (tool-only, no compatibility requirement)

Code Compatibility Fixes

To ensure compatibility with .NET Standard 2.0 and C# 9.0, the following changes were made:

  1. Language Version: Upgraded to C# 9.0 (from 7.3) to support nullable reference types while maintaining .NET Standard 2.0 compatibility

  2. Namespace Conversions: Converted all file-scoped namespaces (namespace X;) to traditional format (namespace X { ... })

  3. Nullable Types: Fixed nullable type declarations:

    • Changed int parameters with null defaults to int?
    • Updated ToonFormatException properties to use nullable types
  4. API Compatibility:

    • Replaced BitConverter.SingleToInt32Bits() (not available in .NET Standard 2.0) with unsafe code
    • Replaced double.IsFinite() / float.IsFinite() with IsNaN() / IsInfinity() checks
    • Updated StreamReader constructor calls to include bufferSize parameter
    • Fixed IReadOnlySet<T> to ISet<T> for compatibility
    • Removed required keyword usage (C# 11 feature)
    • Fixed collection expressions to use traditional syntax
    • Fixed char-to-string conversions
  5. Regex Pattern Fix: Fixed malformed regex pattern in ValidationShared.cs:

    • Before: "^-\\d+(:\\.\\d+)(:e[+-]\\d+)$" (invalid syntax)
    • After: "^-?\\d+(\\.\\d+)?(e[+-]?\\d+)?$" (correct pattern)
    • This fix resolved the QuotesStringThatLooksLikeScientificNotation test failure
  6. Dependencies: Added explicit System.Text.Json 8.0.0 NuGet package reference (required for .NET Standard 2.0)

Test Results

Before Retargeting: 16 failing tests (documented in test-failures-before-retargeting.txt)
After Retargeting: 16 failing tests (same tests, all pre-existing)

All tests that were passing before retargeting continue to pass
One new test failure was identified and fixed (QuotesStringThatLooksLikeScientificNotation)

The 16 remaining failures are all pre-existing issues unrelated to the retargeting:

  • Decimal precision issues (floating-point representation)
  • Path expansion edge cases
  • Tabular array encoding with specific delimiters

Package Compatibility

✅ Successfully builds and packages as .nupkg
System.Text.Json 8.0.0 is compatible with .NET Standard 2.0
✅ All dependencies resolve correctly

Documentation Updates

  • Updated README.md to reflect .NET Standard 2.0 target
  • Updated CONTRIBUTING.md to document .NET Standard 2.0 support

Testing

  • ✅ Full solution builds successfully (0 errors)
  • ✅ All 358 tests run successfully
  • ✅ 342 tests pass (same as before retargeting)
  • ✅ 16 tests fail (same pre-existing failures)
  • ✅ Package builds and validates correctly

Checklist

  • Code compiles without errors
  • All pre-existing passing tests continue to pass
  • New test failures identified and fixed
  • Documentation updated
  • Package compatibility verified
  • Commits follow conventional commit format
  • Branch created and ready for review

Breaking Changes

None - This is a purely additive change that expands compatibility without modifying the public API.

Migration Guide

No migration required! The library works exactly the same way, just with broader framework support.

For projects already using the library:

  • No code changes needed
  • Simply update the package reference
  • The library will now work on .NET Framework 4.6.1+ and .NET Core 2.0+

Note: This PR includes comprehensive test failure documentation in test-failures-before-retargeting.txt for reference.

Rizwan Rizvi added 4 commits December 8, 2025 00:46
- Convert file-scoped namespaces to traditional format
- Fix nullable type declarations
- Replace BitConverter.SingleToInt32Bits with unsafe code
- Fix double.IsFinite/float.IsFinite checks
- Fix StreamReader constructor calls
- Fix collection expressions and char-to-string conversions
- Fix regex pattern for numeric-like string detection
- Convert test namespaces from file-scoped to traditional
@syedrizwanmy syedrizwanmy requested review from a team and johannschopplich as code owners December 7, 2025 13:48
Rizwan Rizvi added 4 commits December 8, 2025 00:51
Restore file-level #nullable enable directives that were present in the original code. The project-level <Nullable>enable</Nullable> setting is maintained, and file-level directives provide explicit per-file control and match the original code style.
Restore all nullable annotations (JsonNode?, JsonObject?, JsonArray?) that were present in the original code. This includes:
- Method return types and parameters
- Property types in internal classes
- Generic type parameters in collections
- Restore IReadOnlySet<string>? to ISet<string>? (IReadOnlySet not available in .NET Standard 2.0)
…ine, and related types

Restore all nullable annotations that were removed:
- ArrayHeaderParseResult? return type
- ArrayHeaderInfo.Key as string?
- ArrayHeaderParseResult.InlineValues as string?
- ParsedLine? return types for Peek(), Next(), Current(), PeekAtDepth()
- JsonNode? return type for ParsePrimitiveToken()
- string? key variable in ParseArrayHeaderLine()
- Remove PR_DESCRIPTION.md and test-failures-before-retargeting.txt from tracking
- Restore string? inlineValues nullable annotation in DecodeArrayFromHeader and DecodeInlinePrimitiveArray
@ghost1face
Copy link
Contributor

Thanks for your contribution, this will help expand support greatly! We're working on getting the library in alignment with the V3 Toon Spec. Once we have this, we'll have to resolve some conflicts here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants