# Toon — Wire Format Specification

Exact grammar of Toon output. Needed by LLMs parsing Toon back to objects, and for verifying generated output against expectations.

Format version: `"1.0"` (constant `AcToonSerializer.FormatVersion`, emitted as `version` in `@meta`).

## Top-level structure

Output contains up to three sections in this order:

```
@meta { ... }
@types { ... }
@data { ... }
```

Section presence per `ToonSerializationMode`:

| Mode | `@meta` | `@types` | `@data` |
|---|---|---|---|
| `Full` | ✓ | ✓ | ✓ |
| `MetaOnly` | ✓ | ✓ | — |
| `DataOnly` | — | — | ✓ |

In `Full` mode with `UseIndentation = true`, a blank line separates `@meta/@types` from `@data`.

## `@meta` section

```
@meta {
  version = "1.0"
  format = "toon"
  source-code-language = "C#"
  context = "optional domain description"
  types = ["Type1", "Type2", "Type3"]
}
```

- `version` — Toon format version.
- `format` — always `"toon"`.
- `source-code-language` — always `"C#"`.
- `context` — emitted only when the `domainDescription` overload was invoked.
- `types` — type short names in **topological order** (dependencies before dependents). Excludes primitives, strings, framework collection generics (`List<>`, `Dictionary<>`, `IEnumerable<>`, `ICollection<>`), and generic type definitions.

The `@types` section body (when emitted) follows the same topological order.

## `@types` section

```
@types {
  TypeName: "description"
    [table-name: "..."]
    [related-type: "dto-of OtherType"]
    [purpose: "..."]
    PropertyName: typeHint
      [description: "..."]
      [purpose: "..."]
      [business-logic: "..."]
      [constraints: "..."]
      [examples: "..."]
      [primary-key: true]
      [foreign-key: "..."]
      [other-key: "..."]
      [navigation: "many-to-one"]
      [inverse-property: "..."]
}
```

- Property metadata indented one level below its property header.
- Optional lines emitted only when the value is non-empty.
- `navigation` values are kebab-case of `ToonRelationType`: `many-to-one`, `one-to-many`, `one-to-one`, `many-to-many`.
- `typeHint` uses **C# short names** — primitives: `int`, `long`, `short`, `byte`, `sbyte`, `uint`, `ulong`, `ushort`, `double`, `float`, `decimal`, `bool`, `string`, `char`; special types: `DateTime`, `DateTimeOffset`, `TimeSpan`, `Guid`; collections: `Person[]`, `List<Person>`, `Dictionary<string, int>`; class / enum names as-is. Nullable suffix: `int?`, `DateTime?`, `TaxDisplayType?`.
- ⚠️ **Two naming conventions coexist.** `@types` uses C# short names (above); `@data` inline type hints (when `UseInlineTypeHints = true`) use full-width tokens like `int32`, `float64`, `datetime` — see Inline type hints below.

### Enum types in `@types`

```
EnumName: enum
  description: "..."
  purpose: "..."
  underlying-type: "int"
  default-value: 0
  values:
    MemberName = numericValue
      description: "..."
    OtherMember = numericValue
```

- Members emitted as `Name = numericValue`; per-member description is an indented sub-property.
- When `UseEnhancedMetadata = false`, only the `MemberName = numericValue` list is emitted (no description, purpose, underlying-type, default-value).

## `@data` section

### Object syntax

```
TypeName {
  PropertyName = value
  OtherProperty = value
}
```

- `TypeName` prefix emitted when `WriteTypeNames = true` (default).
- Properties written one per line; `=` has surrounding spaces only when `UseIndentation = true`, else tight (`prop=value`).
- Properties whose value equals `default(T)` / `null` / `0` / `false` skipped when `OmitDefaultValues = true`.

### Primitive values

| Kind | Representation |
|---|---|
| `string` | `"escaped"` inline, or triple-quote for long strings. |
| `int32`/`int64`/`int16`/`byte`/`sbyte`/`uint16`/`uint32`/`uint64` | Plain number, `CultureInfo.InvariantCulture`. |
| `bool` | `true` / `false`. |
| `double` | `G17` format; `NaN`/`±Infinity` → `null`. |
| `float` | `G9` format; `NaN`/`±Infinity` → `null`. |
| `decimal` | Invariant culture. |
| `DateTime` | ISO 8601 in quotes: `"2026-04-24T10:30:00.0000000"` (`"O"` format). |
| `DateTimeOffset` | ISO 8601 with offset in quotes. |
| `TimeSpan` | `"c"` format in quotes. |
| `Guid` | `"D"` format (36-char dashed) in quotes. |
| `char` | single-char string in quotes. |
| `enum` | **Numeric** value of the underlying type (not the member name). `@types` holds the name→value map. |
| `null` | literal `null` (no quotes). |

### String escaping

JSON-like escapes: `\"`, `\\`, `\n`, `\r`, `\t`, `\uXXXX` for chars `< 32`. If no escape applies, raw double-quoted.

### Multi-line strings (triple-quote)

Automatic when `UseMultiLineStrings = true` AND `string.Length > MultiLineStringThreshold` (default 80):

```
Bio = """
  Line 1
  Line 2

  Line 4
"""
```

- Each content line indented one level deeper than the owning property.
- Closing `"""` at the property's own indent level.
- Line terminators inside the string normalized to platform newline during split.

### Collection syntax

```
PropertyName = <ElementType[]> (count: N) [
  item1
  item2
]
```

- `<ElementType[]> (count: N) ` header emitted only when `ShowCollectionCount = true` (default).
- One item per line.
- Items serialize by runtime type (polymorphic collections supported).

### Dictionary syntax

```
PropertyName = <Dictionary<KeyType, ValueType>> (count: N) {
  key => value
  otherKey => otherValue
}
```

- Header shows the specific generic type when derivable (via `IsDictionaryType`), else `<dict>`.
- Key/value separator is literal ` => ` regardless of indentation setting.

### Reference syntax

When `ReferenceHandling != None` and an object is referenced more than once:

- **First occurrence:** `@N TypeName { ... }` — `N` is the reference ID.
- **Subsequent occurrences:** `@ref:N`.

Circular references safe — the second visit emits `@ref:N` instead of recursing. When the reference system is disabled (`ReferenceHandling = None`), shared objects serialize redundantly and true cycles cause depth-truncation to `null`.

### Inline type hints

When `UseInlineTypeHints = true`:

```
Age = 30 <int32>
Name = "Alice" <string>
```

Hint tokens (full-width naming — **distinct** from C# short names in `@types`): `string`, `int32`, `int64`, `int16`, `byte`, `sbyte`, `uint16`, `uint32`, `uint64`, `bool`, `float32`, `float64`, `decimal`, `char`, `datetime`, `datetimeoffset`, `timespan`, `guid`, `enum`. Disabled by default (info lives in `@types`).

## Compact mode quirks

When `UseIndentation = false`:

- No leading indent whitespace.
- Property assignments use `=` with no surrounding spaces.
- Enum member list uses `=` with no surrounding spaces.
- No blank line between `@meta` and `@data`.
- `@types` section drops the trailing blank line between type definitions.
- Closing braces/brackets remain on their own lines (structure is still line-based).
