A human-friendly DSL for ATProto Lexicons
27
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add docs for conversion quirks

authored by stavola.xyz and committed by

Tangled dd7c71c3 0bf25761

+41
+41
website/content/docs/cli/06-generate.md
··· 134 134 135 135 Without `--root`, it defaults to the `source.directory` from mlf.toml or the current directory. 136 136 137 + ### `@const` Float Values 138 + 139 + ATProto's data model has no floats — integers only. Annotations themselves accept any numeric literal (they're free-form metadata), but `@const` is special: its values become actual fields in the generated JSON Lexicon. 140 + 141 + To keep output spec-compliant, the lexicon generator applies two rules to `@const` numeric values: 142 + 143 + - **Whole-number floats → integers.** `@const("revision", 3)` emits `"revision": 3` (JSON number), never `3.0`. 144 + - **Fractional floats → strings.** `@const("x-threshold", 3.14)` emits `"x-threshold": "3.14"` (JSON string) and prints a warning. Wrapping as a string is the spec-compliant way to carry non-integer numeric values through ATProto. 145 + 146 + If you genuinely need a float-shaped value in your lexicon JSON, pass it as a string in MLF — `@const("x-threshold", "3.14")` — to skip the coercion. 147 + 137 148 --- 138 149 139 150 ## Generate Code ··· 376 387 createdAt!: Datetime, 377 388 } 378 389 ``` 390 + 391 + ### Conversion Warnings 392 + 393 + Some published lexicons in the wild use shapes the ATProto spec doesn't strictly require, or def types MLF doesn't have dedicated syntax for. The converter accepts these with a warning rather than failing, so you can always roundtrip a lexicon and decide what to do next. 394 + 395 + **Lenient handling of non-spec shapes:** 396 + 397 + | Source JSON shape | Converter behavior | 398 + |---|---| 399 + | `object` with no `properties` field | Treated as an empty object; emits `{}` | 400 + | Open `union` with empty `refs: []` | Emits `unknown` | 401 + | `array` with no `items` field | Emits `unknown[]` | 402 + 403 + Each of these produces a warning printed to stderr identifying the namespace and the shape that was coerced. 404 + 405 + **Unknown def types:** 406 + 407 + When a def's `type` isn't in MLF's known set (`record`, `query`, `procedure`, `subscription`, `object`, `array`, `union`, `ref`, `token`, primitive types), the converter emits it as a placeholder: 408 + 409 + ```mlf 410 + @const("type", "permission-set") 411 + @const("permissions", [...]) 412 + def type mySet = unknown; 413 + ``` 414 + 415 + Every field of the original JSON def is preserved as `@const` annotations. On the return trip through `mlf generate lexicon`, codegen re-emits all those fields verbatim, making any future spec-defined def type roundtrip automatically without grammar work. 416 + 417 + **NSID-shaped `@const` strings:** 418 + 419 + When a `@const` string value contains `#` (the ATProto local-ref marker), the converter emits a warning suggesting you may want `@reference` instead when hand-editing the MLF. `@reference` resolves type paths through the workspace and emits the resulting NSID at codegen time, which is useful when the target moves; `@const` is kept as the default since it's always safe. 379 420 380 421 --- 381 422