Generate Rust and MoonBit types from JSON Schema (port of oxidecomputer/typify)
Dependencies
moonx bobzhang/typify/cmd/typify schema.json # writes schema.rs
moonx bobzhang/typify/cmd/typify schema.json --lang moonbit # writes schema.mbt
moonx bobzhang/typify/cmd/typify schema.json -o - # to stdout| option | |
|---|---|
| -l, --lang <rust\|moonbit> | language to generate (default rust) |
| -b, --builder / -B, --no-builder | builder-style interface for Rust structs (default on) |
| -d, --additional-derive <derive> | extra derive for every type |
| -a, --additional-attr <attr> | extra attribute for every type |
| -o, --output <file> | output file, - for stdout (default: input with .rs/.mbt) |
| --crate <name@version> | crates assumed available for x-rust-type |
| --map-type <type> | map type (default ::std::collections::HashMap) |
| --unknown-crates <generate\|allow\|deny> | policy for unknown x-rust-type crates |
moonx bobzhang/typify/cmd/typify schema.json -o - | rustfmt --edition 2021 > schema.rs// moon.pkg of the package holding the generated file
import {
"bobzhang/typify/runtime" @typify_rt,
}{
"title": "Veggies",
"type": "object",
"properties": {
"fruits": { "type": "array", "items": { "type": "string" } },
"vegetables": { "type": "array", "items": { "$ref": "#/definitions/veggie" } }
},
"definitions": {
"veggie": {
"type": "object",
"required": ["veggieName", "veggieLike"],
"properties": {
"veggieName": { "type": "string" },
"veggieLike": { "type": "boolean" }
}
}
}
}let veggies = Veggies::from_json_str(
"{\"fruits\":[\"apple\"],\"vegetables\":[{\"veggieName\":\"leek\",\"veggieLike\":true}]}",
)
println(veggies.vegetables[0].veggie_name) // leek
println(veggies.to_json_string()) // same JSON as serde_json::to_string| JSON Schema / Rust | MoonBit |
|---|---|
| bool, String | Bool, String |
| i8/i32, i16, i64 | Int, Int16, Int64 |
| u8, u16, u32, u64, NonZeroU* | Byte, UInt16, UInt, UInt64 (non-zero is checked) |
| f32, f64 | Float, Double (serialized with the shortest f32/f64 digits, as serde_json does) |
| Option<T>, Box<T> | T?, T |
| Vec<T>, sets, [T; N], tuples | Array[T], Array[T], FixedArray[T], tuples |
| HashMap<K, V> / BTreeMap | Map[K, V] (BTreeMap output is key-sorted) |
| serde_json::Value | Json |
| uuid::Uuid, chrono::NaiveDate, chrono::DateTime<Utc> | @typify_rt.Uuid, @typify_rt.NaiveDate, @typify_rt.DateTimeUtc |
| std::net::{IpAddr, Ipv4Addr, Ipv6Addr} | @typify_rt.IpAddr, Ipv4Addr, Ipv6Addr |
| constrained strings, numbers and enums | newtypes validated on construction and decoding |
let root = @schema.RootSchema::from_json_str(schema_text)
let space = @typify.TypeSpace::new(@typify.TypeSpaceSettings::default())
space.add_root_schema(root)
let rust : String = @rust.to_stream(space).to_string()
let moonbit : String = @moonbit.generate(space)impl Show for TypifyErrorpub(all) struct StructProperty {
name : String
rename : StructPropertyRename
state : StructPropertyState
description : String?
type_id : TypeId
} derive(Eq, Debug)pub(all) struct TypeEntry {
details : TypeEntryDetails
extra_derives : StrSet
extra_attrs : StrSet
} derive(Eq, Debug)fn TypeEntry::has_impl(self : TypeEntry, space : TypeSpace, impl_name : TypeSpaceImpl) -> Bool raise TypifyErrorfn TypeEntry::validate_value(self : TypeEntry, space : TypeSpace, value : Value) -> DefaultKind raise TypifyErrorpub(all) enum TypeEntryDetails {
Enum(TypeEntryEnum)
Struct(TypeEntryStruct)
Newtype(TypeEntryNewtype)
Native(TypeEntryNative)
Option(TypeId)
Box(TypeId)
Vec(TypeId)
Map(TypeId, TypeId)
Set(TypeId)
Array(TypeId, Int)
Tuple(Array[TypeId])
Unit
Boolean
Integer(String)
Float(String)
String
JsonValue
Reference(TypeId)
} derive(Eq, Debug)pub(all) struct TypeEntryEnum {
name : String
rename : String?
description : String?
default : Value?
tag_type : EnumTagType
variants : Array[Variant]
deny_unknown_fields : Bool
bespoke_impls : Array[TypeEntryEnumImpl]
schema : Schema
} derive(Eq, Debug)pub struct TypeSpace {
id_to_entry : SortedMap[TypeId, TypeEntry]
uses_chrono : Bool
uses_uuid : Bool
uses_serde_json : Bool
uses_regress : Bool
settings : TypeSpaceSettings
defaults : Array[DefaultImpl]
// private fields
}fn TypeSpace::add_ref_types(self : TypeSpace, type_defs : Array[(String, Schema)]) -> Unit raise TypifyErrorfn TypeSpace::add_type_with_name(self : TypeSpace, schema : Schema, name_hint : String?) -> TypeId raise TypifyErrorpub(all) struct TypeSpaceReplace {
replace_type : String
impls : Array[TypeSpaceImpl]
} derive(Debug)pub struct TypeSpaceSettings {
type_mod : String?
extra_derives : Array[String]
extra_attrs : Array[String]
struct_builder : Bool
unknown_crates : UnknownPolicy
map_type : String
patch : Map[String, TypeSpacePatch]
replace : Map[String, TypeSpaceReplace]
// private fields
}fn TypeSpaceSettings::with_conversion(self : TypeSpaceSettings, schema : SchemaObject, type_name : String, impls : Array[TypeSpaceImpl]) -> TypeSpaceSettingsfn TypeSpaceSettings::with_crate(self : TypeSpaceSettings, crate_name : String, version : CrateVers, rename? : String) -> TypeSpaceSettingsfn TypeSpaceSettings::with_derive(self : TypeSpaceSettings, derive_name : String) -> TypeSpaceSettingsfn TypeSpaceSettings::with_map_type(self : TypeSpaceSettings, map_type : String) -> TypeSpaceSettingsfn TypeSpaceSettings::with_patch(self : TypeSpaceSettings, type_name : String, patch : TypeSpacePatch) -> TypeSpaceSettingsfn TypeSpaceSettings::with_replacement(self : TypeSpaceSettings, type_name : String, replace_type : String, impls : Array[TypeSpaceImpl]) -> TypeSpaceSettingsfn TypeSpaceSettings::with_struct_builder(self : TypeSpaceSettings, struct_builder : Bool) -> TypeSpaceSettingsfn TypeSpaceSettings::with_type_mod(self : TypeSpaceSettings, type_mod : String) -> TypeSpaceSettingsfn TypeSpaceSettings::with_unknown_crates(self : TypeSpaceSettings, policy : UnknownPolicy) -> TypeSpaceSettingspub(all) struct Variant {
raw_name : String
ident_name : String?
description : String?
details : VariantDetails
} derive(Eq, Debug)fn accept_as_ident(ident : String) -> BoolInstall
Download zipGenerate Rust and MoonBit types from JSON Schema (port of oxidecomputer/typify)
Dependencies