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,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smithy
4
+ module Model
5
+ # Represents a shape from the model.
6
+ # Shape IDs have the following syntax:
7
+ #
8
+ # smithy.example.foo#ExampleShapeName$memberName
9
+ # └─────────┬──────┘ └───────┬──────┘ └────┬───┘
10
+ # (Namespace) (Shape name) (Member name)
11
+ # └──────────────┬────────────┘
12
+ # (Relative shape ID)
13
+ # └──────────────────────┬───────────────────────┘
14
+ # (Absolute shape ID)
15
+ class Shape
16
+ # Optional shape namespace
17
+ # @param [String] id Shape ID
18
+ # @return [String, nil] Shape namespace
19
+ def self.namespace(id)
20
+ return nil unless id.include?('#')
21
+
22
+ id.split('#').first
23
+ end
24
+
25
+ # Relative shape ID
26
+ # @param [String] id Shape ID
27
+ # @return [String, nil] Relative shape ID
28
+ def self.relative_id(id)
29
+ id.split('#').last
30
+ end
31
+
32
+ # Shape name
33
+ # @param [String] id Shape ID
34
+ # @return [String, nil] Shape name
35
+ def self.name(id)
36
+ id.split('#').last&.split('$')&.first
37
+ end
38
+
39
+ # Optional member name
40
+ # @param [String] id Shape ID
41
+ # @return [String, nil] Member name
42
+ def self.member_name(id)
43
+ return nil unless id.include?('$')
44
+
45
+ id.split('$').last
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smithy
4
+ module Model
5
+ # @api private
6
+ class StructureParser
7
+ def initialize(model)
8
+ @model = model
9
+ end
10
+
11
+ def shapes_for(structure)
12
+ shapes = {}
13
+ _id, structure = structure.first
14
+ structure['members']&.each_value { |member| parse_member(member, shapes) }
15
+ shapes
16
+ end
17
+
18
+ private
19
+
20
+ def parse_member(member_shape, shapes)
21
+ target = member_shape['target']
22
+ return if shapes.key?(target)
23
+ return if Model::PRELUDE_SHAPES.key?(target)
24
+
25
+ shape = Model.shape(@model, target)
26
+ shapes[target] = shape
27
+ parse_shape(shape, shapes)
28
+ end
29
+
30
+ def parse_shape(shape, shapes)
31
+ case shape['type']
32
+ when 'list'
33
+ parse_member(shape['member'], shapes)
34
+ when 'map'
35
+ parse_member(shape['key'], shapes)
36
+ parse_member(shape['value'], shapes)
37
+ when 'structure', 'union', 'intEnum', 'enum'
38
+ shape['members']&.each_value { |member| parse_member(member, shapes) }
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smithy
4
+ module Model
5
+ # @api private
6
+ class YARD
7
+ class << self
8
+ def deprecated_docstrings(message, since)
9
+ lines = ['@deprecated']
10
+ lines << " #{escape(message)}" unless message.empty?
11
+ lines << " Since: #{escape(since)}" unless since.empty?
12
+ lines
13
+ end
14
+
15
+ def external_documentation_docstrings(hash)
16
+ hash.map { |key, value| "@see #{escape(value)} #{escape(key)}" }
17
+ end
18
+
19
+ def option_docstrings(service, model, id, shape, option, docstrings) # rubocop:disable Metrics/ParameterLists
20
+ lines = ["@option params [#{type(service, model, id, shape)}] :#{option}"]
21
+ docstrings.each do |docstring|
22
+ lines << " #{docstring}"
23
+ end
24
+ lines
25
+ end
26
+
27
+ def param_docstring(service, model, id, shape)
28
+ "@param [Hash, #{type(service, model, id, shape)}] params"
29
+ end
30
+
31
+ def recommended_docstrings(reason)
32
+ lines = ['@note']
33
+ lines << ' This shape is recommended'
34
+ lines << " Reason: #{escape(reason)}" unless reason.empty?
35
+ lines
36
+ end
37
+
38
+ def return_docstring(service, model, id, shape)
39
+ "@return [#{type(service, model, id, shape)}]"
40
+ end
41
+
42
+ def sensitive_docstring
43
+ '@note This shape contains sensitive data and should be treated as such.'
44
+ end
45
+
46
+ def since_docstring(since)
47
+ "@since #{escape(since)}"
48
+ end
49
+
50
+ def title_docstring(title)
51
+ "@title #{escape(title)}"
52
+ end
53
+
54
+ def unstable_docstring
55
+ '@note This shape is unstable and may change in future releases.'
56
+ end
57
+
58
+ private
59
+
60
+ def type(service, model, id, shape) # rubocop:disable Metrics/CyclomaticComplexity
61
+ case shape['type']
62
+ when 'blob', 'string', 'enum' then 'String'
63
+ when 'boolean' then 'Boolean'
64
+ when 'byte', 'short', 'integer', 'long', 'intEnum' then 'Integer'
65
+ when 'float', 'double' then 'Float'
66
+ when 'timestamp' then 'Time'
67
+ when 'document' then 'JSON'
68
+ when 'list' then list(service, model, shape)
69
+ when 'map' then map(service, model, shape)
70
+ when 'structure', 'union' then structure(service, id)
71
+ else 'Object'
72
+ end
73
+ end
74
+
75
+ def structure(service, id)
76
+ return 'Smithy::Schema::EmptyStructure' if id == 'smithy.api#Unit'
77
+
78
+ "Types::#{(service.dig('rename', id) || Model::Shape.name(id)).camelize}"
79
+ end
80
+
81
+ def map(service, model, shape)
82
+ key_target = Model.shape(model, shape['key']['target'])
83
+ value_target = Model.shape(model, shape['value']['target'])
84
+ key_type = type(service, model, shape['key']['target'], key_target)
85
+ value_type = type(service, model, shape['value']['target'], value_target)
86
+ "Hash<#{key_type}, #{value_type}>"
87
+ end
88
+
89
+ def list(service, model, shape)
90
+ member_target = Model.shape(model, shape['member']['target'])
91
+ "Array<#{type(service, model, shape['member']['target'], member_target)}>"
92
+ end
93
+
94
+ def escape(string)
95
+ string.split("\n").join(' ')
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'model/flattener'
4
+ require_relative 'model/operation_parser'
5
+ require_relative 'model/rbs'
6
+ require_relative 'model/service_index'
7
+ require_relative 'model/service_parser'
8
+ require_relative 'model/shape'
9
+ require_relative 'model/structure_parser'
10
+ require_relative 'model/yard'
11
+
12
+ module Smithy
13
+ # A module that parses the Smithy JSON model.
14
+ module Model
15
+ # Generated with smithy-cli 1.53.0
16
+ # @api private
17
+ PRELUDE_SHAPES = {
18
+ 'smithy.api#BigInteger' => { 'type' => 'bigInteger' },
19
+ 'smithy.api#BigDecimal' => { 'type' => 'bigDecimal' },
20
+ 'smithy.api#Blob' => { 'type' => 'blob' },
21
+ 'smithy.api#Boolean' => { 'type' => 'boolean' },
22
+ 'smithy.api#Byte' => { 'type' => 'byte' },
23
+ 'smithy.api#Document' => { 'type' => 'document' },
24
+ 'smithy.api#Double' => { 'type' => 'double' },
25
+ 'smithy.api#Float' => { 'type' => 'float' },
26
+ 'smithy.api#Integer' => { 'type' => 'integer' },
27
+ 'smithy.api#Long' => { 'type' => 'long' },
28
+ 'smithy.api#PrimitiveBoolean' => { 'type' => 'boolean', 'traits' => { 'smithy.api#default' => false } },
29
+ 'smithy.api#PrimitiveByte' => { 'type' => 'byte', 'traits' => { 'smithy.api#default' => 0 } },
30
+ 'smithy.api#PrimitiveDouble' => { 'type' => 'double', 'traits' => { 'smithy.api#default' => 0 } },
31
+ 'smithy.api#PrimitiveFloat' => { 'type' => 'float', 'traits' => { 'smithy.api#default' => 0 } },
32
+ 'smithy.api#PrimitiveInteger' => { 'type' => 'integer', 'traits' => { 'smithy.api#default' => 0 } },
33
+ 'smithy.api#PrimitiveLong' => { 'type' => 'long', 'traits' => { 'smithy.api#default' => 0 } },
34
+ 'smithy.api#PrimitiveShort' => { 'type' => 'short', 'traits' => { 'smithy.api#default' => 0 } },
35
+ 'smithy.api#Short' => { 'type' => 'short' },
36
+ 'smithy.api#String' => { 'type' => 'string' },
37
+ 'smithy.api#Timestamp' => { 'type' => 'timestamp' },
38
+ 'smithy.api#Unit' => { 'type' => 'structure', 'members' => {}, 'traits' => { 'smithy.api#unitType' => {} } }
39
+ }.freeze
40
+
41
+ # @param [Hash] model Model
42
+ # @param [String] id Shape ID
43
+ # @return [Hash]
44
+ def self.shape(model, id)
45
+ if model['shapes'].key?(id)
46
+ Flattener.new(model).shape(id)
47
+ elsif PRELUDE_SHAPES.key?(id)
48
+ PRELUDE_SHAPES[id]
49
+ else
50
+ raise ArgumentError, "Shape not found: #{id}"
51
+ end
52
+ end
53
+ end
54
+ end
data/lib/smithy/plan.rb CHANGED
@@ -1,10 +1,86 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Smithy
4
+ # The Plan class is a simple data structure that holds the model, type, and options for a generator.
4
5
  class Plan
5
- def initialize(*args)
6
- puts 'Creating a Smithy plan'
7
- puts "ARGS: #{args.join(', ')}"
6
+ # @param [Hash] model The API model as a JSON hash.
7
+ # @param [Symbol] type The type of code to generate, either :client, :server, or :schema.
8
+ # @param [Hash] options
9
+ # @option options [String] :name The name of the service to generate code for.
10
+ # @option options [String] :module_name The module name for clients and schemas.
11
+ # Defaults to the name of the service.
12
+ # @option options [String] :gem_name The gem name for clients and schemas.
13
+ # Defaults to a gem name derived from the module name, suffixed with '-schema' if type is schema.
14
+ # @option options [String] :gem_version The version of the gem to generate.
15
+ # @option options [String] :destination_root The destination directory for the generated code.
16
+ # If not provided, source code will be generated to STDOUT.
17
+ # @option options [Boolean] :quiet Whether to suppress output.
18
+ def initialize(model, type, options = {})
19
+ @model = model
20
+ @type = type
21
+ @service = find_service(model['shapes'])
22
+
23
+ @name = options.fetch(:name, default_name(@service))
24
+ @module_name = options.fetch(:module_name, @name)
25
+ @gem_name = options.fetch(:gem_name, default_gem_name(@module_name, @type))
26
+ @gem_version = options.fetch(:gem_version)
27
+
28
+ @destination_root = options.fetch(:destination_root, nil)
29
+ @quiet = options.fetch(:quiet, false)
30
+
31
+ Welds.load!(self)
32
+ @welds = Welds.for(@service)
33
+ end
34
+
35
+ # @return [Hash] The API model as a JSON hash.
36
+ attr_reader :model
37
+
38
+ # @return [Symbol] The type of code to generate.
39
+ attr_reader :type
40
+
41
+ # @return [Hash<String, Hash>] The service shape for the shapes.
42
+ attr_reader :service
43
+
44
+ # @return [String] The name of the service.
45
+ attr_reader :name
46
+
47
+ # @return [String] The module name for clients and schemas.
48
+ attr_reader :module_name
49
+
50
+ # @return [String] The gem name for clients and schemas.
51
+ attr_reader :gem_name
52
+
53
+ # @return [String] The version of the gem to generate.
54
+ attr_reader :gem_version
55
+
56
+ # @return [String] The destination directory for the generated code.
57
+ attr_reader :destination_root
58
+
59
+ # @return [Boolean] Whether to suppress output.
60
+ attr_reader :quiet
61
+
62
+ # @return [Array<Weld>] The welds that apply to this plan.
63
+ attr_reader :welds
64
+
65
+ private
66
+
67
+ def find_service(shapes)
68
+ service = shapes.select { |_, shape| shape['type'] == 'service' }
69
+ raise 'Multiple service shapes found' if service.size > 1
70
+ raise 'No service shape found' if service.empty?
71
+
72
+ service
73
+ end
74
+
75
+ def default_name(service)
76
+ Model::Shape.name(service.keys.first)
77
+ end
78
+
79
+ def default_gem_name(module_name, type)
80
+ gem_name = module_name.split('::').map do |part|
81
+ part.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
82
+ end.join('-')
83
+ type == :schema ? "#{gem_name.downcase}-schema" : gem_name.downcase
8
84
  end
9
85
  end
10
86
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is generated code!
4
+
5
+ module <%= module_name %>
6
+ # Auth parameters used to resolve authentication per request.
7
+ <% parameters.each do |param| -%>
8
+ # @!attribute <%= param.name %>
9
+ <% param.docstrings.each do |docstring| -%>
10
+ # <%= docstring %>
11
+ <% end -%>
12
+ #
13
+ # @return [<%= param.documentation_type %>]
14
+ #
15
+ <% end -%>
16
+ AuthParameters = Struct.new(
17
+ <% parameters.each do |param| -%>
18
+ :<%= param.name %>,
19
+ <% end -%>
20
+ keyword_init: true
21
+ ) do
22
+
23
+ # @api private
24
+ def self.create(context)
25
+ # TODO: support more properties
26
+ new(operation_name: context.operation_name)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,14 @@
1
+ module <%= module_name %>
2
+ class AuthParameters
3
+ def initialize: (
4
+ <% parameters.each do |param| -%>
5
+ <%= '?' unless param.name == :operation_name %><%= param.name %>: <%= param.rbs_type %>,
6
+ <% end -%>
7
+ ) -> void
8
+ | (?Hash[Symbol, untyped]) -> void
9
+
10
+ <% parameters.each do |param| -%>
11
+ attr_accessor <%= param.name %>: <%= param.rbs_type %><%= '?' unless param.name == :operation_name %>
12
+ <% end -%>
13
+ end
14
+ end
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is generated code!
4
+
5
+ module <%= module_name %>
6
+ module Plugins
7
+ # @api private
8
+ class Auth < Smithy::Client::Plugin
9
+ option(
10
+ :auth_resolver,
11
+ doc_type: '<%= module_name %>::AuthResolver',
12
+ docstring: <<~DOCS) do |config|
13
+ The auth resolver used to resolve authentication. Any object that responds to `#resolve(parameters)`.
14
+ DOCS
15
+ AuthResolver.new
16
+ end
17
+
18
+ option(
19
+ :auth_schemes,
20
+ doc_type: Hash,
21
+ rbs_type: 'Hash[String, Smithy::Client::AuthScheme]',
22
+ docstring: <<~DOCS) do |config|
23
+ The auth schemes used to resolve authentication. The key is the scheme name as a String,
24
+ and the value is an initialized auth scheme class.
25
+ DOCS
26
+ {
27
+ <% auth_schemes.each do |k, v| -%>
28
+ '<%= k %>' => config.<%= v %>,
29
+ <% end -%>
30
+ }
31
+ end
32
+
33
+ # @api private
34
+ class Handler < Smithy::Client::Handler
35
+ def call(context)
36
+ # TODO: apply endpoint auth properties if present
37
+ auth_params = AuthParameters.create(context)
38
+ auth_options = context.config.auth_resolver.resolve(auth_params)
39
+ context[:auth] = resolve_auth(context, auth_options)
40
+ @handler.call(context)
41
+ end
42
+
43
+ private
44
+
45
+ def resolve_auth(context, auth_options)
46
+ failures = []
47
+
48
+ raise 'No auth options were resolved' if auth_options.empty?
49
+
50
+ identity_providers = {
51
+ <% identity_providers.each do |k, v| -%>
52
+ <%= k %> => context.config.<%= v %>,
53
+ <% end -%>
54
+ }
55
+
56
+ auth_options.each do |auth_option|
57
+ auth_scheme = context.config.auth_schemes[auth_option.scheme_id]
58
+ resolved_auth = try_load_auth_scheme(
59
+ auth_option,
60
+ auth_scheme,
61
+ identity_providers,
62
+ failures
63
+ )
64
+
65
+ return resolved_auth if resolved_auth
66
+ end
67
+
68
+ raise failures.join("\n")
69
+ end
70
+
71
+ def try_load_auth_scheme(auth_option, auth_scheme, identity_providers, failures)
72
+ scheme_id = auth_option.scheme_id
73
+ unless auth_scheme
74
+ failures << "Auth scheme #{scheme_id} was not enabled " \
75
+ 'for this request'
76
+ return
77
+ end
78
+
79
+ identity_provider = auth_scheme.identity_provider(identity_providers)
80
+ unless identity_provider
81
+ failures << "Auth scheme #{scheme_id} did not have an " \
82
+ 'identity resolver configured'
83
+ return
84
+ end
85
+
86
+ identity_properties = auth_option.identity_properties
87
+ identity = identity_provider.identity(identity_properties)
88
+
89
+ ResolvedAuth.new(
90
+ scheme_id: scheme_id,
91
+ identity: identity,
92
+ identity_properties: auth_option.identity_properties,
93
+ signer: auth_scheme.signer,
94
+ signer_properties: auth_option.signer_properties
95
+ )
96
+ end
97
+
98
+ # @api private
99
+ class ResolvedAuth
100
+ def initialize(options = {})
101
+ @scheme_id = options[:scheme_id]
102
+ @signer = options[:signer]
103
+ @signer_properties = options[:signer_properties]
104
+ @identity = options[:identity]
105
+ @identity_properties = options[:identity_properties]
106
+ end
107
+
108
+ attr_accessor :scheme_id, :signer, :signer_properties, :identity, :identity_properties
109
+ end
110
+ end
111
+
112
+ handler(Handler, step: :sign, priority: 70)
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is generated code!
4
+
5
+ module <%= module_name %>
6
+ # Resolves the auth scheme from {AuthParameters}.
7
+ class AuthResolver
8
+ # @param [AuthParameters] parameters
9
+ # @return [Smithy::Client::AuthOption]
10
+ def resolve(parameters)
11
+ <% auth_rules_code.each do |line| -%>
12
+ <%= line %>
13
+ <% end -%>
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,5 @@
1
+ module <%= module_name %>
2
+ class AuthResolver
3
+ def resolve: (AuthParameters) -> Array[Smithy::Client::AuthOption]
4
+ end
5
+ end
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is generated code!
4
+
5
+ <%require_plugins.each do |require| -%>
6
+ <%= require %>
7
+ <% end -%>
8
+
9
+ module <%= module_name %>
10
+ # An API client for <%= module_name %>.
11
+ # See {#initialize} for a full list of supported configuration options.
12
+ class Client < Smithy::Client::Base
13
+ include Smithy::Client::Stubs
14
+
15
+ self.service = Schema::<%= service_name %>
16
+
17
+ <% add_plugins.each do |plugin_class| -%>
18
+ add_plugin(<%= plugin_class %>)
19
+ <% end -%>
20
+
21
+ # @param options [Hash] Client options
22
+ <% docstrings.each do |docstring| -%>
23
+ # <%= docstring %>
24
+ <% end -%>
25
+ def initialize(*options)
26
+ super
27
+ end
28
+
29
+ <% operations.each do |operation| -%>
30
+ <% operation.docstrings.each do |docstring| -%>
31
+ # <%= docstring %>
32
+ <% end -%>
33
+ def <%= operation.method_name %>(params = {}, options = {})
34
+ request = build_request(:<%= operation.method_name %>, params)
35
+ request.send_request(options)
36
+ end
37
+
38
+ <% end -%>
39
+ # Polls an API operation until a resource enters a desired state.
40
+ #
41
+ # ## Basic Usage
42
+ #
43
+ # A waiter will call an API operation until:
44
+ #
45
+ # * It is successful
46
+ # * It enters a terminal state
47
+ # * It reaches the maximum wait time allowed
48
+ #
49
+ # In between attempts, the waiter will sleep.
50
+ #
51
+ # # polls in a loop, sleeping between attempts
52
+ # client.wait_until(waiter_name, params, options)
53
+ #
54
+ # ## Configuration
55
+ #
56
+ # You must configure the maximum amount of time in seconds a
57
+ # waiter should wait for. You may also configure the minimum
58
+ # and maximum amount of time in seconds to delay between
59
+ # retries. You can pass these configuration as the final
60
+ # arguments hash.
61
+ #
62
+ # weather = Weather::Client.new
63
+ #
64
+ # # poll for a maximum of 25 seconds
65
+ # weather.wait_until(:forecast_exists, { forecast_id: '1' }, {
66
+ # max_wait_time: 25,
67
+ # min_delay: 2,
68
+ # max_delay: 10
69
+ # })
70
+ #
71
+ # ## Handling Errors
72
+ #
73
+ # When a waiter is unsuccessful, it will raise an error.
74
+ # All the failure errors extend from
75
+ # {Smithy::Client::Waiters::WaiterFailed}.
76
+ #
77
+ # weather = Weather::Client.new
78
+ # begin
79
+ # weather.wait_until(:forecast_exists, { forecast_id: '1' }, max_wait_time: 60)
80
+ # rescue Smithy::Client::Waiters::WaiterFailed
81
+ # # resource did not enter the desired state in time
82
+ # end
83
+ #
84
+ # @param [Symbol] waiter_name
85
+ # @param [Hash] params ({})
86
+ # @param [Hash] options ({})
87
+ # @option options [Integer] :max_wait_time
88
+ # @option options [Integer] :min_delay
89
+ # @option options [Integer] :max_delay
90
+ # @return [nil] Returns `nil` if the waiter was successful.
91
+ # @raise [FailureStateError] Raised when the waiter terminates
92
+ # because the waiter has entered a state that it will not transition
93
+ # out of, preventing success.
94
+ # @raise [MaxWaitTimeExceededError] Raised when the configured
95
+ # maximum wait time is reached and the waiter is not yet successful.
96
+ # @raise [UnexpectedError] Raised when an error that is not
97
+ # expected is encountered while polling for a resource.
98
+ # @raise [NoSuchWaiterError] Raised when you request to wait
99
+ # for an unknown state.
100
+ def wait_until(waiter_name, params = {}, options = {})
101
+ waiter(waiter_name, options).wait(params)
102
+ end
103
+
104
+ # @api private
105
+ def build_request(operation_name, params)
106
+ handlers = @handlers.for(operation_name)
107
+ context = Smithy::Client::HandlerContext.new(
108
+ operation_name: operation_name,
109
+ operation: config.service.operation(operation_name),
110
+ client: self,
111
+ config: config,
112
+ params: params
113
+ )
114
+ context[:gem_name] = '<%= gem_name %>'
115
+ context[:gem_version] = '<%= gem_version %>'
116
+ Smithy::Client::Request.new(handlers: handlers, context: context)
117
+ end
118
+
119
+ private
120
+
121
+ def waiters
122
+ <% waiters.each do |line| -%>
123
+ <%= line %>
124
+ <% end -%>
125
+ end
126
+
127
+ class << self
128
+ # @api private
129
+ attr_reader :identifier
130
+
131
+ # @api private
132
+ def protocols
133
+ <%= protocols %>
134
+ end
135
+
136
+ # @api private
137
+ def errors_module
138
+ Errors
139
+ end
140
+ end
141
+ end
142
+ end