Skip to content

feat: Extended Types Support (Choice, Anonymous Records, DU Encodings)#27

Merged
panesofglass merged 2 commits intomasterfrom
002-extended-types
Feb 7, 2026
Merged

feat: Extended Types Support (Choice, Anonymous Records, DU Encodings)#27
panesofglass merged 2 commits intomasterfrom
002-extended-types

Conversation

@panesofglass
Copy link
Collaborator

@panesofglass panesofglass commented Feb 7, 2026

Summary

Implements comprehensive support for extended F# type features in JSON Schema generation, resolving issue #22.

Features

US1: Anonymous Record Support - inline object schemas with no $ref
US2: Choice Type Support - anyOf schemas for all 7 Choice variants
US3: DU Encoding Styles - InternalTag, AdjacentTag, ExternalTag, Untagged
US4: Format Annotations - DateTime, Guid, Uri, TimeSpan, etc.

API Changes

  • Added unionEncoding parameter to Generator.Create() and CreateMemoized()
  • Fully backwards compatible - all parameters optional
  • Default behavior unchanged (InternalTag)

Test Results

  • 181 total tests (was 172): +5 Core tests, +9 main tests
  • ✅ All tests pass across net8.0, net9.0, net10.0
  • ✅ 100% backwards compatible - all 167 original tests pass byte-identical
  • ✅ No breaking changes

Example Usage

```fsharp
// Use different DU encoding styles
let gen = Generator.Create(unionEncoding = AdjacentTag)
let schema = gen typeof

// Anonymous records automatically inline
type Rec = { Details: {| Name: string; Age: int |} }

// Choice types produce anyOf schemas
type Data = { Value: Choice<string, int> }
```

🤖 Generated with Claude Code

…d DU encoding styles

Implements comprehensive support for extended F# type features in JSON Schema generation:

**User Stories Implemented:**
- US1: Anonymous Record Support - inline object schemas with no $ref
- US2: Choice Type Support - anyOf schemas for all 7 Choice variants
- US3: DU Encoding Styles - InternalTag, AdjacentTag, ExternalTag, Untagged
- US4: Format Annotations - already implemented (DateTime, Guid, Uri, etc.)

**Core Changes:**
- Added isChoiceType and analyzeChoiceType for Choice<_,_> through Choice<_,_,_,_,_,_,_>
- Added isAnonymousRecord (detects <>f__AnonymousType) and analyzeAnonymousRecord
- Added resolveUnionEncoding using CustomAttributeData (properties are write-only)
- Updated buildCaseSchema with 4 encoding styles (InternalTag default)
- Extended isInlineType to include Choice and anonymous records

**NJsonSchema API:**
- Added unionEncoding parameter to Generator.Create() and CreateMemoized()
- Updated cache key to include UnionEncodingStyle
- Fixed translateProp to copy Properties/Required for nested Object schemas

**Testing:**
- 181 total tests (was 172): +5 Core tests, +9 main tests
- All tests pass across net8.0, net9.0, net10.0
- 100% backwards compatible - default InternalTag unchanged
- New snapshot tests for all encoding styles

**Backwards Compatibility:**
- ✅ All 167 original tests pass byte-identical
- ✅ Default UnionEncoding = InternalTag (unchanged)
- ✅ API fully backwards compatible (optional parameters)
- ✅ No breaking changes to schemas or behavior

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@panesofglass panesofglass changed the base branch from 001-core-extraction to master February 7, 2026 18:25
@panesofglass panesofglass merged commit ed80ac1 into master Feb 7, 2026
1 check failed
@panesofglass panesofglass deleted the 002-extended-types branch February 7, 2026 18:27
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.

1 participant