///|
fn export_traits(traits : Map[ShapeId, NodeValue]) -> Map[String, Json] {
let out : Map[String, Json] = Map([])
for id, value in traits {
out[id.to_string()] = @json.to_json(value)
}
out
}
///|
fn export_references(ids : Array[ShapeId]) -> Json {
Json::array(ids.map(id => reference(id.to_string())))
}
///|
fn export_reference_map(ids : Map[String, ShapeId]) -> Json {
let out : Map[String, Json] = Map([])
for name, id in ids {
out[name] = reference(id.to_string())
}
Json::object(out)
}
///|
fn Model::export_member(self : Model, id : ShapeId) -> Json raise BuildError {
guard self.shapes.get(id) is Some(shape) && shape.body is Member(target~) else {
raise InvalidShape(
"I expected a member shape at \{id} while serializing the model.",
)
}
let fields : Map[String, Json] = {
"target": Json::string(target.to_string()),
}
if !shape.traits.is_empty() {
fields["traits"] = Json::object(export_traits(shape.traits))
}
Json::object(fields)
}
///|
/// Serialize the assembled graph to a flattened JSON AST. Mixins remain
/// available as shape provenance in memory; their inherited contents are
/// explicit in this representation. The standard prelude is omitted by default.
pub fn Model::to_json_ast(
self : Model,
include_prelude~ : Bool = false,
) -> @syntax.JsonAst raise {
let shapes : Map[String, Json] = Map([])
for id, shape in self.shapes {
if id.member is Some(_) ||
(!include_prelude && shape.source.file == "") {
continue
}
let fields : Map[String, Json] = {
"type": Json::string(shape.body.keyword()),
}
match shape.body {
Simple(_) => ()
Member(..) => continue
List(member_) => fields["member"] = self.export_member(member_)
Map(key~, value~) => {
fields["key"] = self.export_member(key)
fields["value"] = self.export_member(value)
}
Structure(members) | Union(members) | Enum(members) | IntEnum(members) => {
let ms : Map[String, Json] = Map([])
for member_ in members {
if member_.member is Some(name) {
ms[name] = self.export_member(member_)
}
}
fields["members"] = Json::object(ms)
}
Operation(input~, output~, errors~) => {
fields["input"] = reference(input.to_string())
fields["output"] = reference(output.to_string())
if !errors.is_empty() {
fields["errors"] = export_references(errors)
}
}
Service(version~, operations~, resources~, errors~, rename~) => {
fields["version"] = Json::string(version)
if !operations.is_empty() {
fields["operations"] = export_references(operations)
}
if !resources.is_empty() {
fields["resources"] = export_references(resources)
}
if !errors.is_empty() {
fields["errors"] = export_references(errors)
}
if !rename.is_empty() {
let names : Map[String, Json] = Map([])
for id, name in rename {
names[id.to_string()] = Json::string(name)
}
fields["rename"] = Json::object(names)
}
}
Resource(
identifiers~,
properties~,
create~,
put~,
read~,
update~,
delete~,
list~,
operations~,
collectionOperations~,
resources~
) => {
if !identifiers.is_empty() {
fields["identifiers"] = export_reference_map(identifiers)
}
if !properties.is_empty() {
fields["properties"] = export_reference_map(properties)
}
for
(key, value) in [
("create", create),
("put", put),
("read", read),
("update", update),
("delete", delete),
("list", list),
] {
if value is Some(id) {
fields[key] = reference(id.to_string())
}
}
if !operations.is_empty() {
fields["operations"] = export_references(operations)
}
if !collectionOperations.is_empty() {
fields["collectionOperations"] = export_references(
collectionOperations,
)
}
if !resources.is_empty() {
fields["resources"] = export_references(resources)
}
}
}
if !shape.traits.is_empty() {
fields["traits"] = Json::object(export_traits(shape.traits))
}
shapes[id.to_string()] = Json::object(fields)
}
let fields : Map[String, Json] = {
"smithy": "2.0",
"shapes": Json::object(shapes),
}
if !self.metadata.is_empty() {
let metadata : Map[String, Json] = Map([])
for key, value in self.metadata {
metadata[key] = @json.to_json(value)
}
fields["metadata"] = Json::object(metadata)
}
@syntax.decode_json_ast(Json::object(fields))
}