Sign in

    #Smithy JSON AST

    Typed records and a JSON codec for the Smithy JSON AST. The package covers every shape kind, legacy set, member traits, mixins, service renames, resource properties and separate apply entries.

    Import moonrockz/smithy-syntax/json_ast, or use the root facade's JsonAst, parse_json_ast, decode_json_ast and encode_json_ast.

    #Read and write a document

    ///|
    test {
    let document = @json_ast.parse(
    (
    #|{"smithy":"2.0","shapes":{"example.weather#CityName":{"type":"string"}}}
    ),
    )
    inspect(document.smithy, content="2.0")
    let shape = document.shapes.unwrap().get("example.weather#CityName").unwrap()
    inspect(shape.kind.keyword(), content="string")
    assert_eq(@json_ast.parse(@json_ast.stringify(document)), document)
    }

    decode accepts a core Json value and raises @json.JsonDecodeError. parse accepts text and can also raise core @json.ParseError for invalid JSON or excessive nesting. Decode errors carry a JSON Pointer, such as /shapes/example.weather#Names/member/target. The records JsonAst, JsonShape, JsonMember and JsonReference also implement core FromJson and ToJson.

    #Construct a document

    ///|
    test {
    let names = @json_ast.JsonShape::new(
    List(Some(@json_ast.JsonMember::new("smithy.api#String"))),
    )
    let document = @json_ast.JsonAst::new(shapes={
    "example.weather#Names": names,
    })
    assert_eq(@json_ast.decode(@json_ast.encode(document)), document)
    }

    JsonShape contains common traits and mixins, plus a JsonShapeKind with typed shape-specific fields. JsonOperation, JsonService and JsonResource hold those shapes' properties. Constructors default optional fields to absent. JsonAst::new defaults the specification version to 2.0. The encoder trusts caller-built records; callers must supply valid IDs and leave mixins absent on an Apply entry.

    #Preservation and validation

    • Absent fields stay absent. Explicit empty maps and arrays stay present. Explicit null is rejected for structural fields; metadata and trait values can contain any JSON value, including null.
    • Object maps retain insertion order, including the order of members. Encoding can rearrange a shape's fixed properties and changes whitespace and string escaping. This is a document codec, without source spans or CST.
    • parse preserves every numeric token's spelling, including long decimals, large integers, signed zero and exponents beyond Double's range. It first validates with core JSON, then rebuilds values with an explicit stack to retain number representations. Duplicate object keys follow core JSON's last-key-wins behavior.
    • decode retains the numeric representations present in its Json input. It cannot recover precision already lost by another parser. Use parse when reading Smithy JSON text. Core Json equality compares numbers as Doubles; use numeric representations or encoded text when checking exact precision.
    • The decoder checks property types, required smithy, type and target fields, absolute ID syntax, member names and service rename names. Unknown properties are errors, including properties belonging to another shape kind. References permit target only; members permit target and traits.
    • Model validation belongs to the semantic loader. This includes version support, reference resolution, target kinds, case-insensitive member collisions, mixin expansion, trait semantics and model merging. Collection members, map keys/values, named members and service versions may be absent because mixins can supply them. The codec preserves the version string and accepts legacy set without deciding whether a model's version allows it.

    The unit tests cover every shape kind, malformed documents, exact numbers, deep nesting and generated inputs. tests/features/json-ast.feature is the acceptance contract. The compatibility suite round trips all 71 vendored reference documents with no exclusions. tests/tck/TCK_JSON_SHA records the upstream commit; refresh them with mise run tck:vendor:json -- <git-ref>.

    JsonAst

    pub(all) struct JsonAst {
    smithy : String
    metadata : Map[String, Json]?
    shapes : Map[String, JsonShape]?
    } derive(Eq,
    Debug
    )

    A Smithy JSON AST document. Optional fields distinguish absence from an explicitly empty object. Metadata and trait values retain core JSON number representations, including integers beyond Double's exact range.
    impl ToJson for JsonAst

    JsonAst::new

    fn JsonAst::new(smithy? : String, metadata? : Map[String, Json], shapes? : Map[String, JsonShape]) -> JsonAst

    Construct a document, defaulting to Smithy 2.0. Omitted maps stay absent.

    JsonMember

    pub(all) struct JsonMember {
    target : String
    traits : Map[String, Json]?
    } derive(Eq,
    Debug
    )

    A member definition with an absolute target and optional applied traits.

    JsonMember::new

    fn JsonMember::new(target : String, traits? : Map[String, Json]) -> JsonMember

    Construct a member with optional applied traits.

    JsonOperation

    pub(all) struct JsonOperation {
    input : JsonReference?
    output : JsonReference?
    errors : Array[JsonReference]?
    } derive(Eq,
    Debug
    )

    An operation's references. Mixins and traits live on the containing shape.

    JsonOperation::new

    fn JsonOperation::new(input? : JsonReference, output? : JsonReference, errors? : Array[JsonReference]) -> JsonOperation

    Construct operation properties with absent references by default.

    JsonReference

    pub(all) struct JsonReference {
    target : String
    } derive(Eq,
    Debug
    )

    An absolute shape reference. Reference existence and target kinds are checked by the semantic loader, not by the JSON codec.

    JsonReference::new

    fn JsonReference::new(target : String) -> JsonReference

    Construct a reference. The decoder checks absolute ID syntax; the encoder trusts caller-built records and does not validate a semantic model.

    JsonResource

    pub(all) struct JsonResource {
    identifiers : Map[String, JsonReference]?
    properties : Map[String, JsonReference]?
    create : JsonReference?
    put : JsonReference?
    read : JsonReference?
    update : JsonReference?
    delete : JsonReference?
    list : JsonReference?
    operations : Array[JsonReference]?
    collectionOperations : Array[JsonReference]?
    resources : Array[JsonReference]?
    } derive(Eq,
    Debug
    )

    A resource's properties. Field spelling follows the Smithy JSON AST.

    JsonResource::new

    fn JsonResource::new(identifiers? : Map[String, JsonReference], properties? : Map[String, JsonReference], create? : JsonReference, put? : JsonReference, read? : JsonReference, update? : JsonReference, delete? : JsonReference, list? : JsonReference, operations? : Array[JsonReference], collectionOperations? : Array[JsonReference], resources? : Array[JsonReference]) -> JsonResource

    Construct resource properties with absent fields by default.

    JsonService

    pub(all) struct JsonService {
    version : String?
    operations : Array[JsonReference]?
    resources : Array[JsonReference]?
    errors : Array[JsonReference]?
    rename : Map[String, String]?
    } derive(Eq,
    Debug
    )

    A service's properties. A version can be inherited from a mixin.

    JsonService::new

    fn JsonService::new(version? : String, operations? : Array[JsonReference], resources? : Array[JsonReference], errors? : Array[JsonReference], rename? : Map[String, String]) -> JsonService

    Construct service properties with absent fields by default.

    JsonShape

    pub(all) struct JsonShape {
    kind : JsonShapeKind
    traits : Map[String, Json]?
    mixins : Array[JsonReference]?
    } derive(Eq,
    Debug
    )

    A shape definition, or an apply entry. Apply permits traits only; decoding rejects a mixins property on an apply entry.
    impl ToJson for JsonShape

    JsonShape::new

    fn JsonShape::new(kind : JsonShapeKind, traits? : Map[String, Json], mixins? : Array[JsonReference]) -> JsonShape

    Construct a shape. An Apply entry must leave mixins absent.

    JsonShapeKind

    pub(all) enum JsonShapeKind {
    Simple(
    SimpleType
    )
    List(JsonMember?)
    Set(JsonMember?)
    Map(key~ : JsonMember?, value~ : JsonMember?)
    Structure(Map[String, JsonMember]?)
    Union(Map[String, JsonMember]?)
    Enum(Map[String, JsonMember]?)
    IntEnum(Map[String, JsonMember]?)
    Operation(JsonOperation)
    Service(JsonService)
    Resource(JsonResource)
    Apply
    } derive(Eq,
    Debug
    )

    Shape-specific JSON fields. Collections and named-member shapes can omit members that a mixin supplies. Required members, nonempty unions/enums and other model constraints are the semantic loader's responsibility.

    JsonShapeKind::keyword

    fn JsonShapeKind::keyword(self : JsonShapeKind) -> String

    The Smithy JSON AST type discriminator.

    decode

    Decode a core JSON value. Errors carry a JSON Pointer to the bad field.

    encode

    fn encode(document : JsonAst) -> Json

    Encode a typed document, omitting absent fields and preserving explicit empty objects/arrays. Object order and whitespace are not source fidelity.

    parse

    fn parse(text : String) -> JsonAst raise

    Parse JSON text and decode its document. JSON syntax errors and AST structure errors retain their standard core error types. The JSON parser bounds nesting before decoding; this codec does not recurse through values.

    stringify

    fn stringify(document : JsonAst, indent? : Int) -> String

    Encode as JSON text. Core JSON retains parsed number spellings.

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io