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,208 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smithy
4
+ module Views
5
+ module Client
6
+ # @api private
7
+ class Client < View
8
+ def initialize(plan, code_generated_plugins)
9
+ @plan = plan
10
+ @model = plan.model
11
+ _, @service = plan.service.first
12
+ @plugins = PluginList.new(plan, code_generated_plugins)
13
+ super()
14
+ end
15
+
16
+ def require_plugins
17
+ requires = []
18
+ @plugins.each do |plugin|
19
+ next if !@plan.destination_root && plugin.require_relative?
20
+
21
+ requires << "require#{'_relative' if plugin.require_relative?} '#{plugin.require_path}'"
22
+ end
23
+ requires
24
+ end
25
+
26
+ def module_name
27
+ @plan.module_name
28
+ end
29
+
30
+ def service_name
31
+ id, = @plan.service.first
32
+ Model::Shape.name(id).camelize
33
+ end
34
+
35
+ def add_plugins
36
+ @plugins.map(&:class_name)
37
+ end
38
+
39
+ def docstrings
40
+ options = @plugins.map(&:options).flatten.sort_by(&:name)
41
+ documentation = {}
42
+ options.each do |option|
43
+ documentation[option.name] = option_docstrings(option) if option.docstring
44
+ end
45
+ lines = []
46
+ documentation.each_value { |value| lines.concat(value) }
47
+ lines
48
+ end
49
+
50
+ def operations
51
+ Model::ServiceIndex
52
+ .new(@model)
53
+ .operations_for(@plan.service)
54
+ .map { |id, operation| Operation.new(@service, @model, id, operation) }
55
+ end
56
+
57
+ def gem_name
58
+ @plan.gem_name
59
+ end
60
+
61
+ def gem_version
62
+ @plan.gem_version
63
+ end
64
+
65
+ # TODO: re-evaluate this approach - perhaps plugins should register protocol classes with options
66
+ def protocols
67
+ @protocols ||= @plan.welds.map(&:protocols).reduce({}, :merge)
68
+ end
69
+
70
+ def waiters
71
+ waiters = Views::Client::Waiters.new(@plan).waiters
72
+ return ['{}'] if waiters.empty?
73
+
74
+ lines = ['{']
75
+ waiters.each do |waiter|
76
+ lines << " #{waiter.name.underscore}: Waiters::#{waiter.name},"
77
+ end
78
+ lines.last.chomp!(',') if lines.last.end_with?(',')
79
+ lines << '}'
80
+ lines
81
+ end
82
+
83
+ private
84
+
85
+ def option_docstrings(option)
86
+ lines = []
87
+ lines << option_tag(option)
88
+ documentation = option.docstring.split("\n").map { |line| " #{line}" }
89
+ lines.concat(documentation)
90
+ lines
91
+ end
92
+
93
+ def option_tag(option)
94
+ tag = StringIO.new
95
+ tag << '@option options'
96
+ tag << " [#{option.doc_type}]" if option.doc_type
97
+ tag << " :#{option.name}"
98
+ default = option_default(option)
99
+ tag << " (#{default})" if default
100
+ tag.string
101
+ end
102
+
103
+ def option_default(option)
104
+ default = option.doc_default || option.default
105
+ return default unless option.name == :protocol
106
+
107
+ default.gsub('<DEFAULT_PROTOCOL>', protocols.keys.first || 'nil')
108
+ end
109
+
110
+ # @api private
111
+ class Operation
112
+ def initialize(service, model, id, operation)
113
+ @service = service
114
+ @model = model
115
+ @id = id
116
+ @operation = operation
117
+ @traits = operation.fetch('traits', {})
118
+ end
119
+
120
+ def docstrings # rubocop:disable Metrics/AbcSize
121
+ lines = []
122
+ lines.concat(documentation_docstrings)
123
+ lines.concat(params_docstrings)
124
+ lines.concat(OperationExamples.new(@model, method_name, @operation).docstrings)
125
+ lines.concat(RequestResponseExample.new(@model, method_name, @operation).docstrings)
126
+ lines.concat(deprecated_docstrings)
127
+ lines.concat(external_documentation_docstrings)
128
+ lines.concat(since_docstrings)
129
+ lines.concat(unstable_docstrings)
130
+ lines.concat(return_docstrings)
131
+ lines
132
+ end
133
+
134
+ def method_name
135
+ Model::Shape.name(@id).underscore
136
+ end
137
+
138
+ private
139
+
140
+ def documentation_docstrings
141
+ @traits.fetch('smithy.api#documentation', '').split("\n")
142
+ end
143
+
144
+ def params_docstrings
145
+ input_target = @operation['input']['target']
146
+ input = Model.shape(@model, input_target)
147
+
148
+ lines = []
149
+ lines << Model::YARD.param_docstring(@service, @model, input_target, input)
150
+ input['members'].each do |member_name, member_shape|
151
+ target = Model.shape(@model, member_shape['target'])
152
+ docstrings = Model::YARD.option_docstrings(
153
+ @service,
154
+ @model,
155
+ member_shape['target'],
156
+ target,
157
+ member_name.underscore,
158
+ param_docstrings(member_shape, target)
159
+ )
160
+ lines.concat(docstrings)
161
+ end
162
+ lines
163
+ end
164
+
165
+ def param_docstrings(member_shape, target)
166
+ documentation = member_shape.fetch('traits', {}).fetch('smithy.api#documentation', '').split("\n")
167
+ return documentation unless documentation.empty?
168
+
169
+ target.fetch('traits', {}).fetch('smithy.api#documentation', '').split("\n")
170
+ end
171
+
172
+ def deprecated_docstrings
173
+ return [] unless @traits.key?('smithy.api#deprecated')
174
+
175
+ message = @traits['smithy.api#deprecated'].fetch('message', '')
176
+ since = @traits['smithy.api#deprecated'].fetch('since', '')
177
+ Model::YARD.deprecated_docstrings(message, since)
178
+ end
179
+
180
+ def external_documentation_docstrings
181
+ return [] unless @traits.key?('smithy.api#externalDocumentation')
182
+
183
+ hash = @traits.fetch('smithy.api#externalDocumentation', {})
184
+ Model::YARD.external_documentation_docstrings(hash)
185
+ end
186
+
187
+ def since_docstrings
188
+ return [] unless @traits.key?('smithy.api#since')
189
+
190
+ [Model::YARD.since_docstring(@traits['smithy.api#since'])]
191
+ end
192
+
193
+ def unstable_docstrings
194
+ return [] unless @traits.key?('smithy.api#unstable')
195
+
196
+ [Model::YARD.unstable_docstring]
197
+ end
198
+
199
+ def return_docstrings
200
+ output_target = @operation['output']['target']
201
+ output = Model.shape(@model, output_target)
202
+ [Model::YARD.return_docstring(@service, @model, output_target, output)]
203
+ end
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,231 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smithy
4
+ module Views
5
+ module Client
6
+ # @api private
7
+ class ClientRbs < View
8
+ def initialize(plan, code_generated_plugins)
9
+ @plan = plan
10
+ @model = plan.model
11
+ @plugins = PluginList.new(plan, code_generated_plugins)
12
+ super()
13
+ end
14
+
15
+ def module_name
16
+ @plan.module_name
17
+ end
18
+
19
+ def option_types
20
+ @plugins
21
+ .map(&:options)
22
+ .flatten
23
+ .sort_by(&:name)
24
+ .select(&:docstring)
25
+ .to_h { |o| [o.name, rbs_type(o)] }
26
+ end
27
+
28
+ def operations
29
+ Model::ServiceIndex
30
+ .new(@model)
31
+ .operations_for(@plan.service)
32
+ .map { |id, operation| Operation.new(@model, id, operation) }
33
+ end
34
+
35
+ private
36
+
37
+ def rbs_type(option)
38
+ return option.rbs_type if option.rbs_type
39
+
40
+ return doc_to_rbs_types(option.doc_type) if option.doc_type
41
+
42
+ 'untyped'
43
+ end
44
+
45
+ # doc types may specify multiple types combined with ","
46
+ def doc_to_rbs_types(doc_type)
47
+ doc_type
48
+ .to_s
49
+ .split(',')
50
+ .map(&:strip)
51
+ .map { |t| doc_to_rbs_type(t) }
52
+ .join(' | ')
53
+ end
54
+
55
+ def doc_to_rbs_type(doc_type)
56
+ case doc_type
57
+ when 'Boolean' then 'bool'
58
+ else
59
+ doc_type
60
+ end
61
+ end
62
+
63
+ # @api private
64
+ class Operation
65
+ def initialize(model, id, operation)
66
+ @model = model
67
+ @id = id
68
+ @operation = operation
69
+ @input = Input.new(model, operation['input']['target'])
70
+ @output = Output.new(model, operation['output']['target'])
71
+ end
72
+
73
+ attr_reader :input, :output
74
+
75
+ def response_interface
76
+ "_#{Model::Shape.name(@id)}Response"
77
+ end
78
+
79
+ def name
80
+ Model::Shape.name(@id).underscore
81
+ end
82
+ end
83
+
84
+ # @api private
85
+ class Output
86
+ def initialize(model, id)
87
+ @model = model
88
+ @id = id
89
+ @shape = Model.shape(model, id)
90
+ end
91
+
92
+ def type
93
+ Model::RBS.type(@model, @id, @shape)
94
+ end
95
+
96
+ def member_types
97
+ @shape.fetch('members', {}).to_h do |member_name, member|
98
+ target = Model.shape(@model, member['target'])
99
+ [member_name.underscore, Model::RBS.type(@model, member['target'], target)]
100
+ end
101
+ end
102
+ end
103
+
104
+ # @api private
105
+ class Input
106
+ def initialize(model, id)
107
+ @model = model
108
+ @id = id
109
+ @shape = Model.shape(model, id)
110
+ end
111
+
112
+ def members?
113
+ @shape.fetch('members', {}).any?
114
+ end
115
+
116
+ # @return [Array<String>]
117
+ def keyword_args
118
+ lines = []
119
+ @shape.fetch('members', {}).each do |name, member|
120
+ member_lines = kwargs_structure_member(name, member['target'])
121
+ # top level members all need to be considered optional
122
+ member_lines[0] = "?#{member_lines[0].strip}"
123
+ lines += member_lines
124
+ end
125
+ lines.last&.chomp!(',')
126
+ lines
127
+ end
128
+
129
+ private
130
+
131
+ def kwargs_structure_member(name, id, level = 0, visited = Set.new)
132
+ return indent(["#{name.underscore}: untyped,"], level) if visited.include?(id)
133
+
134
+ visited << id
135
+ shape = Model.shape(@model, id)
136
+ if complex?(shape)
137
+ kwargs_complex_structure_member(level, name, shape, visited)
138
+ else
139
+ indent(["#{name.underscore}: #{Model::RBS.type(@model, nil, shape)},"], level)
140
+ end
141
+ end
142
+
143
+ def kwargs_complex_structure_member(level, name, shape, visited)
144
+ lines = kwargs_complex_shape(shape, level, visited)
145
+ lines[0] = indent("#{name.underscore}: #{lines[0].strip}", level)
146
+ lines[lines.size - 1] = "#{lines.last},"
147
+ lines
148
+ end
149
+
150
+ def kwargs_complex_shape(shape, level, visited)
151
+ case shape['type']
152
+ when 'list'
153
+ kwargs_list(shape, level, visited)
154
+ when 'map'
155
+ kwargs_map(shape, level, visited)
156
+ when 'structure', 'union'
157
+ kwargs_structure(shape, level, visited)
158
+ else
159
+ ['untyped']
160
+ end
161
+ end
162
+
163
+ def kwargs_structure(shape, level, visited)
164
+ lines = [indent('{', level)]
165
+ shape.fetch('members', {}).each do |name, member|
166
+ lines += kwargs_structure_member(name, member['target'], level + 1, visited)
167
+ end
168
+ lines[lines.size - 1] = lines.last.chomp(',')
169
+ lines << indent('}', level)
170
+ lines
171
+ end
172
+
173
+ def kwargs_list(shape, level, visited)
174
+ member_target = Model.shape(@model, shape['member']['target'])
175
+ if complex?(member_target)
176
+ lines = [indent('Array[', level)]
177
+ lines += kwargs_complex_shape(member_target, level + 1, visited)
178
+ lines << indent(']', level)
179
+ lines
180
+ else
181
+ sparse = shape.fetch('traits', {}).key?('smithy.api#sparse')
182
+ indent(
183
+ ["Array[#{Model::RBS.type(@model, shape['member']['target'], member_target)}#{'?' if sparse}]"],
184
+ level
185
+ )
186
+ end
187
+ end
188
+
189
+ def kwargs_map(shape, level, visited)
190
+ key_target = Model.shape(@model, shape['key']['target'])
191
+ key_type = Model::RBS.type(@model, shape['key']['target'], key_target)
192
+ value_target = Model.shape(@model, shape['value']['target'])
193
+ if complex?(value_target)
194
+ kwargs_complex__map(key_type, level, value_target, visited)
195
+ else
196
+ kwargs_simple_map(key_type, level, shape, value_target)
197
+ end
198
+ end
199
+
200
+ def kwargs_simple_map(key_type, level, shape, value_target)
201
+ sparse = shape.fetch('traits', {}).key?('smithy.api#sparse')
202
+ value_type = Model::RBS.type(@model, shape['value']['target'], value_target)
203
+ indent(
204
+ ["Hash[#{key_type}, #{value_type}#{'?' if sparse}]"],
205
+ level
206
+ )
207
+ end
208
+
209
+ def kwargs_complex__map(key_type, level, value_target, visited)
210
+ lines = [indent("Hash[#{key_type},", level)]
211
+ lines += kwargs_complex_shape(value_target, level + 1, visited)
212
+ lines << indent(']', level)
213
+ lines
214
+ end
215
+
216
+ def complex?(shape)
217
+ %w[list map structure union].include?(shape['type'])
218
+ end
219
+
220
+ def indent(str, level)
221
+ case str
222
+ when Array then str.map { |s| indent(s, level) }
223
+ else
224
+ (' ' * level) + str
225
+ end
226
+ end
227
+ end
228
+ end
229
+ end
230
+ end
231
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smithy
4
+ module Views
5
+ module Client
6
+ # @api private
7
+ class Customizations < View; end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,156 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smithy
4
+ module Views
5
+ module Client
6
+ # @api private
7
+ class EndpointParameter
8
+ def initialize(id, data, plan, operation = nil)
9
+ @id = id
10
+ @data = data
11
+ @plan = plan
12
+ @model = @plan.model
13
+ @service = @plan.service.values.first
14
+
15
+ @operation = operation
16
+
17
+ @name = @id.underscore
18
+ @value, @source = endpoint_parameter_value(operation)
19
+ end
20
+
21
+ attr_reader :id, :data, :name, :source, :value
22
+
23
+ def docstrings
24
+ @data['documentation'].split("\n")
25
+ end
26
+
27
+ def documentation_type
28
+ case @data['type'].downcase
29
+ when 'stringarray' then 'Array<String>'
30
+ when 'string' then 'String'
31
+ when 'boolean' then 'Boolean'
32
+ else
33
+ @data['type']
34
+ end
35
+ end
36
+
37
+ def rbs_type
38
+ case @data['type'].downcase
39
+ when 'stringarray' then 'Array[String]'
40
+ when 'string' then 'String'
41
+ when 'boolean' then 'bool'
42
+ else
43
+ @data['type']
44
+ end
45
+ end
46
+
47
+ def default_value
48
+ default = @data['default']
49
+ case default
50
+ when String then "\"#{default}\""
51
+ when nil then 'nil'
52
+ else
53
+ default
54
+ end
55
+ end
56
+
57
+ def validate_required?
58
+ @data['required'] && !@data['default']
59
+ end
60
+
61
+ def create_from_config?
62
+ @source == 'config'
63
+ end
64
+
65
+ def built_in?
66
+ @data['builtIn']
67
+ end
68
+
69
+ def built_in_binding
70
+ @built_in_binding ||=
71
+ @plan.welds
72
+ .map(&:endpoint_built_in_bindings)
73
+ .map { |b| b[@data['builtIn']] }
74
+ .find { |b| !b.nil? }
75
+ end
76
+
77
+ def client_context?
78
+ @service['traits']['smithy.rules#clientContextParams']&.key?(@id) && !@data['builtIn']
79
+ end
80
+
81
+ def client_context_doc
82
+ @service['traits']['smithy.rules#clientContextParams'][@id]['documentation']
83
+ end
84
+
85
+ private
86
+
87
+ # Highest to lowest priority:
88
+ # 1. staticContextParams
89
+ # 2. contextParam
90
+ # 3. operationContextParams
91
+ # 4. clientContextParams (always sourced from config)
92
+ # 5. Built-In Bindings (sourced from config in most cases)
93
+ # @return [value, source]. source may be one of [operation, config, default]
94
+ def endpoint_parameter_value(operation)
95
+ unless operation.nil?
96
+ value = static_context_param(operation)
97
+ value = context_param_value(operation) if value.nil?
98
+ value = operation_context_param_value(operation) if value.nil?
99
+ source = 'operation' unless value.nil?
100
+ end
101
+
102
+ value, source = client_context_param_value if value.nil?
103
+ value, source = built_in_param_value if value.nil?
104
+
105
+ [value, source]
106
+ end
107
+
108
+ def static_context_param(operation)
109
+ value = operation.dig('traits', 'smithy.rules#staticContextParams', @id, 'value')
110
+ if !value.nil? && value.is_a?(String)
111
+ "\"#{value}\""
112
+ else
113
+ value
114
+ end
115
+ end
116
+
117
+ def context_param_value(operation)
118
+ return nil unless operation['input']
119
+
120
+ input = Model.shape(@model, operation['input']['target'])
121
+ context_param_member(input['members'])
122
+ end
123
+
124
+ def context_param_member(members)
125
+ members.find do |(member_name, member_def)|
126
+ context_param = member_def.fetch('traits', {}).fetch('smithy.rules#contextParam', {})
127
+ break "params[:#{member_name.underscore}]" if context_param.fetch('name', nil) == @id
128
+ end
129
+ end
130
+
131
+ def operation_context_param_value(operation)
132
+ return nil unless operation['input']
133
+
134
+ binding = operation.fetch('traits', {}).fetch('smithy.rules#operationContextParams', {})[@id]
135
+
136
+ return nil unless binding
137
+
138
+ "JMESPath.search(\"#{Util::Underscore.underscore_jmespath(binding['path'])}\", params)"
139
+ end
140
+
141
+ def client_context_param_value
142
+ return unless client_context?
143
+
144
+ ["config.#{name}", 'config']
145
+ end
146
+
147
+ def built_in_param_value
148
+ return unless @data['builtIn']
149
+ raise ArgumentError, "Endpoint built-in not available for #{@data['builtIn']}" unless built_in_binding
150
+
151
+ [built_in_binding[:render_build].call(@plan, nil), 'config']
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smithy
4
+ module Views
5
+ module Client
6
+ # @api private
7
+ class EndpointParameters < View
8
+ def initialize(plan)
9
+ @plan = plan
10
+ @model = plan.model
11
+ service = @plan.service
12
+ @endpoint_rules = service.values.first['traits']['smithy.rules#endpointRuleSet']
13
+ @operations = Model::ServiceIndex.new(@model).operations_for(@plan.service)
14
+ @parameters = @endpoint_rules['parameters']
15
+ .map { |id, data| EndpointParameter.new(id, data, @plan) }
16
+ @operation_params = build_operation_params
17
+
18
+ super()
19
+ end
20
+
21
+ attr_reader :parameters, :operation_params
22
+
23
+ def module_name
24
+ @plan.module_name
25
+ end
26
+
27
+ private
28
+
29
+ def build_operation_params
30
+ operation_params = {}
31
+ @operations.each do |operation_id, operation|
32
+ name = operation_id.split('#').last.underscore
33
+ params = @endpoint_rules['parameters']
34
+ .map { |id, data| EndpointParameter.new(id, data, @plan, operation) }
35
+ .select { |p| p.source == 'operation' }
36
+ operation_params[name] = params unless params.empty?
37
+ end
38
+ operation_params
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smithy
4
+ module Views
5
+ module Client
6
+ # @api private
7
+ class EndpointParametersRbs < View
8
+ def initialize(plan)
9
+ @plan = plan
10
+ @model = plan.model
11
+ service = @plan.service
12
+ @endpoint_rules = service.values.first['traits']['smithy.rules#endpointRuleSet']
13
+ @operations = Model::ServiceIndex.new(@model).operations_for(@plan.service)
14
+ @parameters = @endpoint_rules['parameters']
15
+ .map { |id, data| EndpointParameter.new(id, data, @plan) }
16
+
17
+ super()
18
+ end
19
+
20
+ attr_reader :parameters
21
+
22
+ def module_name
23
+ @plan.module_name
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smithy
4
+ module Views
5
+ module Client
6
+ # @api private
7
+ class EndpointPlugin < View
8
+ def initialize(plan)
9
+ @plan = plan
10
+ @model = plan.model
11
+ service = @plan.service.values.first
12
+ @endpoint_rules = service['traits']['smithy.rules#endpointRuleSet']
13
+ @parameters = @endpoint_rules['parameters']
14
+ .map { |id, data| EndpointParameter.new(id, data, @plan) }
15
+
16
+ super()
17
+ end
18
+
19
+ attr_reader :plan, :parameters
20
+
21
+ def module_name
22
+ @plan.module_name
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end