move to state parameter and index level rather than prefix
This also includes a small change to force output of mappings even if empty New zig correctly detects that without any field, we end up trying to use a constant that does not exist (this is in the generated code)
This commit is contained in:
parent
2d10c6e356
commit
0368c27c2c
|
@ -68,10 +68,9 @@ fn generateServices(allocator: *std.mem.Allocator, comptime _: []const u8, file:
|
|||
defer allocator.free(json);
|
||||
const model = try smithy.parse(allocator, json);
|
||||
defer model.deinit();
|
||||
const ShapeInfo = @TypeOf(model.shapes[0]); // assume we have at least one shape
|
||||
var shapes = std.StringHashMap(ShapeInfo).init(allocator);
|
||||
var shapes = std.StringHashMap(smithy.ShapeInfo).init(allocator);
|
||||
defer shapes.deinit();
|
||||
var services = std.ArrayList(ShapeInfo).init(allocator);
|
||||
var services = std.ArrayList(smithy.ShapeInfo).init(allocator);
|
||||
defer services.deinit();
|
||||
for (model.shapes) |shape| {
|
||||
try shapes.put(shape.id, shape);
|
||||
|
@ -131,7 +130,7 @@ fn generateServices(allocator: *std.mem.Allocator, comptime _: []const u8, file:
|
|||
|
||||
// Operations
|
||||
for (service.shape.service.operations) |op|
|
||||
try generateOperation(allocator, shapes.get(op).?, shapes, writer, constant_name);
|
||||
try generateOperation(allocator, shapes.get(op).?, shapes, writer);
|
||||
}
|
||||
return constant_names.toOwnedSlice();
|
||||
}
|
||||
|
@ -155,67 +154,115 @@ fn constantName(allocator: *std.mem.Allocator, id: []const u8) ![]const u8 {
|
|||
// Not a special case - just snake it
|
||||
return try snake.fromPascalCase(allocator, id);
|
||||
}
|
||||
fn generateOperation(allocator: *std.mem.Allocator, operation: smithy.ShapeInfo, shapes: anytype, writer: anytype, service: []const u8) !void {
|
||||
|
||||
const GenerationState = struct {
|
||||
type_stack: *std.ArrayList(*const smithy.ShapeInfo),
|
||||
map_fields: *std.StringArrayHashMap(std.ArrayList([]const u8)),
|
||||
allocator: *std.mem.Allocator,
|
||||
indent_level: u64,
|
||||
all_required: bool,
|
||||
};
|
||||
|
||||
fn outputIndent(state: GenerationState, writer: anytype) !void {
|
||||
const n_chars = 4 * state.indent_level;
|
||||
try writer.writeByteNTimes(' ', n_chars);
|
||||
}
|
||||
fn generateOperation(allocator: *std.mem.Allocator, operation: smithy.ShapeInfo, shapes: std.StringHashMap(smithy.ShapeInfo), writer: anytype) !void {
|
||||
const snake_case_name = try snake.fromPascalCase(allocator, operation.name);
|
||||
defer allocator.free(snake_case_name);
|
||||
|
||||
const prefix = " ";
|
||||
var type_stack = std.ArrayList(*const smithy.ShapeInfo).init(allocator);
|
||||
defer type_stack.deinit();
|
||||
var map_fields = std.StringArrayHashMap(std.ArrayList([]const u8)).init(allocator);
|
||||
defer {
|
||||
for (map_fields.values()) |v|
|
||||
v.deinit();
|
||||
map_fields.deinit();
|
||||
}
|
||||
const state = GenerationState{
|
||||
.type_stack = &type_stack,
|
||||
.map_fields = &map_fields,
|
||||
.allocator = allocator,
|
||||
.indent_level = 1,
|
||||
.all_required = false,
|
||||
};
|
||||
var child_state = state;
|
||||
child_state.indent_level += 1;
|
||||
// indent should start at 4 spaces here
|
||||
const operation_name = avoidReserved(snake_case_name);
|
||||
try writer.print("pub const {s}: struct ", .{operation_name});
|
||||
_ = try writer.write("{\n");
|
||||
for (operation.shape.operation.traits) |trait| {
|
||||
if (trait == .http) {
|
||||
try outputIndent(state, writer);
|
||||
_ = try writer.write("pub const http_config = .{\n");
|
||||
try outputIndent(child_state, writer);
|
||||
try writer.print(".method = \"{s}\",\n", .{trait.http.method});
|
||||
try outputIndent(child_state, writer);
|
||||
try writer.print(".uri = \"{s}\",\n", .{trait.http.uri});
|
||||
try outputIndent(child_state, writer);
|
||||
try writer.print(".success_code = {d},\n", .{trait.http.code});
|
||||
try outputIndent(state, writer);
|
||||
_ = try writer.write("};\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
try outputIndent(state, writer);
|
||||
try writer.print("action_name: []const u8 = \"{s}\",\n", .{operation.name});
|
||||
try outputIndent(state, writer);
|
||||
_ = try writer.write("Request: type = ");
|
||||
if (operation.shape.operation.input) |member| {
|
||||
try generateTypeFor(allocator, member, shapes, writer, prefix, false, &type_stack, false);
|
||||
try generateTypeFor(member, shapes, writer, state, false);
|
||||
_ = try writer.write("\n");
|
||||
try generateMetadataFunction(service, operation_name, prefix, writer);
|
||||
try generateMetadataFunction(operation_name, state, writer);
|
||||
} else {
|
||||
_ = try writer.write("struct {\n");
|
||||
try generateMetadataFunction(service, operation_name, prefix, writer);
|
||||
try generateMetadataFunction(operation_name, state, writer);
|
||||
}
|
||||
_ = try writer.write(",\n");
|
||||
try outputIndent(state, writer);
|
||||
_ = try writer.write("Response: type = ");
|
||||
if (operation.shape.operation.output) |member| {
|
||||
try generateTypeFor(allocator, member, shapes, writer, " ", false, &type_stack, true);
|
||||
try generateTypeFor(member, shapes, writer, state, true);
|
||||
} else _ = try writer.write("struct {}"); // we want to maintain consistency with other ops
|
||||
_ = try writer.write(",\n");
|
||||
|
||||
if (operation.shape.operation.errors) |errors| {
|
||||
try outputIndent(state, writer);
|
||||
_ = try writer.write("ServiceError: type = error{\n");
|
||||
for (errors) |err| {
|
||||
const err_name = getErrorName(shapes.get(err).?.name); // need to remove "exception"
|
||||
try outputIndent(child_state, writer);
|
||||
try writer.print("{s},\n", .{err_name});
|
||||
}
|
||||
try outputIndent(state, writer);
|
||||
_ = try writer.write("},\n");
|
||||
}
|
||||
_ = try writer.write("} = .{};\n");
|
||||
}
|
||||
|
||||
fn generateMetadataFunction(_: []const u8, operation_name: []const u8, comptime prefix: []const u8, writer: anytype) !void {
|
||||
fn generateMetadataFunction(operation_name: []const u8, state: GenerationState, writer: anytype) !void {
|
||||
// TODO: Shove these lines in here, and also the else portion
|
||||
// pub fn metaInfo(self: @This()) struct { service: @TypeOf(sts), action: @TypeOf(sts.get_caller_identity) } {
|
||||
// return .{ .service = sts, .action = sts.get_caller_identity };
|
||||
// }
|
||||
// We want to add a short "get my parents" function into the response
|
||||
try writer.print("{s} ", .{prefix});
|
||||
var child_state = state;
|
||||
child_state.indent_level += 1;
|
||||
try outputIndent(child_state, writer);
|
||||
_ = try writer.write("pub fn metaInfo() struct { ");
|
||||
try writer.print("service_metadata: @TypeOf(service_metadata), action: @TypeOf({s})", .{operation_name});
|
||||
_ = try writer.write(" } {\n" ++ prefix ++ " return .{ .service_metadata = service_metadata, ");
|
||||
_ = try writer.write(" } {\n");
|
||||
child_state.indent_level += 1;
|
||||
try outputIndent(child_state, writer);
|
||||
_ = try writer.write("return .{ .service_metadata = service_metadata, ");
|
||||
try writer.print(".action = {s}", .{operation_name});
|
||||
_ = try writer.write(" };\n" ++ prefix ++ " }\n" ++ prefix ++ "}");
|
||||
_ = try writer.write(" };\n");
|
||||
child_state.indent_level -= 1;
|
||||
try outputIndent(child_state, writer);
|
||||
_ = try writer.write("}\n");
|
||||
try outputIndent(state, writer);
|
||||
try writer.writeByte('}');
|
||||
}
|
||||
fn getErrorName(err_name: []const u8) []const u8 {
|
||||
if (endsWith("Exception", err_name))
|
||||
|
@ -231,7 +278,7 @@ fn endsWith(item: []const u8, str: []const u8) bool {
|
|||
return std.mem.eql(u8, item, str[str.len - item.len ..]);
|
||||
}
|
||||
/// return type is anyerror!void as this is a recursive function, so the compiler cannot properly infer error types
|
||||
fn generateTypeFor(allocator: *std.mem.Allocator, shape_id: []const u8, shapes: anytype, writer: anytype, prefix: []const u8, all_required: bool, type_stack: anytype, end_structure: bool) anyerror!void {
|
||||
fn generateTypeFor(shape_id: []const u8, shapes: std.StringHashMap(smithy.ShapeInfo), writer: anytype, state: GenerationState, end_structure: bool) anyerror!void {
|
||||
if (shapes.get(shape_id) == null) {
|
||||
std.debug.print("Shape ID not found. This is most likely a bug. Shape ID: {s}\n", .{shape_id});
|
||||
return error.InvalidType;
|
||||
|
@ -242,7 +289,7 @@ fn generateTypeFor(allocator: *std.mem.Allocator, shape_id: []const u8, shapes:
|
|||
const shape = shape_info.shape;
|
||||
// Check for ourselves up the stack
|
||||
var self_occurences: u8 = 0;
|
||||
for (type_stack.items) |i| {
|
||||
for (state.type_stack.items) |i| {
|
||||
// NOTE: shapes.get isn't providing a consistent pointer - is it allocating each time?
|
||||
// we will therefore need to compare ids
|
||||
if (std.mem.eql(u8, i.*.id, shape_info.id))
|
||||
|
@ -264,60 +311,69 @@ fn generateTypeFor(allocator: *std.mem.Allocator, shape_id: []const u8, shapes:
|
|||
// type to properly reference. Realistically, AWS or the service
|
||||
// must be blocking deep recursion somewhere or this would be a great
|
||||
// DOS attack
|
||||
try generateSimpleTypeFor("nothing", "[]const u8", writer, all_required);
|
||||
try generateSimpleTypeFor("nothing", "[]const u8", writer);
|
||||
std.log.warn("Type cycle detected, limiting depth. Type: {s}", .{shape_id});
|
||||
// std.log.info(" Type stack:\n", .{});
|
||||
// for (type_stack.items) |i|
|
||||
// std.log.info(" {s}", .{i.*.id});
|
||||
return;
|
||||
}
|
||||
try type_stack.append(&shape_info);
|
||||
try state.type_stack.append(&shape_info);
|
||||
switch (shape) {
|
||||
.structure => {
|
||||
try generateComplexTypeFor(allocator, shape.structure.members, "struct", shapes, writer, prefix, all_required, type_stack);
|
||||
try generateComplexTypeFor(shape_id, shape.structure.members, "struct", shapes, writer, state);
|
||||
if (end_structure) {
|
||||
// epilog
|
||||
try writer.print("{s}", .{prefix});
|
||||
try outputIndent(state, writer);
|
||||
_ = try writer.write("}");
|
||||
}
|
||||
},
|
||||
.uniontype => {
|
||||
try generateComplexTypeFor(allocator, shape.uniontype.members, "union", shapes, writer, prefix, all_required, type_stack);
|
||||
try generateComplexTypeFor(shape_id, shape.uniontype.members, "union", shapes, writer, state);
|
||||
// epilog
|
||||
try writer.print("{s}", .{prefix});
|
||||
try outputIndent(state, writer);
|
||||
_ = try writer.write("}");
|
||||
},
|
||||
.string => |s| try generateSimpleTypeFor(s, "[]const u8", writer, all_required),
|
||||
.integer => |s| try generateSimpleTypeFor(s, "i64", writer, all_required),
|
||||
.string => |s| try generateSimpleTypeFor(s, "[]const u8", writer),
|
||||
.integer => |s| try generateSimpleTypeFor(s, "i64", writer),
|
||||
.list => {
|
||||
_ = try writer.write("[]");
|
||||
try generateTypeFor(allocator, shape.list.member_target, shapes, writer, prefix, all_required, type_stack, true);
|
||||
try generateTypeFor(shape.list.member_target, shapes, writer, state, true);
|
||||
},
|
||||
.set => {
|
||||
_ = try writer.write("[]");
|
||||
try generateTypeFor(allocator, shape.set.member_target, shapes, writer, prefix, all_required, type_stack, true);
|
||||
try generateTypeFor(shape.set.member_target, shapes, writer, state, true);
|
||||
},
|
||||
.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),
|
||||
.timestamp => |s| try generateSimpleTypeFor(s, "i64", writer),
|
||||
.blob => |s| try generateSimpleTypeFor(s, "[]const u8", writer),
|
||||
.boolean => |s| try generateSimpleTypeFor(s, "bool", writer),
|
||||
.double => |s| try generateSimpleTypeFor(s, "f64", writer),
|
||||
.float => |s| try generateSimpleTypeFor(s, "f32", writer),
|
||||
.long => |s| try generateSimpleTypeFor(s, "i64", writer),
|
||||
.map => {
|
||||
// TODO: We need this:
|
||||
//
|
||||
// pub fn jsonStringifyField(self: @This(), comptime field_name: []const u8, options: anytype, out_stream: anytype) !bool {
|
||||
// if (std.mem.eql(u8, "tags", field_name))
|
||||
// return try serializeMap(self.tags, self.jsonFieldNameFor("tags"), options, out_stream);
|
||||
// return false;
|
||||
// }
|
||||
_ = 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});
|
||||
if (!all_required) try writeOptional(shape.map.traits, writer, null);
|
||||
try generateTypeFor(allocator, shape.map.key, shapes, writer, prefix, all_required, type_stack, true);
|
||||
if (!all_required) try writeOptional(shape.map.traits, writer, " = null");
|
||||
var child_state = state;
|
||||
child_state.indent_level += 1;
|
||||
try outputIndent(child_state, writer);
|
||||
_ = try writer.write("key: ");
|
||||
try writeOptional(shape.map.traits, writer, null);
|
||||
try generateTypeFor(shape.map.key, shapes, writer, state, true);
|
||||
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);
|
||||
try generateTypeFor(allocator, shape.map.key, shapes, writer, prefix, all_required, type_stack, true);
|
||||
if (!all_required) try writeOptional(shape.map.traits, writer, " = null");
|
||||
try outputIndent(child_state, writer);
|
||||
_ = try writer.write("value: ");
|
||||
try writeOptional(shape.map.traits, writer, null);
|
||||
try generateTypeFor(shape.map.key, shapes, writer, state, true);
|
||||
try writeOptional(shape.map.traits, writer, " = null");
|
||||
_ = try writer.write(",\n");
|
||||
_ = try writer.write(prefix);
|
||||
try outputIndent(state, writer);
|
||||
_ = try writer.write("}");
|
||||
},
|
||||
else => {
|
||||
|
@ -326,25 +382,19 @@ fn generateTypeFor(allocator: *std.mem.Allocator, shape_id: []const u8, shapes:
|
|||
// return error{UnimplementedShapeType}.UnimplementedShapeType;
|
||||
},
|
||||
}
|
||||
_ = type_stack.pop();
|
||||
_ = state.type_stack.pop();
|
||||
}
|
||||
|
||||
// fn generateSimpleTypeFor(shape: anytype, type_name: []const u8, writer: anytype, _: bool) !void {
|
||||
fn generateSimpleTypeFor(_: anytype, type_name: []const u8, writer: anytype, all_required: bool) !void {
|
||||
// current compiler checks unused variables, but can't handle multiple unused
|
||||
// function parameters. We don't want to change the signature in case we need to work with
|
||||
// these in the future, so this stupid code is only here to trick the compiler
|
||||
if (all_required or !all_required)
|
||||
fn generateSimpleTypeFor(_: anytype, type_name: []const u8, writer: anytype) !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(shape_id: []const u8, members: []smithy.TypeMember, type_type_name: []const u8, shapes: std.StringHashMap(smithy.ShapeInfo), writer: anytype, state: GenerationState) anyerror!void {
|
||||
_ = shape_id;
|
||||
const Mapping = struct { snake: []const u8, json: []const u8 };
|
||||
var json_field_name_mappings = try std.ArrayList(Mapping).initCapacity(allocator, members.len);
|
||||
var json_field_name_mappings = try std.ArrayList(Mapping).initCapacity(state.allocator, members.len);
|
||||
defer {
|
||||
for (json_field_name_mappings.items) |mapping| {
|
||||
allocator.free(mapping.snake);
|
||||
}
|
||||
for (json_field_name_mappings.items) |mapping|
|
||||
state.allocator.free(mapping.snake);
|
||||
json_field_name_mappings.deinit();
|
||||
}
|
||||
// There is an httpQueryParams trait as well, but nobody is using it. API GW
|
||||
|
@ -353,28 +403,26 @@ fn generateComplexTypeFor(allocator: *std.mem.Allocator, members: []smithy.TypeM
|
|||
// Same with httpPayload
|
||||
//
|
||||
// httpLabel is interesting - right now we just assume anything can be used - do we need to track this?
|
||||
var http_query_mappings = try std.ArrayList(Mapping).initCapacity(allocator, members.len);
|
||||
var http_query_mappings = try std.ArrayList(Mapping).initCapacity(state.allocator, members.len);
|
||||
defer {
|
||||
for (http_query_mappings.items) |mapping| {
|
||||
allocator.free(mapping.snake);
|
||||
}
|
||||
for (http_query_mappings.items) |mapping|
|
||||
state.allocator.free(mapping.snake);
|
||||
http_query_mappings.deinit();
|
||||
}
|
||||
var http_header_mappings = try std.ArrayList(Mapping).initCapacity(allocator, members.len);
|
||||
var http_header_mappings = try std.ArrayList(Mapping).initCapacity(state.allocator, members.len);
|
||||
defer {
|
||||
for (http_header_mappings.items) |mapping| {
|
||||
allocator.free(mapping.snake);
|
||||
}
|
||||
for (http_header_mappings.items) |mapping|
|
||||
state.allocator.free(mapping.snake);
|
||||
http_header_mappings.deinit();
|
||||
}
|
||||
// prolog. We'll rely on caller to get the spacing correct here
|
||||
_ = try writer.write(type_type_name);
|
||||
_ = try writer.write(" {\n");
|
||||
var child_state = state;
|
||||
child_state.indent_level += 1;
|
||||
for (members) |member| {
|
||||
const new_prefix = try std.fmt.allocPrint(allocator, " {s}", .{prefix});
|
||||
defer allocator.free(new_prefix);
|
||||
// This is our mapping
|
||||
const snake_case_member = try snake.fromPascalCase(allocator, member.name);
|
||||
const snake_case_member = try snake.fromPascalCase(state.allocator, member.name);
|
||||
// So it looks like some services have duplicate names?! Check out "httpMethod"
|
||||
// in API Gateway. Not sure what we're supposed to do there. Checking the go
|
||||
// sdk, they move this particular duplicate to 'http_method' - not sure yet
|
||||
|
@ -384,20 +432,21 @@ fn generateComplexTypeFor(allocator: *std.mem.Allocator, members: []smithy.TypeM
|
|||
switch (trait) {
|
||||
.json_name => {
|
||||
found_name_trait = true;
|
||||
json_field_name_mappings.appendAssumeCapacity(.{ .snake = try allocator.dupe(u8, snake_case_member), .json = trait.json_name });
|
||||
json_field_name_mappings.appendAssumeCapacity(.{ .snake = try state.allocator.dupe(u8, snake_case_member), .json = trait.json_name });
|
||||
},
|
||||
.http_query => http_query_mappings.appendAssumeCapacity(.{ .snake = try allocator.dupe(u8, snake_case_member), .json = trait.http_query }),
|
||||
.http_header => http_header_mappings.appendAssumeCapacity(.{ .snake = try allocator.dupe(u8, snake_case_member), .json = trait.http_header }),
|
||||
.http_query => http_query_mappings.appendAssumeCapacity(.{ .snake = try state.allocator.dupe(u8, snake_case_member), .json = trait.http_query }),
|
||||
.http_header => http_header_mappings.appendAssumeCapacity(.{ .snake = try state.allocator.dupe(u8, snake_case_member), .json = trait.http_header }),
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
if (!found_name_trait)
|
||||
json_field_name_mappings.appendAssumeCapacity(.{ .snake = try allocator.dupe(u8, snake_case_member), .json = member.name });
|
||||
defer allocator.free(snake_case_member);
|
||||
try writer.print("{s} {s}: ", .{ prefix, avoidReserved(snake_case_member) });
|
||||
if (!all_required) try writeOptional(member.traits, writer, null);
|
||||
try generateTypeFor(allocator, member.target, shapes, writer, new_prefix, all_required, type_stack, true);
|
||||
if (!all_required and !std.mem.eql(u8, "union", type_type_name))
|
||||
json_field_name_mappings.appendAssumeCapacity(.{ .snake = try state.allocator.dupe(u8, snake_case_member), .json = member.name });
|
||||
defer state.allocator.free(snake_case_member);
|
||||
try outputIndent(child_state, writer);
|
||||
try writer.print("{s}: ", .{avoidReserved(snake_case_member)});
|
||||
try writeOptional(member.traits, writer, null);
|
||||
try generateTypeFor(member.target, shapes, writer, child_state, true);
|
||||
if (!std.mem.eql(u8, "union", type_type_name))
|
||||
try writeOptional(member.traits, writer, " = null");
|
||||
_ = try writer.write(",\n");
|
||||
}
|
||||
|
@ -409,12 +458,10 @@ fn generateComplexTypeFor(allocator: *std.mem.Allocator, members: []smithy.TypeM
|
|||
// .marker = "Marker",
|
||||
// .max_items = "MaxItems",
|
||||
// };
|
||||
var constprefix = try std.fmt.allocPrint(allocator, "{s} ", .{prefix});
|
||||
defer allocator.free(constprefix);
|
||||
if (http_query_mappings.items.len > 0) _ = try writer.write("\n");
|
||||
try writeMappings(constprefix, "pub ", "http_query", http_query_mappings, writer);
|
||||
try writeMappings(child_state, "pub ", "http_query", http_query_mappings, false, writer);
|
||||
if (http_query_mappings.items.len > 0 and http_header_mappings.items.len > 0) _ = try writer.write("\n");
|
||||
try writeMappings(constprefix, "pub ", "http_header", http_header_mappings, writer);
|
||||
try writeMappings(child_state, "pub ", "http_header", http_header_mappings, false, writer);
|
||||
|
||||
// Add in json mappings. The function looks like this:
|
||||
//
|
||||
|
@ -426,23 +473,39 @@ fn generateComplexTypeFor(allocator: *std.mem.Allocator, members: []smithy.TypeM
|
|||
// return @field(mappings, field_name);
|
||||
// }
|
||||
//
|
||||
var fieldnameprefix = try std.fmt.allocPrint(allocator, "{s} ", .{prefix});
|
||||
defer allocator.free(fieldnameprefix);
|
||||
try writer.print("\n{s} pub fn jsonFieldNameFor(_: @This(), comptime field_name: []const u8) []const u8 ", .{prefix});
|
||||
try writer.writeByte('\n');
|
||||
try outputIndent(child_state, writer);
|
||||
_ = try writer.write("pub fn jsonFieldNameFor(_: @This(), comptime field_name: []const u8) []const u8 ");
|
||||
_ = try writer.write("{\n");
|
||||
try writeMappings(fieldnameprefix, "", "mappings", json_field_name_mappings, writer);
|
||||
try writer.print("{s} return @field(mappings, field_name);\n{s}", .{ prefix, prefix });
|
||||
var grandchild_state = child_state;
|
||||
grandchild_state.indent_level += 1;
|
||||
// We need to force output here becaseu we're referencing the field in the return statement below
|
||||
try writeMappings(grandchild_state, "", "mappings", json_field_name_mappings, true, writer);
|
||||
try outputIndent(grandchild_state, writer);
|
||||
_ = try writer.write("return @field(mappings, field_name);\n");
|
||||
try outputIndent(child_state, writer);
|
||||
_ = try writer.write("}\n");
|
||||
|
||||
// TODO: Deal with the jsonStringifyField stuff
|
||||
}
|
||||
|
||||
fn writeMappings(prefix: []const u8, @"pub": []const u8, mapping_name: []const u8, mappings: anytype, writer: anytype) !void {
|
||||
if (mappings.items.len == 0) return;
|
||||
try writer.print("{s}{s}const {s} = .", .{ prefix, @"pub", mapping_name });
|
||||
_ = try writer.write("{\n");
|
||||
for (mappings.items) |mapping| {
|
||||
try writer.print("{s} .{s} = \"{s}\",\n", .{ prefix, avoidReserved(mapping.snake), mapping.json });
|
||||
fn writeMappings(state: GenerationState, @"pub": []const u8, mapping_name: []const u8, mappings: anytype, force_output: bool, writer: anytype) !void {
|
||||
if (mappings.items.len == 0 and !force_output) return;
|
||||
try outputIndent(state, writer);
|
||||
if (mappings.items.len == 0) {
|
||||
try writer.print("{s}const {s} = ", .{ @"pub", mapping_name });
|
||||
_ = try writer.write(".{};\n");
|
||||
return;
|
||||
}
|
||||
_ = try writer.write(prefix);
|
||||
try writer.print("{s}const {s} = .", .{ @"pub", mapping_name });
|
||||
_ = try writer.write("{\n");
|
||||
var child_state = state;
|
||||
child_state.indent_level += 1;
|
||||
for (mappings.items) |mapping| {
|
||||
try outputIndent(child_state, writer);
|
||||
try writer.print(".{s} = \"{s}\",\n", .{ avoidReserved(mapping.snake), mapping.json });
|
||||
}
|
||||
try outputIndent(state, writer);
|
||||
_ = try writer.write("};\n");
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user