add traits everywhere/make "required" fixes/add ec2_query_name/json_name

This commit is contained in:
Emil Lerch 2021-05-29 21:03:45 -07:00
parent c5bf148856
commit f997907bf1
Signed by: lobo
GPG Key ID: A7B62D657EF764F8
2 changed files with 72 additions and 37 deletions

View File

@ -135,7 +135,7 @@ fn generateOperation(allocator: *std.mem.Allocator, operation: smithy.ShapeInfo,
try writer.print(" action_name: []const u8 = \"{s}\",\n", .{operation.name});
_ = try writer.write(" Request: type = ");
if (operation.shape.operation.input) |member| {
try generateTypeFor(allocator, member, shapes, writer, " ", true, &type_stack);
try generateTypeFor(allocator, member, shapes, writer, " ", false, &type_stack);
} else _ = try writer.write("struct {}"); // we want to maintain consistency with other ops
_ = try writer.write(",\n");
_ = try writer.write(" Response: type = ");
@ -210,38 +210,37 @@ fn generateTypeFor(allocator: *std.mem.Allocator, shape_id: []const u8, shapes:
}
try type_stack.append(&shape_info);
switch (shape) {
.structure => try generateComplexTypeFor(allocator, shape.structure.members, "struct", shapes, writer, prefix, all_required, type_stack),
.uniontype => try generateComplexTypeFor(allocator, shape.uniontype.members, "union", shapes, writer, prefix, all_required, type_stack),
.string => _ = try writer.write("[]const u8"),
.integer => _ = try writer.write("i64"),
.list => {
.structure => |s| try generateComplexTypeFor(allocator, shape.structure.members, "struct", shapes, writer, prefix, all_required, type_stack),
.uniontype => |s| try generateComplexTypeFor(allocator, shape.uniontype.members, "union", shapes, writer, prefix, all_required, type_stack),
.string => |s| try generateSimpleTypeFor(s, "[]const u8", writer, all_required),
.integer => |s| try generateSimpleTypeFor(s, "i64", writer, all_required),
.list => |s| {
_ = try writer.write("[]");
try generateTypeFor(allocator, shape.list.member_target, shapes, writer, prefix, all_required, type_stack);
},
.set => {
.set => |s| {
_ = try writer.write("[]");
try generateTypeFor(allocator, shape.set.member_target, shapes, writer, prefix, all_required, type_stack);
},
.timestamp => _ = try writer.write("i64"),
.blob => _ = try writer.write("[]const u8"),
.boolean => _ = try writer.write("bool"),
.double => _ = try writer.write("f64"),
.float => _ = try writer.write("f32"),
.long => _ = try writer.write("i64"),
.timestamp => |s| try generateSimpleTypeFor(s, "i64", writer, all_required),
.blob => |s| try generateSimpleTypeFor(s, "[]const u8", writer, all_required),
.boolean => |s| try generateSimpleTypeFor(s, "bool", writer, all_required),
.double => |s| try generateSimpleTypeFor(s, "f64", writer, all_required),
.float => |s| try generateSimpleTypeFor(s, "f32", writer, all_required),
.long => |s| try generateSimpleTypeFor(s, "i64", writer, all_required),
.map => {
_ = try writer.write("[]struct {\n");
const new_prefix = try std.fmt.allocPrint(allocator, " {s}", .{prefix});
defer allocator.free(new_prefix);
try writer.print("{s} key: ", .{prefix});
// this doesn't have traits, but I expect it will
// if (!all_required) try writeOptional(shape.map.traits, writer, null);
if (!all_required) try writeOptional(shape.map.traits, writer, null);
try generateTypeFor(allocator, shape.map.key, shapes, writer, prefix, all_required, type_stack);
// if (!all_required) try writeOptional(shape.map.traits, writer, " = null");
if (!all_required) try writeOptional(shape.map.traits, writer, " = null");
_ = try writer.write(",\n");
try writer.print("{s} value: ", .{prefix});
// if (!all_required) try writeOptional(shape.map.traits, writer, null);
if (!all_required) try writeOptional(shape.map.traits, writer, null);
try generateTypeFor(allocator, shape.map.key, shapes, writer, prefix, all_required, type_stack);
// if (!all_required) try writeOptional(shape.map.traits, writer, " = null");
if (!all_required) try writeOptional(shape.map.traits, writer, " = null");
_ = try writer.write(",\n");
_ = try writer.write(prefix);
_ = try writer.write("}");
@ -255,9 +254,14 @@ fn generateTypeFor(allocator: *std.mem.Allocator, shape_id: []const u8, shapes:
_ = type_stack.pop();
}
fn generateSimpleTypeFor(shape: anytype, type_name: []const u8, writer: anytype, all_required: bool) !void {
_ = try writer.write(type_name); // This had required stuff but the problem was elsewhere. Better to leave as function just in case
}
fn generateComplexTypeFor(allocator: *std.mem.Allocator, members: []smithy.TypeMember, type_type_name: []const u8, shapes: anytype, writer: anytype, prefix: []const u8, all_required: bool, type_stack: anytype) anyerror!void {
// prolog. We'll rely on caller to get the spacing correct here
_ = try writer.write("struct {\n");
_ = try writer.write(type_type_name);
_ = try writer.write(" {\n");
for (members) |member| {
const new_prefix = try std.fmt.allocPrint(allocator, " {s}", .{prefix});
defer allocator.free(new_prefix);
@ -278,13 +282,14 @@ fn generateComplexTypeFor(allocator: *std.mem.Allocator, members: []smithy.TypeM
fn writeOptional(traits: ?[]smithy.Trait, writer: anytype, value: ?[]const u8) !void {
if (traits) |ts| {
for (ts) |t|
if (t == smithy.TraitType.required) return;
// not required
if (value) |v| {
_ = try writer.write(v);
} else
_ = try writer.write("?");
if (t == .required) return;
}
// not required
if (value) |v| {
_ = try writer.write(v);
} else
_ = try writer.write("?");
}
fn camelCase(allocator: *std.mem.Allocator, name: []const u8) ![]const u8 {
const first_letter = name[0] + ('a' - 'A');

View File

@ -59,6 +59,8 @@ pub const TraitType = enum {
aws_api_service,
aws_auth_sigv4,
aws_protocol,
ec2_query_name,
json_name,
required,
documentation,
pattern,
@ -79,6 +81,8 @@ pub const Trait = union(TraitType) {
name: []const u8,
},
aws_protocol: AwsProtocol,
ec2_query_name: []const u8,
json_name: []const u8,
required: struct {},
documentation: []const u8,
pattern: []const u8,
@ -126,7 +130,7 @@ pub const TypeMember = struct {
traits: []Trait,
};
const Shape = union(ShapeType) {
blob: struct {},
blob: TraitsOnly,
boolean: TraitsOnly,
string: TraitsOnly,
byte: TraitsOnly,
@ -138,23 +142,28 @@ const Shape = union(ShapeType) {
bigInteger: TraitsOnly,
bigDecimal: TraitsOnly,
timestamp: TraitsOnly,
document: struct {},
member: struct {},
document: TraitsOnly,
member: TraitsOnly,
list: struct {
member_target: []const u8,
traits: []Trait,
},
set: struct {
member_target: []const u8,
traits: []Trait,
},
map: struct {
key: []const u8,
value: []const u8,
traits: []Trait,
},
structure: struct {
members: []TypeMember,
traits: []Trait,
},
uniontype: struct {
members: []TypeMember,
traits: []Trait,
},
service: struct {
version: []const u8,
@ -168,7 +177,7 @@ const Shape = union(ShapeType) {
errors: ?[][]const u8,
traits: []Trait,
},
resource: struct {},
resource: TraitsOnly,
};
// https://awslabs.github.io/smithy/1.0/spec/aws/index.html
@ -295,12 +304,14 @@ fn getShape(allocator: *std.mem.Allocator, shape: std.json.Value) SmithyParseErr
return Shape{
.structure = .{
.members = try parseMembers(allocator, shape.Object.get("members")),
.traits = try parseTraits(allocator, shape.Object.get("traits")),
},
};
if (std.mem.eql(u8, shape_type, "union"))
return Shape{
.uniontype = .{
.members = try parseMembers(allocator, shape.Object.get("members")),
.traits = try parseTraits(allocator, shape.Object.get("traits")),
},
};
if (std.mem.eql(u8, shape_type, "operation"))
@ -321,12 +332,14 @@ fn getShape(allocator: *std.mem.Allocator, shape: std.json.Value) SmithyParseErr
return Shape{
.list = .{
.member_target = shape.Object.get("member").?.Object.get("target").?.String,
.traits = try parseTraits(allocator, shape.Object.get("traits")),
},
};
if (std.mem.eql(u8, shape_type, "set"))
return Shape{
.set = .{
.member_target = shape.Object.get("member").?.Object.get("target").?.String,
.traits = try parseTraits(allocator, shape.Object.get("traits")),
},
};
if (std.mem.eql(u8, shape_type, "map"))
@ -334,6 +347,7 @@ fn getShape(allocator: *std.mem.Allocator, shape: std.json.Value) SmithyParseErr
.map = .{
.key = shape.Object.get("key").?.Object.get("target").?.String,
.value = shape.Object.get("value").?.Object.get("target").?.String,
.traits = try parseTraits(allocator, shape.Object.get("traits")),
},
};
if (std.mem.eql(u8, shape_type, "string"))
@ -356,12 +370,16 @@ fn getShape(allocator: *std.mem.Allocator, shape: std.json.Value) SmithyParseErr
return Shape{ .bigDecimal = try parseTraitsOnly(allocator, shape) };
if (std.mem.eql(u8, shape_type, "boolean"))
return Shape{ .boolean = try parseTraitsOnly(allocator, shape) };
if (std.mem.eql(u8, shape_type, "blob")) return Shape{ .blob = .{} };
if (std.mem.eql(u8, shape_type, "blob"))
return Shape{ .blob = try parseTraitsOnly(allocator, shape) };
if (std.mem.eql(u8, shape_type, "timestamp"))
return Shape{ .timestamp = try parseTraitsOnly(allocator, shape) };
if (std.mem.eql(u8, shape_type, "document")) return Shape{ .document = .{} };
if (std.mem.eql(u8, shape_type, "member")) return Shape{ .member = .{} };
if (std.mem.eql(u8, shape_type, "resource")) return Shape{ .resource = .{} };
if (std.mem.eql(u8, shape_type, "document"))
return Shape{ .document = try parseTraitsOnly(allocator, shape) };
if (std.mem.eql(u8, shape_type, "member"))
return Shape{ .member = try parseTraitsOnly(allocator, shape) };
if (std.mem.eql(u8, shape_type, "resource"))
return Shape{ .resource = try parseTraitsOnly(allocator, shape) };
std.debug.print("Invalid Type: {s}", .{shape_type});
return SmithyParseError.InvalidType;
@ -483,6 +501,12 @@ fn getTrait(trait_type: []const u8, value: std.json.Value) SmithyParseError!?Tra
if (std.mem.eql(u8, trait_type, "smithy.api#pattern"))
return Trait{ .pattern = value.String };
if (std.mem.eql(u8, trait_type, "aws.protocols#ec2QueryName"))
return Trait{ .ec2_query_name = value.String };
if (std.mem.eql(u8, trait_type, "smithy.api#jsonName"))
return Trait{ .json_name = value.String };
// TODO: Maybe care about these traits?
if (std.mem.eql(u8, trait_type, "smithy.api#title"))
return null;
@ -490,22 +514,24 @@ fn getTrait(trait_type: []const u8, value: std.json.Value) SmithyParseError!?Tra
if (std.mem.eql(u8, trait_type, "smithy.api#xmlNamespace"))
return null;
// TODO: win argument with compiler to get this comptime
// aws.protocols#ec2QueryName looks important
const list =
\\aws.api#arnReference
\\aws.api#clientDiscoveredEndpoint
\\aws.api#clientEndpointDiscovery
\\aws.api#arn
\\aws.auth#unsignedPayload
\\aws.protocols#ec2QueryName
\\aws.iam#disableConditionKeyInference
\\smithy.api#auth
\\smithy.api#cors
\\smithy.api#deprecated
\\smithy.api#endpoint
\\smithy.api#enum
\\smithy.api#error
\\smithy.api#eventPayload
\\smithy.api#externalDocumentation
\\smithy.api#hostLabel
\\smithy.api#http
\\smithy.api#httpError
\\smithy.api#httpChecksumRequired
\\smithy.api#httpHeader
\\smithy.api#httpLabel
@ -516,12 +542,16 @@ fn getTrait(trait_type: []const u8, value: std.json.Value) SmithyParseError!?Tra
\\smithy.api#httpResponseCode
\\smithy.api#idempotencyToken
\\smithy.api#idempotent
\\smithy.api#jsonName
\\smithy.api#mediaType
\\smithy.api#noReplace
\\smithy.api#optionalAuth
\\smithy.api#paginated
\\smithy.api#readonly
\\smithy.api#references
\\smithy.api#requiresLength
\\smithy.api#retryable
\\smithy.api#sensitive
\\smithy.api#streaming
\\smithy.api#suppress
\\smithy.api#tags
\\smithy.api#timestampFormat
@ -537,7 +567,7 @@ fn getTrait(trait_type: []const u8, value: std.json.Value) SmithyParseError!?Tra
}
// Totally unknown type
std.debug.print("Invalid Trait Type: {s}\n", .{trait_type});
std.log.err("Invalid Trait Type: {s}", .{trait_type});
return null;
}
fn getOptionalNumber(value: std.json.Value, key: []const u8) ?f64 {