Generating JSON from Bosatsu Values
Bosatsu can be used as a typed configuration language and then rendered to JSON with lib json.
This page focuses on lib json (not tool json).
Quick start
- Typecheck as you iterate:
./bosatsuj lib check --name core_alpha
- Generate JSON for a value:
./bosatsuj lib json write --name core_alpha --main Bosatsu/Example/Json/Github/Workflows/Ci::workflow
Command reference
./bosatsuj lib json write [--repo_root <path>] [--name <lib_name>] --main <valueIdent> [--output <path>]
Common flags:
--name: library name from yourbosatsu_libs.json--main: package/value to evaluate and encode--output: write JSON to a file instead of stdout
Encoding shape
lib json uses type-directed encoding:
Int-> JSON numberFloat64-> JSON numberString-> JSON stringBool-> JSON booleanList[a]-> JSON arrayDict[String, a]-> JSON objectstruct-> JSON objectenum-> JSON object (constructors must remain distinguishable after encoding)
Option behavior
Option is especially useful for configuration records:
Noneencodes asnullwhen that is unambiguousSome(x)encodes asx- Nested options (
Option[Option[a]]) use array encoding to avoid ambiguity: - outer
None->[] - outer
Some(None)->[null] - outer
Some(Some(x))->[x]
For record fields, Option lets you model shape variation directly:
struct Step(
uses: Option[String],
run: Option[String],
with: Option[WithConfig],
)
This usually replaces many near-duplicate structs.
Patterns that worked well for GitHub workflow modeling
- Put shared types/constants/helpers in a common module (for example
Util.bosatsu) - Use constants for repeated literals (runner names, action versions,
17, step labels) - Use helper functions for multi-line shell scripts (for example
cat_lines) - Prefer one record with
Option[...]fields over many one-off variants - Use backticks only when a field is not a valid bindable name, such as
`runs-on`and`timeout-minutes`
Practical gotchas
- Keep running
lib checkwhile editing models; it catches most mistakes before JSON generation. - JSON field names come from your Bosatsu field names exactly.
Float64JSON encoding requires finite values;.NaN,∞, and-∞are not valid JSON numbers.- If your consumer treats absent and
nulldifferently, model that intentionally and test it. lib json writerequires a serializable value. Function-typed mains are rejected.
Full commands used in this workflow example
These are the exact commands used to generate the four workflow values modeled in this example:
./bosatsuj lib json write --name core_alpha --main Bosatsu/Example/Json/Github/Workflows/Ci::workflow
./bosatsuj lib json write --name core_alpha --main Bosatsu/Example/Json/Github/Workflows/CodecovMain::workflow
./bosatsuj lib json write --name core_alpha --main Bosatsu/Example/Json/Github/Workflows/DeployWeb::workflow
./bosatsuj lib json write --name core_alpha --main Bosatsu/Example/Json/Github/Workflows/Release::workflow
The source code for this page can be found here.