# JSON Export

The JSON exporter serialises an entire project's imported master data into one JSON document. Its on-disk shape is the **canonical Masterbelt export format** consumed by every codegen target's `LoadJSON`-shaped helper.

## Kind

The export-kind identifier is `json`.

## Configuration

A JSON export is configured under `exports:` in the project configuration file:

```yaml
exports:
  - kind: json
    out: data/masterdata.json
```

- `kind` selects this exporter.
- `out` is the file system path the exporter writes to. Relative paths resolve against the project root. The exporter creates any missing parent directories.

No `options` keys are recognised at this stage; unknown keys are silently ignored to leave room for future extensions.

## Document Shape

The exporter writes one JSON object per run. Top-level keys are the masters' **flat camelCased identifiers** (the same name the per-target MasterData accessor uses). Values are arrays of record objects in importer-supplied order:

```json
{
  "items": [
    {"count": 10, "id": 1, "name": "alpha"},
    {"count": 20, "id": 2, "name": "beta"}
  ],
  "userFriendships": [
    {"friend": 9, "owner": 7}
  ]
}
```

- Top-level keys appear in the project's master-declaration order. A master that declared no source section appears with an empty array.
- Per-record keys appear in lexicographic order so two records with the same field set always produce byte-identical encodings regardless of producer iteration order.
- The exporter ends the file with a trailing newline.

A nested master `master User { master Friendships { ... } }` appears at the top level under its flattened-then-camelCased name (`userFriendships`) — no nested object layout is used.

## Value Encoding

| Masterbelt value | JSON encoding |
| --- | --- |
| `null` | `null` |
| `bool` | `true` / `false` |
| `int` whose abs value < 2^53 | JSON number (decimal digits) |
| `int` whose abs value >= 2^53 | JSON string (quoted decimal digits) |
| `string` | JSON string with standard escapes |
| `list<T>` | JSON array, elements recursed |
| `map<K, V>` | JSON object keyed by rendered key, entries sorted by key |
| nested product | JSON object, keys sorted lexicographically |

The safe-integer guard at 2^53 keeps the document round-trippable through JavaScript consumers. Loaders that promote those values back to a numeric type are free to detect the quoted form and parse it through a big-integer constructor; the exporter never emits a `bigint` JavaScript literal because plain JSON does not have one.

## Field Names

Per-record keys are the master's surface field names as written in Masterbelt source. Names are emitted verbatim; no case transformation is applied at the field level. A `ref<T>` field expands to the target master's primary-key fields under the surrounding field's name joined with `_` (`field_pk1`, `field_pk2`, ...) before serialisation.

## Determinism

Two runs against the same input produce byte-identical output:

- Top-level keys appear in master-declaration order.
- Per-record keys are sorted lexicographically inside each object.
- Map entries are sorted by their rendered key.
- List elements preserve the producer's order (the producer's order is itself deterministic for every importer defined in [import-csv.md](import-csv.md) and friends).

## Loader Contract

Every codegen target produces a `LoadJSON` / `loadJSON` / `LoadJson` helper that consumes this format and returns a fully wired `MasterData`. The per-target signatures and casing are defined in:

- [../codegen/golang.md](../codegen/golang.md#master-data)
- [../codegen/typescript.md](../codegen/typescript.md#master-data)
- [../codegen/csharp.md](../codegen/csharp.md#master-data)

The format is the contract between the exporter and the loaders; changes to the document shape are coordinated through all three target specifications.
