Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions lib/aws_codegen.ex
Original file line number Diff line number Diff line change
Expand Up @@ -90,20 +90,27 @@ defmodule AWS.CodeGen do
@spec generate(:elixir | :erlang, binary(), binary(), binary()) :: :ok
def generate(language, spec_base_path, template_base_path, output_base_path) do
endpoints_spec = get_endpoints_spec(spec_base_path)

tasks =
Enum.map(
api_specs(spec_base_path, language),
fn spec ->
output_path = Path.join(output_base_path, spec.filename)

Task.async(fn ->
generate_code(spec, language, endpoints_spec, template_base_path, output_path)
end)
if spec == :error do
IO.puts("Skipping due to error")
Task.async(fn -> :ok end)
else
if spec.filename == "health_lake.ex" or spec.filename == "aws_healthlake.erl" do
IO.puts("Skipping health_lake due to known issues with the spec since it has another frontend service wrapped in the same spec")
Task.async(fn -> :ok end)
else
output_path = Path.join(output_base_path, spec.filename)
Task.async(fn ->
generate_code(spec, language, endpoints_spec, template_base_path, output_path)
end)
end
end
end
)

Enum.each(tasks, fn task -> Task.await(task, 120_000) end)
Enum.each(tasks, fn task -> Task.await(task, :infinity) end)
end

defp generate_code(spec, language, endpoints_spec, template_base_path, output_path) do
Expand Down
2 changes: 1 addition & 1 deletion lib/aws_codegen/name.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ defmodule AWS.CodeGen.Name do
"""
def to_snake_case(text) do
text
|> String.replace(~r/com\.amazonaws\.[^#]+#/, "")
|> String.replace(~r/com\.(amazonaws|amazon)\.[^#]+#/, "")
|> String.replace(@names_to_capitalize, &String.capitalize(&1))
|> String.to_charlist()
|> Enum.map_join(&char_to_snake_case/1)
Expand Down
4 changes: 1 addition & 3 deletions lib/aws_codegen/post_service.ex
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ defmodule AWS.CodeGen.PostService do
endpoint_prefix
end
signing_name = traits["aws.auth#sigv4"]["name"] || maybe_signing_name

%Service{
actions: actions,
api_version: service["version"],
Expand Down Expand Up @@ -155,7 +154,6 @@ defmodule AWS.CodeGen.PostService do
]
|> Enum.reject(&is_nil/1)
|> Kernel.++(acc)

_ ->
acc
end
Expand All @@ -175,7 +173,7 @@ defmodule AWS.CodeGen.PostService do
),
function_name: AWS.CodeGen.Name.to_snake_case(operation),
host_prefix: operation_spec["traits"]["smithy.api#endpoint"]["hostPrefix"],
name: String.replace(operation, ~r/com\.amazonaws\.[^#]+#/, ""),
name: String.replace(operation, ~r/com\.(amazonaws|amazon)\.[^#]+#/, ""),
input: operation_spec["input"],
output: operation_spec["output"],
errors: operation_spec["errors"]
Expand Down
8 changes: 5 additions & 3 deletions lib/aws_codegen/rest_service.ex
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ defmodule AWS.CodeGen.RestService do
end)
|> List.flatten()
|> Enum.map(fn %{"target" => target} -> target end)
|> Enum.reverse()

Enum.map(operations, fn operation ->
operation_spec = shapes[operation]
Expand Down Expand Up @@ -337,7 +338,6 @@ defmodule AWS.CodeGen.RestService do
defp collect_url_parameters(language, api_spec, operation) do
url_params =
collect_parameters(language, api_spec, operation, "input", "smithy.api#httpLabel")

url_params
end

Expand Down Expand Up @@ -377,10 +377,12 @@ defmodule AWS.CodeGen.RestService do

shape["members"]
|> Enum.filter(filter_fn(param_type))
|> Enum.map(fn {name, x} ->
|> Enum.reduce([], fn {name, x}, acc ->
required = Enum.member?(required_members, name)
build_parameter(language, {name, x["traits"][param_type]}, required)
acc ++ [build_parameter(language, {name, x["traits"][param_type]}, required)]
end)
|> Enum.sort(fn a, b -> a.code_name < b.code_name end)

end
else
[]
Expand Down
2 changes: 1 addition & 1 deletion lib/aws_codegen/shapes.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ defmodule AWS.CodeGen.Shapes do

def collect_shapes(_language, api_spec) do
api_spec["shapes"]
|> Map.new(fn {name, shape} ->
|> Enum.map(fn {name, shape} ->
{name,
%Shape{
name: name,
Expand Down
65 changes: 36 additions & 29 deletions lib/aws_codegen/spec.ex
Original file line number Diff line number Diff line change
Expand Up @@ -32,42 +32,49 @@ defmodule AWS.CodeGen.Spec do
service_name =
api
|> find_service()
|> String.replace("com.amazonaws.#{api_name}#", "")
|> String.replace(~r/com\.(amazonaws|amazon)\.[^#]+#/, "")

traits = api["shapes"]["com.amazonaws." <> api_name <> "#" <> service_name]["traits"]

protocol =
protocol0 =
Enum.find_value(traits, fn {k, _v} ->
case String.split(k, "#") do
["aws.protocols", protocol] -> protocol
_ -> nil
end
end)
|> String.replace("restJson1", "rest_json")
|> String.replace(["awsJson1_0", "awsJson1_1"], "json")
|> String.replace("awsQuery", "query")
|> String.replace("restXml", "rest_xml")
|> String.replace("ec2Query", "ec2")
|> then(fn value ->
if value in ~w(rest_json json query rest_xml ec2) do
value
else
raise "the protocol #{value} is not valid"
_ ->
nil
end
end)
|> String.to_atom()

module_name = module_name(traits, language)
filename = filename(module_name, language)

%AWS.CodeGen.Spec{
protocol: protocol,
module_name: module_name,
filename: filename,
api: api,
language: language,
shape_name: "com.amazonaws." <> api_name <> "#" <> service_name
}
if is_nil(protocol0) do
IO.puts("Unhandled protocol (nil) for #{api_filename} with service #{service_name}")
:error
else
protocol =
protocol0
|> String.replace("restJson1", "rest_json")
|> String.replace(["awsJson1_0", "awsJson1_1"], "json")
|> String.replace("awsQuery", "query")
|> String.replace("restXml", "rest_xml")
|> String.replace("ec2Query", "ec2")
|> then(fn value ->
if value in ~w(rest_json json query rest_xml ec2) do
value
else
raise "the protocol #{value} is not valid"
end
end)
|> String.to_atom()

module_name = module_name(traits, language)
filename = filename(module_name, language)

%AWS.CodeGen.Spec{
protocol: protocol,
module_name: module_name,
filename: filename,
api: api,
language: language,
shape_name: "com.amazonaws." <> api_name <> "#" <> service_name
}
end
end

def find_service(api) do
Expand Down
38 changes: 17 additions & 21 deletions lib/aws_codegen/types.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule AWS.CodeGen.Types do
alias AWS.CodeGen.Shapes.Shape

def types(context) do
Enum.reduce(context.shapes, %{}, fn {_name, shape}, acc ->
Enum.reduce(context.shapes, [], fn {_name, shape}, acc ->
process_shape(context, shape, acc)
end)
end
Expand All @@ -23,12 +23,12 @@ defmodule AWS.CodeGen.Types do

defp normalize_type_name(name) do
name
|> String.replace(~r/com\.amazonaws\.[^#]+#/, "")
|> String.replace(~r/com\.(amazonaws|amazon)\.[^#]+#/, "")
|> AWS.CodeGen.Name.to_snake_case()
end

defp process_shape_members(context, shape) do
Enum.reduce(shape.members, %{}, fn {name, shape_member}, a ->
Enum.reduce(shape.members, [], fn {name, shape_member}, a ->
process_shape_member(context, shape, name, shape_member, a)
end)
end
Expand All @@ -41,11 +41,7 @@ defmodule AWS.CodeGen.Types do
else
shape_member_type = shape_to_type(context, target, context.module_name, context.shapes)

Map.put(
a,
is_required(context.language, shape.is_input, shape_member, name),
shape_member_type
)
[({is_required(context.language, shape.is_input, shape_member, name), shape_member_type}) | a]
end
end

Expand All @@ -54,9 +50,9 @@ defmodule AWS.CodeGen.Types do
defp update_acc_with_types(acc, type, types, context) do
if reserved_type(type) do
module_name = String.downcase(String.replace(context.module_name, ["aws_", "AWS."], ""))
Map.put(acc, "#{module_name}_#{type}", types)
[{ "#{module_name}_#{type}", types } | acc]
else
Map.put(acc, type, types)
[{ type, types } | acc]
end
end

Expand Down Expand Up @@ -99,18 +95,18 @@ defmodule AWS.CodeGen.Types do
"[#{shape_to_type(context.language, %Shape{type: "blob"}, module_name)}]"

_ ->
case all_shapes[shape_name] do
%Shape{type: "structure"} ->
case List.keyfind(all_shapes, shape_name, 0) do
{_, %Shape{type: "structure"}} ->
type =
"#{AWS.CodeGen.Name.to_snake_case(String.replace(shape_name, ~r/com\.amazonaws\.[^#]+#/, ""))}"
"#{AWS.CodeGen.Name.to_snake_case(String.replace(shape_name, ~r/com\.(amazonaws|amazon)\.[^#]+#/, ""))}"
|> AWS.CodeGen.Util.maybe_add_parens()
if reserved_type(type) do
"#{String.downcase(String.replace(context.module_name, ["aws_", "AWS."], ""))}_#{type}"
else
"#{type}"
end

%Shape{type: "list", member: member} ->
{_, %Shape{type: "list", member: member}} ->
# this change alone gets us down to 1595
type =
"#{shape_to_type(context, member["target"], module_name, all_shapes)}"
Expand All @@ -125,7 +121,7 @@ defmodule AWS.CodeGen.Types do
nil ->
raise "Tried to reference an undefined shape for #{shape_name}"

shape ->
{_, shape} ->
shape_to_type(context.language, shape, module_name)
end
end
Expand Down Expand Up @@ -162,7 +158,7 @@ defmodule AWS.CodeGen.Types do
defp shape_to_type(_, %Shape{type: "document"}, _module_name), do: "any()"

defp is_required(:elixir, is_input, shape, target) do
trimmed_name = String.replace(target, ~r/com\.amazonaws\.[^#]+#/, "")
trimmed_name = String.replace(target, ~r/com\.(amazonaws|amazon)\.[^#]+#/, "")

if is_input do
if Map.has_key?(shape, "traits") do
Expand All @@ -180,7 +176,7 @@ defmodule AWS.CodeGen.Types do
end

defp is_required(:erlang, is_input, shape, target) do
trimmed_name = String.replace(target, ~r/com\.amazonaws\.[^#]+#/, "")
trimmed_name = String.replace(target, ~r/com\.(amazonaws|amazon)\.[^#]+#/, "")

if is_input do
if Map.has_key?(shape, "traits") do
Expand All @@ -207,7 +203,7 @@ defmodule AWS.CodeGen.Types do
"%{}"

type ->
"#{AWS.CodeGen.Name.to_snake_case(String.replace(type, ~r/com\.amazonaws\.[^#]+#/, ""))}()"
"#{AWS.CodeGen.Name.to_snake_case(String.replace(type, ~r/com\.(amazonaws|amazon)\.[^#]+#/, ""))}()"
end
end

Expand All @@ -217,7 +213,7 @@ defmodule AWS.CodeGen.Types do
"\#{}"

type ->
"#{AWS.CodeGen.Name.to_snake_case(String.replace(type, ~r/com\.amazonaws\.[^#]+#/, ""))}()"
"#{AWS.CodeGen.Name.to_snake_case(String.replace(type, ~r/com\.(amazonaws|amazon)\.[^#]+#/, ""))}()"
end
end

Expand All @@ -237,7 +233,7 @@ defmodule AWS.CodeGen.Types do

type ->
normal =
"{:ok, #{AWS.CodeGen.Name.to_snake_case(String.replace(type, ~r/com\.amazonaws\.[^#]+#/, ""))}(), any()}"
"{:ok, #{AWS.CodeGen.Name.to_snake_case(String.replace(type, ~r/com\.(amazonaws|amazon)\.[^#]+#/, ""))}(), any()}"

errors =
if is_list(action.errors) do
Expand Down Expand Up @@ -266,7 +262,7 @@ defmodule AWS.CodeGen.Types do

type ->
normal =
"{ok, #{AWS.CodeGen.Name.to_snake_case(String.replace(type, ~r/com\.amazonaws\.[^#]+#/, ""))}(), tuple()}"
"{ok, #{AWS.CodeGen.Name.to_snake_case(String.replace(type, ~r/com\.(amazonaws|amazon)\.[^#]+#/, ""))}(), tuple()}"

errors =
if is_list(action.errors) do
Expand Down
15 changes: 6 additions & 9 deletions lib/aws_codegen/util.ex
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,19 @@ defmodule AWS.CodeGen.Util do
[]

[{_name, shape}] ->
Enum.reduce(
Enum.map(
shape.members,
[],
fn
{name, %{"traits" => traits}}, acc ->
{name, %{"traits" => traits}} ->
if Map.has_key?(traits, "smithy.api#required") do
[name <> " Required: true" | acc]
name <> " Required: true"
else
[name <> " Required: false" | acc]
name <> " Required: false"
end

{name, _shape}, acc ->
[name <> " Required: false" | acc]
{name, _shape} ->
name <> " Required: false"
end
)
|> Enum.reverse()
end
end

Expand Down
8 changes: 4 additions & 4 deletions priv/post.erl.eex
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@

-include_lib("hackney/include/hackney_lib.hrl").

<%= for {type_name, type_fields} <- AWS.CodeGen.Types.types(context) do %>
<%= for {type_name, type_fields} <- AWS.CodeGen.Types.types(context) |> Enum.sort(fn {type_a, _}, {type_b, _} -> type_a < type_b end) do %>
%% Example:
%% <%= type_name %>() :: #{
<%= Enum.map_join(type_fields, ",\n", fn {field_name, field_type} ->
<%= Enum.map_join(type_fields |> Enum.sort(fn {field_a, _}, {field_b, _} -> field_a < field_b end), ",\n", fn {field_name, field_type} ->
~s{%% #{field_name}#{field_type}}
end) %>
%% }
Expand All @@ -21,8 +21,8 @@ end) %>
fn action ->
errors = action.errors
if not is_nil(errors) do
errors_snakecased = errors |> Enum.map(fn error -> AWS.CodeGen.Name.to_snake_case(String.replace(error["target"], ~r/com\.amazonaws\.[^#]+#/, "")) end)
all_types = AWS.CodeGen.Types.types(context)
errors_snakecased = errors |> Enum.map(fn error -> AWS.CodeGen.Name.to_snake_case(String.replace(error["target"], ~r/com\.(amazonaws|amazon)\.[^#]+#/, "")) end)
all_types = AWS.CodeGen.Types.types(context) |> Enum.sort(fn {type_a, _}, {type_b, _} -> type_a < type_b end)
error_types = Enum.reduce(all_types,
[],
fn {type_name, _type_fields}, acc ->
Expand Down
Loading
Loading