smithy 2.0.0.pre0 → 2.0.0.pre1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/bin/smithy-ruby +1 -4
  4. data/lib/smithy/command.rb +68 -0
  5. data/lib/smithy/generators/base.rb +19 -0
  6. data/lib/smithy/generators/client.rb +106 -0
  7. data/lib/smithy/generators/schema.rb +61 -0
  8. data/lib/smithy/generators.rb +29 -0
  9. data/lib/smithy/model/flattener.rb +114 -0
  10. data/lib/smithy/model/operation_parser.rb +42 -0
  11. data/lib/smithy/model/rbs.rb +57 -0
  12. data/lib/smithy/model/service_index.rb +51 -0
  13. data/lib/smithy/model/service_parser.rb +74 -0
  14. data/lib/smithy/model/shape.rb +49 -0
  15. data/lib/smithy/model/structure_parser.rb +43 -0
  16. data/lib/smithy/model/yard.rb +100 -0
  17. data/lib/smithy/model.rb +54 -0
  18. data/lib/smithy/plan.rb +79 -3
  19. data/lib/smithy/templates/client/auth_parameters.erb +29 -0
  20. data/lib/smithy/templates/client/auth_parameters_rbs.erb +14 -0
  21. data/lib/smithy/templates/client/auth_plugin.erb +115 -0
  22. data/lib/smithy/templates/client/auth_resolver.erb +16 -0
  23. data/lib/smithy/templates/client/auth_resolver_rbs.erb +5 -0
  24. data/lib/smithy/templates/client/client.erb +142 -0
  25. data/lib/smithy/templates/client/client_rbs.erb +29 -0
  26. data/lib/smithy/templates/client/customizations.erb +3 -0
  27. data/lib/smithy/templates/client/endpoint_parameters.erb +65 -0
  28. data/lib/smithy/templates/client/endpoint_parameters_rbs.erb +13 -0
  29. data/lib/smithy/templates/client/endpoint_plugin.erb +58 -0
  30. data/lib/smithy/templates/client/endpoint_provider.erb +15 -0
  31. data/lib/smithy/templates/client/endpoint_provider_rbs.erb +5 -0
  32. data/lib/smithy/templates/client/endpoint_provider_spec.erb +70 -0
  33. data/lib/smithy/templates/client/errors.erb +69 -0
  34. data/lib/smithy/templates/client/errors_rbs.erb +17 -0
  35. data/lib/smithy/templates/client/gemspec.erb +17 -0
  36. data/lib/smithy/templates/client/module.erb +22 -0
  37. data/lib/smithy/templates/client/module_rbs.erb +7 -0
  38. data/lib/smithy/templates/client/paginators.erb +33 -0
  39. data/lib/smithy/templates/client/protocol_spec.erb +144 -0
  40. data/lib/smithy/templates/client/rubocop_yml.erb +33 -0
  41. data/lib/smithy/templates/client/schema.erb +76 -0
  42. data/lib/smithy/templates/client/schema_rbs.erb +13 -0
  43. data/lib/smithy/templates/client/spec_helper.erb +10 -0
  44. data/lib/smithy/templates/client/types.erb +64 -0
  45. data/lib/smithy/templates/client/types_rbs.erb +47 -0
  46. data/lib/smithy/templates/client/waiters.erb +42 -0
  47. data/lib/smithy/util/hash_formatter.rb +124 -0
  48. data/lib/smithy/util/underscore.rb +18 -0
  49. data/lib/smithy/util.rb +9 -0
  50. data/lib/smithy/views/client/auth_parameter.rb +29 -0
  51. data/lib/smithy/views/client/auth_parameters.rb +23 -0
  52. data/lib/smithy/views/client/auth_parameters_rbs.rb +23 -0
  53. data/lib/smithy/views/client/auth_plugin.rb +35 -0
  54. data/lib/smithy/views/client/auth_resolver.rb +125 -0
  55. data/lib/smithy/views/client/auth_resolver_rbs.rb +19 -0
  56. data/lib/smithy/views/client/client.rb +208 -0
  57. data/lib/smithy/views/client/client_rbs.rb +231 -0
  58. data/lib/smithy/views/client/customizations.rb +10 -0
  59. data/lib/smithy/views/client/endpoint_parameter.rb +156 -0
  60. data/lib/smithy/views/client/endpoint_parameters.rb +43 -0
  61. data/lib/smithy/views/client/endpoint_parameters_rbs.rb +28 -0
  62. data/lib/smithy/views/client/endpoint_plugin.rb +27 -0
  63. data/lib/smithy/views/client/endpoint_provider.rb +241 -0
  64. data/lib/smithy/views/client/endpoint_provider_rbs.rb +19 -0
  65. data/lib/smithy/views/client/endpoint_provider_spec.rb +137 -0
  66. data/lib/smithy/views/client/errors.rb +88 -0
  67. data/lib/smithy/views/client/errors_rbs.rb +12 -0
  68. data/lib/smithy/views/client/gemspec.rb +36 -0
  69. data/lib/smithy/views/client/module.rb +107 -0
  70. data/lib/smithy/views/client/module_rbs.rb +20 -0
  71. data/lib/smithy/views/client/operation_examples.rb +157 -0
  72. data/lib/smithy/views/client/paginators.rb +108 -0
  73. data/lib/smithy/views/client/plugin.rb +29 -0
  74. data/lib/smithy/views/client/plugin_list.rb +57 -0
  75. data/lib/smithy/views/client/protocol_spec.rb +254 -0
  76. data/lib/smithy/views/client/request_response_example.rb +179 -0
  77. data/lib/smithy/views/client/rubocop_yml.rb +19 -0
  78. data/lib/smithy/views/client/schema.rb +356 -0
  79. data/lib/smithy/views/client/schema_rbs.rb +84 -0
  80. data/lib/smithy/views/client/shape_to_hash.rb +99 -0
  81. data/lib/smithy/views/client/spec_helper.rb +19 -0
  82. data/lib/smithy/views/client/types.rb +293 -0
  83. data/lib/smithy/views/client/types_rbs.rb +67 -0
  84. data/lib/smithy/views/client/waiters.rb +82 -0
  85. data/lib/smithy/views/client.rb +47 -0
  86. data/lib/smithy/views/view.rb +30 -0
  87. data/lib/smithy/views.rb +9 -0
  88. data/lib/smithy/weld.rb +109 -0
  89. data/lib/smithy/welds/auth/anonymous_auth.rb +31 -0
  90. data/lib/smithy/welds/auth/http_api_key_auth.rb +34 -0
  91. data/lib/smithy/welds/auth/http_basic_auth.rb +34 -0
  92. data/lib/smithy/welds/auth/http_bearer_auth.rb +34 -0
  93. data/lib/smithy/welds/auth/http_digest_auth.rb +34 -0
  94. data/lib/smithy/welds/plugins.rb +54 -0
  95. data/lib/smithy/welds/rpc_v2_cbor.rb +20 -0
  96. data/lib/smithy/welds/rubocop.rb +33 -0
  97. data/lib/smithy/welds/transforms/default_endpoint_rules.json +35 -0
  98. data/lib/smithy/welds/transforms/default_endpoint_tests.json +24 -0
  99. data/lib/smithy/welds/transforms/endpoints.rb +68 -0
  100. data/lib/smithy/welds/transforms/synthetic_input_output.rb +60 -0
  101. data/lib/smithy/welds.rb +29 -0
  102. data/lib/smithy.rb +33 -2
  103. metadata +144 -9
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is generated code!
4
+
5
+ module <%= module_name %>
6
+ # This module contains a schema composed of shapes used by the client.
7
+ module Schema
8
+
9
+ <% shapes.each do |shape| -%>
10
+ <%= shape.name %> = <%= shape.initializer %>
11
+ <% end -%>
12
+
13
+ <% shapes.each do |shape| -%>
14
+ <% case shape.type -%>
15
+ <% when 'enum', 'intEnum' -%>
16
+ <% shape.members.each do |member| -%>
17
+ <%= shape.name %>.add_member(:<%= member.name %>, <%= member.initializer %>)
18
+ <% end -%>
19
+ <% when 'list' -%>
20
+ <%= shape.name %>.member = <%= shape.member.initializer %>
21
+ <% when 'map' -%>
22
+ <%= shape.name %>.key = <%= shape.key.initializer %>
23
+ <%= shape.name %>.value = <%= shape.value.initializer %>
24
+ <% when 'structure' -%>
25
+ <% shape.members.each do |member| -%>
26
+ <%= shape.name %>.add_member(:<%= member.name %>, <%= member.initializer %>)
27
+ <% end -%>
28
+ <% if shape.http_payload? -%>
29
+ <%= shape.name %>[:http_payload] = :<%= shape.http_payload %>
30
+ <%= shape.name %>[:http_payload_member] = <%= shape.name %>.member(:<%= shape.http_payload %>)
31
+ <% end -%>
32
+ <%= shape.name %>.type = <%= shape.type_class %>
33
+ <% when 'union' -%>
34
+ <% shape.members.each do |member| -%>
35
+ <%= shape.name %>.add_member(:<%= member.name %>, <%= shape.union_type(member) %>, <%= member.initializer %>)
36
+ <% end -%>
37
+ <%= shape.name %>.add_member(:unknown, Types::<%= shape.name %>::Unknown, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::Unit))
38
+ <%= shape.name %>.type = <%= shape.type_class %>
39
+ <% end -%>
40
+ <% end -%>
41
+
42
+ <%= service_shape.name %> = Smithy::Schema::Shapes::ServiceShape.new do |service|
43
+ service.id = "<%= service_shape.id %>"
44
+ service.name = "<%= service_shape.name %>"
45
+ <% if service_shape.version -%>
46
+ service.version = "<%= service_shape.version %>"
47
+ <% end -%>
48
+ service.traits = <%= service_shape.traits %>
49
+ <% operation_shapes.each do |shape| -%>
50
+ service.add_operation(:<%= shape.name.underscore %>, Smithy::Schema::Shapes::OperationShape.new do |operation|
51
+ operation.id = "<%= shape.id %>"
52
+ operation.name = "<%= shape.name %>"
53
+ operation.input = <%= shape.input.initializer %>
54
+ operation.output = <%= shape.output.initializer %>
55
+ <% shape.errors.each do |error| -%>
56
+ operation.errors << <%= error.initializer %>
57
+ <% end -%>
58
+ operation.traits = <%= shape.traits %>
59
+ <% if !schema_gem? && shape.paginated? -%>
60
+ operation[:paginator] = <%= shape.paginator %>
61
+ <% end -%>
62
+ end)
63
+ <% end -%>
64
+
65
+ end
66
+
67
+ class << self
68
+ def type_registry
69
+ return @type_registry if @type_registry
70
+
71
+ shapes = constants.map { |sym| const_get(sym) }.select { |const| const.is_a?(Smithy::Schema::Shapes::StructureShape) }
72
+ @type_registry = Smithy::Schema::TypeRegistry.new(shapes)
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,13 @@
1
+ module <%= module_name %>
2
+ module Schema
3
+ include Smithy::Schema::Shapes
4
+
5
+ <% shapes.each do |shape| -%>
6
+ <%= shape.name %>: <%= shape.shape_class %>
7
+ <% end -%>
8
+
9
+ <% if service_shape -%>
10
+ <%= service_shape.name %>: <%= service_shape.shape_class %>
11
+ <% end -%>
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is generated code!
4
+
5
+ $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
6
+
7
+ require '<%= gem_name %>'
8
+
9
+ require 'rspec'
10
+ require 'smithy-client/protocol_spec_matcher'
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is generated code!
4
+
5
+ module <%= module_name %>
6
+ # This module contains the types returned by client operations.
7
+ module Types
8
+ <% types.each do |type| -%>
9
+
10
+ <% type.docstrings.each do |docstring| -%>
11
+ # <%= docstring %>
12
+ <% end -%>
13
+ <% case type.type -%>
14
+ <% when 'enum', 'intEnum' -%>
15
+ module <%= type.name %>
16
+ <% type.members.each do |member| -%>
17
+ <% member.docstrings.each do |docstring| -%>
18
+ # <%= docstring %>
19
+ <% end -%>
20
+ <%= member.name %> = <%= member.value %>
21
+ <% end -%>
22
+ end
23
+ <% when 'structure' -%>
24
+ <% type.attribute_docstrings.each do |docstring| -%>
25
+ # <%= docstring %>
26
+ <% end -%>
27
+ class <%= type.name %> < Struct.new(
28
+ <% type.members.each do |member| -%>
29
+ :<%= member.name.underscore %>,
30
+ <% end -%>
31
+ keyword_init: true)
32
+ include Smithy::Schema::Structure
33
+ <% if !type.input? && type.defaults.any? -%>
34
+
35
+ def initialize(options = {})
36
+ <% type.defaults.each do |member| -%>
37
+ options[:<%= member.name.underscore %>] = <%= member.default %> unless options.key?(:<%= member.name.underscore %>)
38
+ <% end -%>
39
+ super
40
+ end
41
+ <% end -%>
42
+ end
43
+ <% when 'union' -%>
44
+ <% type.attribute_docstrings.each do |docstring| -%>
45
+ # <%= docstring %>
46
+ <% end -%>
47
+ class <%= type.name %> < Struct.new(
48
+ <% type.members.each do |member| -%>
49
+ :<%= member.name.underscore %>,
50
+ <% end -%>
51
+ :unknown,
52
+ keyword_init: true)
53
+ include Smithy::Schema::Union
54
+
55
+ <% type.members.each do |member| -%>
56
+ class <%= member.name.camelize %> < <%= type.name %>; end
57
+ <% end -%>
58
+ class Unknown < <%= type.name %>; end
59
+ end
60
+ <% end -%>
61
+ <% end -%>
62
+
63
+ end
64
+ end
@@ -0,0 +1,47 @@
1
+ module <%= module_name %>
2
+ module Types
3
+ <% types.each do |type| -%>
4
+
5
+ <% case type.type -%>
6
+ <% when 'enum', 'intEnum' -%>
7
+ module <%= type.name %>
8
+ <% type.members.each do |member| -%>
9
+ <% if type.type == 'enum' -%>
10
+ <%= member.name %>: String
11
+ <% elsif type.type == 'intEnum' -%>
12
+ <%= member.name %>: Integer
13
+ <% end -%>
14
+ <% end -%>
15
+ end
16
+ <% when 'structure', 'union' -%>
17
+ class <%= type.name %>
18
+ <% if type.type == 'structure' -%>
19
+ include Smithy::Schema::Structure
20
+ <% elsif type.type == 'union' -%>
21
+ include Smithy::Schema::Union
22
+ <% end -%>
23
+
24
+ def initialize: (
25
+ <% type.members.each do |member| -%>
26
+ ?<%= member.name.underscore %>: <%= member.rbs_type %>,
27
+ <% end -%>
28
+ ) -> void
29
+ | (?Hash[Symbol, untyped]) -> void
30
+
31
+ <% type.members.each do |member| -%>
32
+ attr_accessor <%= member.name.underscore %>: <%= member.rbs_type %>?
33
+ <% end -%>
34
+ <% if type.type == 'union' -%>
35
+
36
+ <% type.members.each do |member| -%>
37
+ class <%= member.name.camelize %> < <%= type.name %>
38
+ end
39
+ <% end -%>
40
+ class Unknown < <%= type.name %>
41
+ end
42
+ <% end -%>
43
+ end
44
+ <% end -%>
45
+ <% end -%>
46
+ end
47
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is generated code!
4
+
5
+ module <%= module_name %>
6
+
7
+ # @api private
8
+ module Waiters
9
+ <% waiters.each do |waiter| -%>
10
+ <% if waiter.deprecated? -%>
11
+ # @deprecated
12
+ <% end -%>
13
+ # @api private
14
+ #
15
+ <% waiter.docstrings.each do |docstring| -%>
16
+ # <%= docstring %>
17
+ <% end -%>
18
+ #
19
+ class <%= waiter.name %>
20
+ def initialize(options = {})
21
+ @client = options[:client]
22
+ @waiter = Smithy::Client::Waiters::Waiter.new(
23
+ max_wait_time: options[:max_wait_time],
24
+ min_delay: options[:min_delay] || <%= waiter.min_delay %>,
25
+ max_delay: options[:max_delay] || <%= waiter.max_delay %>,
26
+ poller: Smithy::Client::Waiters::Poller.new(
27
+ operation_name: :<%= waiter.operation_name %>,
28
+ <% waiter.acceptors.each do |acceptor| -%>
29
+ <%= acceptor %>
30
+ <% end -%>
31
+ )
32
+ )
33
+ end
34
+
35
+ def wait(params = {})
36
+ @waiter.wait(@client, params)
37
+ end
38
+ end
39
+
40
+ <% end -%>
41
+ end
42
+ end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smithy
4
+ module Util
5
+ # A class to format a hash into a string.
6
+ class HashFormatter
7
+ # @option options [Boolean] :wrap (true) When `true`, the formatted hash will
8
+ # be wrapped with curly braces.
9
+ # @option options [Boolean] :inline (false) When `true` the formatted hash will
10
+ # contain no newlines.
11
+ # @option options [Boolean] :quote_strings (false) By default, all hash string values
12
+ # must contain their own quotes. If you pass `true`, then all hash string
13
+ # values will be inspected via `#inspect` which will auto-quote them.
14
+ # @option options [String] :indent ('') The indentation to use for the hash.
15
+ def initialize(options = {})
16
+ @wrap = options.fetch(:wrap, true)
17
+ @inline = options.fetch(:inline, false)
18
+ @quote_strings = options.fetch(:quote_strings, false)
19
+ @indent = options.fetch(:indent, '')
20
+ end
21
+
22
+ # @return [String]
23
+ def format(obj)
24
+ result = hash(obj, indent: @indent, inline: @inline)
25
+ result = unwrap(result, obj.size) unless @wrap
26
+ result = result.strip if @inline && result.lines.to_a.length == 1
27
+ result
28
+ end
29
+
30
+ private
31
+
32
+ def value(obj, options)
33
+ indent = options.fetch(:indent)
34
+ inline = options.fetch(:inline)
35
+ case obj
36
+ when Hash then hash(obj, indent: indent, inline: inline)
37
+ when Array then array(obj, indent: indent)
38
+ when String then @quote_strings ? obj.inspect : obj
39
+ when Symbol, Numeric, true, false then obj.inspect
40
+ else raise ArgumentError, "unsupported value: #{obj.class}"
41
+ end
42
+ end
43
+
44
+ def hash(hash, options)
45
+ indent = options.fetch(:indent)
46
+ inline = options.fetch(:inline)
47
+ if hash.empty?
48
+ '{}'
49
+ elsif inline_hash?(hash, inline)
50
+ inline_hash(hash)
51
+ else
52
+ multiline_hash(hash, indent: indent)
53
+ end
54
+ end
55
+
56
+ def inline_hash(hash)
57
+ "{ #{hash_entry(hash.keys[0], hash.values[0], indent: '')} }"
58
+ end
59
+
60
+ def multiline_hash(hash, options)
61
+ indent = options.fetch(:indent)
62
+ str = "{\n"
63
+ hash.each.with_index do |(key, value), n|
64
+ str += "#{indent} #{hash_entry(key, value, indent: indent)}"
65
+ str += ',' unless n == hash.keys.length - 1
66
+ str += "\n"
67
+ end
68
+ str + "#{indent}}"
69
+ end
70
+
71
+ def hash_entry(key, value, options)
72
+ indent = options.fetch(:indent)
73
+ value = value(value, indent: "#{indent} ", inline: false)
74
+ if key.is_a?(Symbol)
75
+ "#{key}: #{value}"
76
+ else
77
+ "#{key.inspect} => #{value}"
78
+ end
79
+ end
80
+
81
+ def array(array, options)
82
+ indent = options.fetch(:indent)
83
+ if array.empty?
84
+ '[]'
85
+ elsif inline_array?(array)
86
+ "[#{value(array[0], indent: indent, inline: true)}]"
87
+ else
88
+ format_multiline_array(array, indent: indent)
89
+ end
90
+ end
91
+
92
+ def format_multiline_array(array, options)
93
+ indent = options.fetch(:indent)
94
+ str = "[\n"
95
+ array.each.with_index do |value, n|
96
+ str += "#{indent} #{value(value, indent: "#{indent} ", inline: true)}"
97
+ str += ',' unless n == array.length - 1
98
+ str += "\n"
99
+ end
100
+ str + "#{indent}]"
101
+ end
102
+
103
+ def inline_hash?(hash, inline)
104
+ hash.length == 1 && hash.values[0].is_a?(String) && inline
105
+ end
106
+
107
+ def inline_array?(array)
108
+ array.length == 1
109
+ end
110
+
111
+ def unwrap(str, size)
112
+ if @inline || size > 1
113
+ str[1..-2]
114
+ else
115
+ lines = str.lines.to_a
116
+ lines.shift
117
+ lines.pop
118
+ lines = lines.map { |line| line[2..] }
119
+ lines.join.rstrip
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smithy
4
+ module Util
5
+ # @api private
6
+ module Underscore
7
+ class << self
8
+ # @param [String<JMESPath>]
9
+ # @return [String]
10
+ def underscore_jmespath(expression)
11
+ expression
12
+ .gsub(' or ', '||')
13
+ .gsub(/(?<![`'])\b\w+\b(?![`'])/, &:underscore)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'util/hash_formatter'
4
+ require_relative 'util/underscore'
5
+
6
+ module Smithy
7
+ # @api private
8
+ module Util; end
9
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smithy
4
+ module Views
5
+ module Client
6
+ # @api private
7
+ class AuthParameter
8
+ def initialize(options = {})
9
+ @name = options[:name]
10
+ @documentation = options[:documentation]
11
+ end
12
+
13
+ attr_reader :name
14
+
15
+ def docstrings
16
+ @documentation.split("\n")
17
+ end
18
+
19
+ def documentation_type
20
+ 'Symbol'
21
+ end
22
+
23
+ def rbs_type
24
+ 'Symbol'
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smithy
4
+ module Views
5
+ module Client
6
+ # @api private
7
+ class AuthParameters < View
8
+ def initialize(plan)
9
+ @plan = plan
10
+ super()
11
+ end
12
+
13
+ def module_name
14
+ @plan.module_name
15
+ end
16
+
17
+ def parameters
18
+ [AuthParameter.new(name: :operation_name, documentation: 'The name of the operation.')]
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smithy
4
+ module Views
5
+ module Client
6
+ # @api private
7
+ class AuthParametersRbs < View
8
+ def initialize(plan)
9
+ @plan = plan
10
+ super()
11
+ end
12
+
13
+ def module_name
14
+ @plan.module_name
15
+ end
16
+
17
+ def parameters
18
+ [AuthParameter.new(name: :operation_name, documentation: 'The name of the operation.')]
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smithy
4
+ module Views
5
+ module Client
6
+ # @api private
7
+ class AuthPlugin < View
8
+ def initialize(plan)
9
+ @plan = plan
10
+ @auth_schemes = weld_auth_schemes(plan.welds)
11
+ super()
12
+ end
13
+
14
+ def module_name
15
+ @plan.module_name
16
+ end
17
+
18
+ def auth_schemes
19
+ @auth_schemes.transform_values { |v| v[:auth_scheme_config_option] }
20
+ end
21
+
22
+ def identity_providers
23
+ @auth_schemes.to_h { |_, v| [v[:identity_type], v[:identity_provider_config_option]] }
24
+ end
25
+
26
+ private
27
+
28
+ def weld_auth_schemes(welds)
29
+ weld_auth_schemes = welds.map(&:add_auth_schemes).reduce({}, :merge)
30
+ weld_auth_schemes.except(*welds.map(&:remove_auth_schemes).reduce([], :+))
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smithy
4
+ module Views
5
+ module Client
6
+ # @api private
7
+ class AuthResolver < View
8
+ def initialize(plan)
9
+ @plan = plan
10
+ _, service = plan.service.first
11
+ @service_traits = service.fetch('traits', {})
12
+ @operations = Model::ServiceIndex.new(plan.model).operations_for(plan.service)
13
+ @auth_schemes = auth_schemes(plan.welds)
14
+ super()
15
+ end
16
+
17
+ def module_name
18
+ @plan.module_name
19
+ end
20
+
21
+ # rubocop:disable Metrics/AbcSize
22
+ # rubocop:disable Metrics/MethodLength
23
+ def auth_rules_code
24
+ lines = []
25
+ lines << 'options = []'
26
+ auth_operations = operations_with_auth_traits
27
+ if auth_operations.empty?
28
+ service_auth_schemes.each do |auth_scheme|
29
+ lines << "options << #{render_auth_option(auth_scheme)}"
30
+ end
31
+ else
32
+ lines << 'case parameters.operation_name'
33
+ auth_operations.each do |id, operation|
34
+ operation_name = Model::Shape.name(id).underscore
35
+ lines << "when :#{operation_name}"
36
+ operation_auth_schemes(operation).each do |auth_scheme|
37
+ lines << " options << #{render_auth_option(auth_scheme)}"
38
+ end
39
+ end
40
+ lines << 'else'
41
+ service_auth_schemes.each do |auth_scheme|
42
+ lines << " options << #{render_auth_option(auth_scheme)}"
43
+ end
44
+ lines << 'end'
45
+ end
46
+ lines << 'options'
47
+ lines
48
+ end
49
+ # rubocop:enable Metrics/MethodLength
50
+ # rubocop:enable Metrics/AbcSize
51
+
52
+ private
53
+
54
+ def auth_schemes(welds)
55
+ weld_auth_schemes = welds.map(&:add_auth_schemes).reduce({}, :merge)
56
+ weld_auth_schemes = weld_auth_schemes.except(*welds.map(&:remove_auth_schemes).reduce([], :+))
57
+ weld_auth_schemes
58
+ .sort_by { |k, _| k }
59
+ .to_h
60
+ end
61
+
62
+ def service_has_auth_trait?
63
+ @service_traits.key?('smithy.api#auth')
64
+ end
65
+
66
+ def service_auth_schemes
67
+ auth_schemes = []
68
+ if service_has_auth_trait?
69
+ service_auth = @service_traits.fetch('smithy.api#auth', [])
70
+ add_auth_schemes_from_auth_trait(auth_schemes, service_auth)
71
+ else
72
+ add_registered_auth_schemes(auth_schemes, @service_traits)
73
+ end
74
+ auth_schemes << 'smithy.api#noAuth' if auth_schemes.empty?
75
+ auth_schemes
76
+ end
77
+
78
+ def operations_with_auth_traits
79
+ @operations.select do |_, operation|
80
+ operation_auth?(operation) || optional_operation_auth?(operation)
81
+ end
82
+ end
83
+
84
+ def operation_auth?(operation)
85
+ operation.fetch('traits', {}).key?('smithy.api#auth')
86
+ end
87
+
88
+ def optional_operation_auth?(operation)
89
+ operation.fetch('traits', {}).key?('smithy.api#optionalAuth')
90
+ end
91
+
92
+ def operation_auth_schemes(operation)
93
+ operation_traits = operation.fetch('traits', {})
94
+ auth_schemes = []
95
+ if operation_auth?(operation)
96
+ operation_auth = operation_traits.fetch('smithy.api#auth', [])
97
+ add_auth_schemes_from_auth_trait(auth_schemes, operation_auth)
98
+ else
99
+ add_registered_auth_schemes(auth_schemes, operation_traits)
100
+ end
101
+ auth_schemes << 'smithy.api#optionalAuth' if operation_traits.key?('smithy.api#optionalAuth')
102
+ auth_schemes << 'smithy.api#noAuth' if auth_schemes.empty?
103
+ auth_schemes
104
+ end
105
+
106
+ def add_auth_schemes_from_auth_trait(auth_schemes, auth_trait)
107
+ auth_trait.each do |auth_scheme|
108
+ auth_schemes << auth_scheme if @auth_schemes.key?(auth_scheme)
109
+ end
110
+ end
111
+
112
+ def add_registered_auth_schemes(auth_schemes, traits)
113
+ @auth_schemes.each_key do |auth_scheme|
114
+ auth_schemes << auth_scheme if traits.key?(auth_scheme)
115
+ end
116
+ end
117
+
118
+ def render_auth_option(auth_scheme)
119
+ properties = @service_traits.fetch(auth_scheme, {})
120
+ "Smithy::Client::AuthOption.new(scheme_id: '#{auth_scheme}', signer_properties: #{properties})"
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smithy
4
+ module Views
5
+ module Client
6
+ # @api private
7
+ class AuthResolverRbs < View
8
+ def initialize(plan)
9
+ @plan = plan
10
+ super()
11
+ end
12
+
13
+ def module_name
14
+ @plan.module_name
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end