Compare commits

...

6 Commits

View File

@ -65,6 +65,14 @@ pub const Smithy = struct {
self.allocator.free(v.value); self.allocator.free(v.value);
self.allocator.free(v.traits); self.allocator.free(v.traits);
}, },
.@"enum" => |v| {
for (v.members) |m| self.allocator.free(m.traits);
self.allocator.free(v.members);
self.allocator.free(v.traits);
},
.unit => |v| {
self.allocator.free(v.traits);
},
} }
} }
self.allocator.free(self.shapes); self.allocator.free(self.shapes);
@ -98,20 +106,23 @@ pub const TraitType = enum {
http_payload, http_payload,
json_name, json_name,
xml_name, xml_name,
required, required, // required on the server
client_optional, // optional as far as the client is concerned
documentation, documentation,
pattern, pattern,
range, range,
length, length,
box, box,
sparse, sparse,
enum_value,
aws_query_error,
}; };
pub const Trait = union(TraitType) { pub const Trait = union(TraitType) {
aws_api_service: struct { aws_api_service: struct {
sdk_id: []const u8, sdk_id: []const u8,
arn_namespace: []const u8, arn_namespace: ?[]const u8,
cloudformation_name: []const u8, cloudformation_name: ?[]const u8,
cloudtrail_event_source: []const u8, cloudtrail_event_source: ?[]const u8,
endpoint_prefix: []const u8, endpoint_prefix: []const u8,
}, },
aws_auth_sigv4: struct { aws_auth_sigv4: struct {
@ -131,6 +142,7 @@ pub const Trait = union(TraitType) {
http_query: []const u8, http_query: []const u8,
http_payload: struct {}, http_payload: struct {},
required: struct {}, required: struct {},
client_optional: void,
documentation: []const u8, documentation: []const u8,
pattern: []const u8, pattern: []const u8,
range: struct { // most data is actually integers, but as some are floats, we'll use that here range: struct { // most data is actually integers, but as some are floats, we'll use that here
@ -143,6 +155,11 @@ pub const Trait = union(TraitType) {
}, },
box: struct {}, box: struct {},
sparse: struct {}, sparse: struct {},
enum_value: []const u8,
aws_query_error: struct {
http_response_code: i64,
code: []const u8,
},
}; };
const ShapeType = enum { const ShapeType = enum {
blob, blob,
@ -167,6 +184,8 @@ const ShapeType = enum {
service, service,
operation, operation,
resource, resource,
@"enum",
unit,
}; };
const TraitsOnly = struct { const TraitsOnly = struct {
traits: []Trait, traits: []Trait,
@ -225,6 +244,11 @@ const Shape = union(ShapeType) {
traits: []Trait, traits: []Trait,
}, },
resource: TraitsOnly, resource: TraitsOnly,
@"enum": struct {
members: []TypeMember,
traits: []Trait,
},
unit: TraitsOnly,
}; };
// https://awslabs.github.io/smithy/1.0/spec/aws/index.html // https://awslabs.github.io/smithy/1.0/spec/aws/index.html
@ -266,7 +290,10 @@ fn shapes(allocator: std.mem.Allocator, map: anytype) ![]ShapeInfo {
.namespace = id_info.namespace, .namespace = id_info.namespace,
.name = id_info.name, .name = id_info.name,
.member = id_info.member, .member = id_info.member,
.shape = try getShape(allocator, kv.value_ptr.*), .shape = getShape(allocator, kv.value_ptr.*) catch |e| {
std.log.err("Caught error parsing shape with name {s}: {}", .{ id_info.name, e });
return e;
},
}); });
} }
// This seems to be a synonym for the simple type "string" // This seems to be a synonym for the simple type "string"
@ -328,6 +355,121 @@ fn shapes(allocator: std.mem.Allocator, map: anytype) ![]ShapeInfo {
}, },
}, },
}); });
try list.append(.{
.id = "smithy.api#Blob",
.namespace = "smithy.api",
.name = "Blob",
.member = null,
.shape = Shape{
.blob = .{
.traits = &.{},
},
},
});
try list.append(.{
.id = "smithy.api#Unit",
.namespace = "smithy.api",
.name = "Unit",
.member = null,
.shape = Shape{
.unit = .{
.traits = &.{},
},
},
});
try list.append(.{
.id = "smithy.api#Long",
.namespace = "smithy.api",
.name = "Long",
.member = null,
.shape = Shape{
.long = .{
.traits = &.{},
},
},
});
try list.append(.{
.id = "smithy.api#Float",
.namespace = "smithy.api",
.name = "Float",
.member = null,
.shape = Shape{
.float = .{
.traits = &.{},
},
},
});
try list.append(.{
.id = "smithy.api#Document",
.namespace = "smithy.api",
.name = "Document",
.member = null,
.shape = Shape{
.document = .{
.traits = &.{},
},
},
});
// These "Primitive" versions only appear to differ in that they have defaults
// defined. Not currently handled:
// byte PrimitiveByte
// short PrimitiveShort
try list.append(.{
.id = "smithy.api#PrimitiveBoolean",
.namespace = "smithy.api",
.name = "PrimitiveBoolean",
.member = null,
.shape = Shape{
.boolean = .{
.traits = &.{},
},
},
});
try list.append(.{
.id = "smithy.api#PrimitiveInteger",
.namespace = "smithy.api",
.name = "PrimitiveInteger",
.member = null,
.shape = Shape{
.integer = .{
.traits = &.{},
},
},
});
try list.append(.{
.id = "smithy.api#PrimitiveDouble",
.namespace = "smithy.api",
.name = "PrimitiveDouble",
.member = null,
.shape = Shape{
.double = .{
.traits = &.{},
},
},
});
try list.append(.{
.id = "smithy.api#PrimitiveLong",
.namespace = "smithy.api",
.name = "PrimitiveLong",
.member = null,
.shape = Shape{
.long = .{
.traits = &.{},
},
},
});
try list.append(.{
.id = "smithy.api#PrimitiveFloat",
.namespace = "smithy.api",
.name = "PrimitiveFloat",
.member = null,
.shape = Shape{
.float = .{
.traits = &.{},
},
},
});
return list.toOwnedSlice(); return list.toOwnedSlice();
} }
@ -426,6 +568,13 @@ fn getShape(allocator: std.mem.Allocator, shape: std.json.Value) SmithyParseErro
return Shape{ .member = try parseTraitsOnly(allocator, shape) }; return Shape{ .member = try parseTraitsOnly(allocator, shape) };
if (std.mem.eql(u8, shape_type, "resource")) if (std.mem.eql(u8, shape_type, "resource"))
return Shape{ .resource = try parseTraitsOnly(allocator, shape) }; return Shape{ .resource = try parseTraitsOnly(allocator, shape) };
if (std.mem.eql(u8, shape_type, "enum"))
return Shape{
.@"enum" = .{
.members = try parseMembers(allocator, shape.object.get("members")),
.traits = try parseTraits(allocator, shape.object.get("traits")),
},
};
std.debug.print("Invalid Type: {s}", .{shape_type}); std.debug.print("Invalid Type: {s}", .{shape_type});
return SmithyParseError.InvalidType; return SmithyParseError.InvalidType;
@ -486,9 +635,9 @@ fn getTrait(trait_type: []const u8, value: std.json.Value) SmithyParseError!?Tra
return Trait{ return Trait{
.aws_api_service = .{ .aws_api_service = .{
.sdk_id = value.object.get("sdkId").?.string, .sdk_id = value.object.get("sdkId").?.string,
.arn_namespace = value.object.get("arnNamespace").?.string, .arn_namespace = if (value.object.get("arnNamespace")) |a| a.string else null,
.cloudformation_name = value.object.get("cloudFormationName").?.string, .cloudformation_name = if (value.object.get("cloudFormationName")) |n| n.string else null,
.cloudtrail_event_source = value.object.get("cloudTrailEventSource").?.string, .cloudtrail_event_source = if (value.object.get("cloudTrailEventSource")) |s| s.string else null,
// what good is a service without an endpoint? I don't know - ask amp // what good is a service without an endpoint? I don't know - ask amp
.endpoint_prefix = if (value.object.get("endpointPrefix")) |endpoint| endpoint.string else "", .endpoint_prefix = if (value.object.get("endpointPrefix")) |endpoint| endpoint.string else "",
}, },
@ -501,6 +650,8 @@ fn getTrait(trait_type: []const u8, value: std.json.Value) SmithyParseError!?Tra
}; };
if (std.mem.eql(u8, trait_type, "smithy.api#required")) if (std.mem.eql(u8, trait_type, "smithy.api#required"))
return Trait{ .required = .{} }; return Trait{ .required = .{} };
if (std.mem.eql(u8, trait_type, "smithy.api#clientOptional"))
return Trait{ .client_optional = {} };
if (std.mem.eql(u8, trait_type, "smithy.api#sparse")) if (std.mem.eql(u8, trait_type, "smithy.api#sparse"))
return Trait{ .sparse = .{} }; return Trait{ .sparse = .{} };
if (std.mem.eql(u8, trait_type, "smithy.api#box")) if (std.mem.eql(u8, trait_type, "smithy.api#box"))
@ -565,6 +716,14 @@ fn getTrait(trait_type: []const u8, value: std.json.Value) SmithyParseError!?Tra
.code = code, .code = code,
} }; } };
} }
if (std.mem.eql(u8, trait_type, "aws.protocols#awsQueryError")) {
return Trait{
.aws_query_error = .{
.code = value.object.get("code").?.string, // code is required
.http_response_code = value.object.get("httpResponseCode").?.integer,
},
};
}
if (std.mem.eql(u8, trait_type, "smithy.api#jsonName")) if (std.mem.eql(u8, trait_type, "smithy.api#jsonName"))
return Trait{ .json_name = value.string }; return Trait{ .json_name = value.string };
if (std.mem.eql(u8, trait_type, "smithy.api#xmlName")) if (std.mem.eql(u8, trait_type, "smithy.api#xmlName"))
@ -582,6 +741,10 @@ fn getTrait(trait_type: []const u8, value: std.json.Value) SmithyParseError!?Tra
if (std.mem.eql(u8, trait_type, "smithy.api#xmlNamespace")) if (std.mem.eql(u8, trait_type, "smithy.api#xmlNamespace"))
return null; return null;
if (std.mem.eql(u8, trait_type, "smithy.api#enumValue"))
return Trait{ .enum_value = value.string };
// TODO: win argument with compiler to get this comptime // TODO: win argument with compiler to get this comptime
const list = const list =
\\aws.api#arnReference \\aws.api#arnReference
@ -623,7 +786,45 @@ fn getTrait(trait_type: []const u8, value: std.json.Value) SmithyParseError!?Tra
\\smithy.api#xmlAttribute \\smithy.api#xmlAttribute
\\smithy.api#xmlFlattened \\smithy.api#xmlFlattened
\\smithy.waiters#waitable \\smithy.waiters#waitable
; \\smithy.rules#endpointTests
\\smithy.api#input
\\smithy.api#output
\\smithy.api#default
\\smithy.api#examples
\\smithy.api#uniqueItems
\\smithy.api#addedDefault
\\smithy.api#resourceIdentifier
\\smithy.api#unstable
\\smithy.api#property
\\smithy.api#notProperty
\\smithy.api#recommended
\\smithy.api#httpBearerAuth
\\smithy.api#nestedProperties
\\smithy.rules#endpointRuleSet
\\smithy.rules#contextParam
\\smithy.rules#clientContextParams
\\smithy.rules#staticContextParams
\\aws.cloudformation#cfnResource
\\aws.cloudformation#cfnMutability
\\aws.cloudformation#cfnExcludeProperty
\\aws.cloudformation#cfnAdditionalIdentifier
\\aws.iam#actionPermissionDescription
\\aws.iam#requiredActions
\\aws.iam#conditionKeys
\\aws.iam#iamResource
\\aws.iam#iamAction
\\aws.iam#supportedPrincipalTypes
\\aws.iam#defineConditionKeys
\\aws.iam#actionName
\\aws.api#data
\\aws.api#controlPlane
\\aws.api#dataPlane
\\aws.api#tagEnabled
\\aws.api#taggable
\\aws.protocols#awsQueryCompatible
\\aws.protocols#httpChecksum
\\aws.customizations#s3UnwrappedXmlOutput
; // NOTE: inputs/outputs are not used in AWS models, but default is and might be handy
var iterator = std.mem.split(u8, list, "\n"); var iterator = std.mem.split(u8, list, "\n");
while (iterator.next()) |known_but_unimplemented| { while (iterator.next()) |known_but_unimplemented| {
if (std.mem.eql(u8, trait_type, known_but_unimplemented)) if (std.mem.eql(u8, trait_type, known_but_unimplemented))