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.print(" action_name: []const u8 = \"{s}\",\n", .{operation.name});
_ = try writer.write(" Request: type = "); _ = try writer.write(" Request: type = ");
if (operation.shape.operation.input) |member| { 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 } else _ = try writer.write("struct {}"); // we want to maintain consistency with other ops
_ = try writer.write(",\n"); _ = try writer.write(",\n");
_ = try writer.write(" Response: type = "); _ = 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); try type_stack.append(&shape_info);
switch (shape) { switch (shape) {
.structure => try generateComplexTypeFor(allocator, shape.structure.members, "struct", shapes, writer, prefix, all_required, type_stack), .structure => |s| 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), .uniontype => |s| try generateComplexTypeFor(allocator, shape.uniontype.members, "union", shapes, writer, prefix, all_required, type_stack),
.string => _ = try writer.write("[]const u8"), .string => |s| try generateSimpleTypeFor(s, "[]const u8", writer, all_required),
.integer => _ = try writer.write("i64"), .integer => |s| try generateSimpleTypeFor(s, "i64", writer, all_required),
.list => { .list => |s| {
_ = try writer.write("[]"); _ = try writer.write("[]");
try generateTypeFor(allocator, shape.list.member_target, shapes, writer, prefix, all_required, type_stack); try generateTypeFor(allocator, shape.list.member_target, shapes, writer, prefix, all_required, type_stack);
}, },
.set => { .set => |s| {
_ = try writer.write("[]"); _ = try writer.write("[]");
try generateTypeFor(allocator, shape.set.member_target, shapes, writer, prefix, all_required, type_stack); try generateTypeFor(allocator, shape.set.member_target, shapes, writer, prefix, all_required, type_stack);
}, },
.timestamp => _ = try writer.write("i64"), .timestamp => |s| try generateSimpleTypeFor(s, "i64", writer, all_required),
.blob => _ = try writer.write("[]const u8"), .blob => |s| try generateSimpleTypeFor(s, "[]const u8", writer, all_required),
.boolean => _ = try writer.write("bool"), .boolean => |s| try generateSimpleTypeFor(s, "bool", writer, all_required),
.double => _ = try writer.write("f64"), .double => |s| try generateSimpleTypeFor(s, "f64", writer, all_required),
.float => _ = try writer.write("f32"), .float => |s| try generateSimpleTypeFor(s, "f32", writer, all_required),
.long => _ = try writer.write("i64"), .long => |s| try generateSimpleTypeFor(s, "i64", writer, all_required),
.map => { .map => {
_ = try writer.write("[]struct {\n"); _ = try writer.write("[]struct {\n");
const new_prefix = try std.fmt.allocPrint(allocator, " {s}", .{prefix}); const new_prefix = try std.fmt.allocPrint(allocator, " {s}", .{prefix});
defer allocator.free(new_prefix); defer allocator.free(new_prefix);
try writer.print("{s} key: ", .{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); 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(",\n");
try writer.print("{s} value: ", .{prefix}); 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); 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(",\n");
_ = try writer.write(prefix); _ = try writer.write(prefix);
_ = try writer.write("}"); _ = try writer.write("}");
@ -255,9 +254,14 @@ fn generateTypeFor(allocator: *std.mem.Allocator, shape_id: []const u8, shapes:
_ = type_stack.pop(); _ = 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 { 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 // 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| { for (members) |member| {
const new_prefix = try std.fmt.allocPrint(allocator, " {s}", .{prefix}); const new_prefix = try std.fmt.allocPrint(allocator, " {s}", .{prefix});
defer allocator.free(new_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 { fn writeOptional(traits: ?[]smithy.Trait, writer: anytype, value: ?[]const u8) !void {
if (traits) |ts| { if (traits) |ts| {
for (ts) |t| for (ts) |t|
if (t == smithy.TraitType.required) return; if (t == .required) return;
}
// not required // not required
if (value) |v| { if (value) |v| {
_ = try writer.write(v); _ = try writer.write(v);
} else } else
_ = try writer.write("?"); _ = try writer.write("?");
}
} }
fn camelCase(allocator: *std.mem.Allocator, name: []const u8) ![]const u8 { fn camelCase(allocator: *std.mem.Allocator, name: []const u8) ![]const u8 {
const first_letter = name[0] + ('a' - 'A'); const first_letter = name[0] + ('a' - 'A');

View File

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