From 833d3ac6d0c9c7ca0f828e42d447ec108ef281a0 Mon Sep 17 00:00:00 2001 From: Matt Muller Date: Mon, 11 Aug 2025 12:56:05 -0400 Subject: [PATCH 01/14] Rest XML --- .github/workflows/ci.yml | 6 + Gemfile | 1 + gems/smithy-cbor/lib/smithy-cbor/builder.rb | 2 +- gems/smithy-cbor/lib/smithy-cbor/parser.rb | 2 +- gems/smithy-json/lib/smithy-json/builder.rb | 2 +- gems/smithy-json/lib/smithy-json/codec.rb | 2 +- gems/smithy-json/lib/smithy-json/parser.rb | 2 +- .../spec/smithy-json/parser_spec.rb | 2 +- .../lib/smithy-schema/structure.rb | 5 + .../sig/smithy-schema/structure.rbs | 1 + .../spec/smithy-schema/structure_spec.rb | 11 + gems/smithy-xml/lib/smithy-xml/builder.rb | 28 +- gems/smithy-xml/lib/smithy-xml/doc_builder.rb | 2 +- gems/smithy-xml/lib/smithy-xml/parser.rb | 2 +- .../smithy-xml/lib/smithy-xml/parser/frame.rb | 27 +- .../lib/smithy-xml/parser/nokogiri_engine.rb | 1 + .../spec/smithy-xml/builder_spec.rb | 199 +++++++++++++ .../smithy-xml/spec/smithy-xml/parser_spec.rb | 281 ++++++++++++++++++ .../lib/smithy/views/client/protocol_spec.rb | 3 + gems/smithy/lib/smithy/views/client/schema.rb | 34 ++- 20 files changed, 568 insertions(+), 45 deletions(-) create mode 100644 gems/smithy-xml/spec/smithy-xml/builder_spec.rb create mode 100644 gems/smithy-xml/spec/smithy-xml/parser_spec.rb diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3e8741a8b..ab70543fa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -61,6 +61,12 @@ jobs: with: gem-name: 'smithy-json' + smithy-xml: + needs: [smithy-schema] + uses: ./.github/workflows/test.yml + with: + gem-name: 'smithy-xml' + smithy-client: needs: [smithy-schema] uses: ./.github/workflows/test.yml diff --git a/Gemfile b/Gemfile index 80f854113..722ddde53 100644 --- a/Gemfile +++ b/Gemfile @@ -11,6 +11,7 @@ gem 'smithy-client', path: 'gems/smithy-client' gem 'smithy-json', path: 'gems/smithy-json' # gem 'smithy-server', path: 'gems/smithy-server' gem 'smithy-schema', path: 'gems/smithy-schema' +gem 'smithy-xml', path: 'gems/smithy-xml' group :development do gem 'byebug', platforms: :ruby diff --git a/gems/smithy-cbor/lib/smithy-cbor/builder.rb b/gems/smithy-cbor/lib/smithy-cbor/builder.rb index 703f42097..ff8e3ecba 100644 --- a/gems/smithy-cbor/lib/smithy-cbor/builder.rb +++ b/gems/smithy-cbor/lib/smithy-cbor/builder.rb @@ -13,7 +13,7 @@ def initialize(options = {}) end def build(shape, data) - ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape) + ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, member_name: shape.name) return if ref.shape == Prelude::Unit Cbor.encode(shape(ref, data)) diff --git a/gems/smithy-cbor/lib/smithy-cbor/parser.rb b/gems/smithy-cbor/lib/smithy-cbor/parser.rb index 96f638aaa..cc54e5634 100644 --- a/gems/smithy-cbor/lib/smithy-cbor/parser.rb +++ b/gems/smithy-cbor/lib/smithy-cbor/parser.rb @@ -15,7 +15,7 @@ def initialize(options = {}) def parse(shape, bytes, target = nil) return {} if bytes.empty? - ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape) + ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, member_name: shape.name) shape(ref, Cbor.decode(bytes), target) end diff --git a/gems/smithy-json/lib/smithy-json/builder.rb b/gems/smithy-json/lib/smithy-json/builder.rb index 6230b2ab4..e040676dc 100644 --- a/gems/smithy-json/lib/smithy-json/builder.rb +++ b/gems/smithy-json/lib/smithy-json/builder.rb @@ -13,7 +13,7 @@ def initialize(options = {}) end def build(shape, data) - ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape) + ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, member_name: shape.name) Smithy::Json.dump(shape(ref, data)) end diff --git a/gems/smithy-json/lib/smithy-json/codec.rb b/gems/smithy-json/lib/smithy-json/codec.rb index 700f105be..82e8abd25 100644 --- a/gems/smithy-json/lib/smithy-json/codec.rb +++ b/gems/smithy-json/lib/smithy-json/codec.rb @@ -2,7 +2,7 @@ module Smithy module Json - # @api private + # Codec that builds and parses in JSON format. class Codec # @param [Hash] options def initialize(options = {}) diff --git a/gems/smithy-json/lib/smithy-json/parser.rb b/gems/smithy-json/lib/smithy-json/parser.rb index b615f3f25..b9e1403af 100644 --- a/gems/smithy-json/lib/smithy-json/parser.rb +++ b/gems/smithy-json/lib/smithy-json/parser.rb @@ -15,7 +15,7 @@ def initialize(options = {}) def parse(shape, bytes, target = nil) return {} if bytes.empty? - ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape) + ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, member_name: shape.name) shape(ref, Smithy::Json.load(bytes), target) end diff --git a/gems/smithy-json/spec/smithy-json/parser_spec.rb b/gems/smithy-json/spec/smithy-json/parser_spec.rb index 411f1361a..13fb46127 100644 --- a/gems/smithy-json/spec/smithy-json/parser_spec.rb +++ b/gems/smithy-json/spec/smithy-json/parser_spec.rb @@ -74,7 +74,7 @@ module Json expect(subject.parse(structure_shape, bytes).to_h).to eq(expected) end - it 'builds and parses structures with jsonName' do + it 'parses structures with jsonName' do subject = described_class.new(json_name: true) shapes['smithy.ruby.tests#Structure']['members']['string'] = { 'target' => 'smithy.api#String', diff --git a/gems/smithy-schema/lib/smithy-schema/structure.rb b/gems/smithy-schema/lib/smithy-schema/structure.rb index 9b7b615c8..755e15eeb 100644 --- a/gems/smithy-schema/lib/smithy-schema/structure.rb +++ b/gems/smithy-schema/lib/smithy-schema/structure.rb @@ -26,6 +26,11 @@ def empty? values.compact == [] end + # @return [Boolean] + def key?(member_name) + !self[member_name].nil? + end + private def _to_h_structure(obj) diff --git a/gems/smithy-schema/sig/smithy-schema/structure.rbs b/gems/smithy-schema/sig/smithy-schema/structure.rbs index a1dd25919..f44e3b749 100644 --- a/gems/smithy-schema/sig/smithy-schema/structure.rbs +++ b/gems/smithy-schema/sig/smithy-schema/structure.rbs @@ -3,6 +3,7 @@ module Smithy module Structure def to_h: () -> ::Hash[Symbol, ::Object] def empty?: () -> bool + def key?: (Symbol) -> bool end end end \ No newline at end of file diff --git a/gems/smithy-schema/spec/smithy-schema/structure_spec.rb b/gems/smithy-schema/spec/smithy-schema/structure_spec.rb index 1d37edad5..7e84220d1 100644 --- a/gems/smithy-schema/spec/smithy-schema/structure_spec.rb +++ b/gems/smithy-schema/spec/smithy-schema/structure_spec.rb @@ -71,6 +71,17 @@ module Schema expect(structure.new(value: 'not nil').empty?).to be false end end + + describe '#key?' do + it 'returns false if the value is nil' do + empty_struct = structure.new + expect(empty_struct.key?(:value)).to be false + end + + it 'returns true if the value is not nil' do + expect(subject.key?(:value)).to be true + end + end end end end diff --git a/gems/smithy-xml/lib/smithy-xml/builder.rb b/gems/smithy-xml/lib/smithy-xml/builder.rb index f55882af2..bbdbd71d9 100644 --- a/gems/smithy-xml/lib/smithy-xml/builder.rb +++ b/gems/smithy-xml/lib/smithy-xml/builder.rb @@ -14,7 +14,7 @@ def initialize(options = {}) end def build(shape, data, target = nil) - ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape) + ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, member_name: shape.name) target ||= [] @builder = DocBuilder.new(target: target, indent: @indent, pad: @pad) structure(location_name(ref, ref.member_name), ref, data) @@ -30,6 +30,7 @@ def shape(name, ref, value) when MapShape then map(name, ref, value) when StructureShape then structure(name, ref, value) when TimestampShape then node(name, ref, timestamp(ref, value)) + when UnionShape then union(name, ref, value) else node(name, ref, value.to_s) end end @@ -39,6 +40,8 @@ def blob(value) end def list(name, ref, values) + return node(name, ref) if values.empty? + member_ref = ref.shape.member if flat?(ref) values.each do |value| @@ -54,6 +57,8 @@ def list(name, ref, values) end def map(name, ref, values) # rubocop:disable Metrics/AbcSize + return node(name, ref) if values.empty? + key_ref = ref.shape.key value_ref = ref.shape.value if flat?(ref) @@ -76,6 +81,8 @@ def map(name, ref, values) # rubocop:disable Metrics/AbcSize end def structure(name, ref, values) + return node(name, ref) if values.empty? + node(name, ref, structure_attrs(ref, values)) do ref.shape.members.each do |member_name, member_ref| next if values[member_name].nil? @@ -97,7 +104,7 @@ def structure_attrs(ref, values) def timestamp(ref, value) trait = 'smithy.api#timestampFormat' case ref.traits[trait] || ref.shape.traits[trait] - when 'epoch-seconds' then value.to_s + when 'epoch-seconds' then value.to_i.to_s when 'http-date' then value.utc.httpdate else # default to date-time @@ -105,6 +112,23 @@ def timestamp(ref, value) end end + def union(name, ref, values) # rubocop:disable Metrics/AbcSize + return node(name, ref) if values.empty? + + node(name, ref, structure_attrs(ref, values)) do + if values.is_a?(Schema::Union) + _name, member_ref = ref.shape.member_by_type(values.class) + shape(location_name(member_ref, member_ref.member_name), member_ref, values.value) + else + key, value = values.first + if ref.shape.member?(key) + member_ref = ref.shape.member(key) + shape(location_name(member_ref, member_ref.member_name), member_ref, value) + end + end + end + end + def location_name(ref, default = nil) ref.traits['smithy.api#xmlName'] || default end diff --git a/gems/smithy-xml/lib/smithy-xml/doc_builder.rb b/gems/smithy-xml/lib/smithy-xml/doc_builder.rb index 2e1131fed..0431dad29 100644 --- a/gems/smithy-xml/lib/smithy-xml/doc_builder.rb +++ b/gems/smithy-xml/lib/smithy-xml/doc_builder.rb @@ -66,7 +66,7 @@ def close_el(name) def attributes(attr) return '' if attr.empty? - " #{attr.map { |key, value| "#{key}=#{escape(value, :attr)}" }.join(' ')}" + " #{attr.map { |key, value| "#{key}=#{escape(value.to_s, :attr)}" }.join(' ')}" end def escape(string, text_or_attr) diff --git a/gems/smithy-xml/lib/smithy-xml/parser.rb b/gems/smithy-xml/lib/smithy-xml/parser.rb index 9f54726a4..be0a1e69f 100644 --- a/gems/smithy-xml/lib/smithy-xml/parser.rb +++ b/gems/smithy-xml/lib/smithy-xml/parser.rb @@ -27,7 +27,7 @@ def initialize(options = {}) # @param [Object, nil] target (nil) # @return [Object] def parse(shape, bytes, target = nil, &) - ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape) + ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, member_name: shape.name) bytes = '' if bytes.nil? || bytes.empty? stack = Stack.new(ref, target, &) @engine.new(stack).parse(bytes.to_s) diff --git a/gems/smithy-xml/lib/smithy-xml/parser/frame.rb b/gems/smithy-xml/lib/smithy-xml/parser/frame.rb index 21db358a4..57074ba96 100644 --- a/gems/smithy-xml/lib/smithy-xml/parser/frame.rb +++ b/gems/smithy-xml/lib/smithy-xml/parser/frame.rb @@ -243,8 +243,8 @@ def initialize(xml_name, parent, ref, result = nil) def child_frame(xml_name) if (@member = @members[xml_name]) Frame.new(xml_name, self, @member[:ref]) - # elsif @ref.shape.union - # UnknownMemberFrame.new(xml_name, self, nil, @result) + elsif @ref.shape.is_a?(UnionShape) + UnknownMemberFrame.new(xml_name, self, nil, @result) else NullFrame.new(xml_name, self) end @@ -258,24 +258,11 @@ def consume_child_frame(child) # rubocop:disable Metrics/AbcSize when FlatListFrame @result[@member[:name]] ||= [] @result[@member[:name]] << child.result - # when UnknownMemberFrame - # @result[:unknown] = { 'name' => child.path.last, 'value' => child.result } + when UnknownMemberFrame + @result[:unknown] = { child.path.last => child.result } when NullFrame # do nothing - else - @result[@member[:name]] = child.result + else @result[@member[:name]] = child.result end - - # if @ref.shape.union - # # a union may only have one member set - # # convert to the union subclass - # # The default Struct created will have defaults set for all values - # # This also sets only one of the values leaving everything else nil - # # as required for unions - # set_member_name = @member ? @member[:name] : :unknown - # member_subclass = @ref.shape.member_subclass(set_member_name).new - # member_subclass[set_member_name] = @result[set_member_name] - # @result = member_subclass - # end end private @@ -283,10 +270,6 @@ def consume_child_frame(child) # rubocop:disable Metrics/AbcSize def xml_name(ref) ref.traits['smithy.api#xmlName'] || ref.member_name end - - def flattened_list?(ref) - ref.shape.is_a?(ListShape) && ref.traits.key?('smithy.api#xmlFlattened') - end end # @api private diff --git a/gems/smithy-xml/lib/smithy-xml/parser/nokogiri_engine.rb b/gems/smithy-xml/lib/smithy-xml/parser/nokogiri_engine.rb index d5e6b2ee2..c73bf4e01 100644 --- a/gems/smithy-xml/lib/smithy-xml/parser/nokogiri_engine.rb +++ b/gems/smithy-xml/lib/smithy-xml/parser/nokogiri_engine.rb @@ -19,6 +19,7 @@ def xmldecl(*_ignored); end def start_document; end def end_document; end def comment(*_ignored); end + def cdata_block(*_ignored); end def start_element_namespace(name, attrs = [], *_ignored) @stack.start_element(name) diff --git a/gems/smithy-xml/spec/smithy-xml/builder_spec.rb b/gems/smithy-xml/spec/smithy-xml/builder_spec.rb new file mode 100644 index 000000000..272ee25d6 --- /dev/null +++ b/gems/smithy-xml/spec/smithy-xml/builder_spec.rb @@ -0,0 +1,199 @@ +# frozen_string_literal: true + +require_relative '../spec_helper' + +require 'rexml' + +module Smithy + module Xml + describe Builder do + let(:shapes) { SchemaHelper.sample_shapes } + let(:sample_schema) { SchemaHelper.sample_schema(shapes: shapes) } + let(:structure_shape) { sample_schema.const_get(:Structure) } + + def rexml(xml) + REXML::Document.new(xml).to_s.gsub(/>\s+?<').strip + end + + it 'returns an empty frame when given a unit shape' do + ref = Schema::Shapes::ShapeRef.new(shape: Schema::Shapes::Prelude::Unit, member_name: 'unit') + expect(subject.build(ref, '')).to eq('') + end + + context 'structures' do + before { allow(Time).to receive(:at).and_return(time) } + let(:time) { Time.now } + let(:data) do + { + big_decimal: 0.0, + big_integer: 0, + blob: 'blob', + boolean: false, + byte: 0, + double: 0.0, + enum: 'enum', + float: 0.0, + int_enum: 0, + integer: 0, + list: [], + long: 0, + map: {}, + short: 0, + streaming_blob: 'streaming blob', + string: 'string', + structure_list: [], + structure_map: {}, + timestamp: time, + union: { string: 'string' } + } + end + let(:expected) do + { + 'bigDecimal' => 0.0, + 'bigInteger' => 0, + 'blob' => 'YmxvYg==', + 'boolean' => false, + 'byte' => 0, + 'double' => 0.0, + 'enum' => 'enum', + 'float' => 0.0, + 'intEnum' => 0, + 'integer' => 0, + 'list' => [], + 'long' => 0, + 'map' => {}, + 'short' => 0, + 'streamingBlob' => 'c3RyZWFtaW5nIGJsb2I=', + 'string' => 'string', + 'structureList' => [], + 'structureMap' => {}, + 'timestamp' => time.to_i, + 'union' => { 'string' => 'string' } + } + end + + it 'builds structures as a type' do + type = structure_shape.type.new(data.merge(structure: data)) + bytes = subject.build(structure_shape, type) + expect(bytes).to eq(rexml(bytes)) + end + + it 'builds structures as a hash' do + bytes = subject.build(structure_shape, data.merge(structure: data)) + expect(bytes).to eq(rexml(bytes)) + end + + it 'builds structures with xmlName' do + shapes['smithy.ruby.tests#Structure']['members']['string'] = { + 'target' => 'smithy.api#String', + 'traits' => { 'smithy.api#xmlName' => 'NewString' } + } + data = { string: 'string' } + bytes = subject.build(structure_shape, data) + expect(bytes).to include('string') + end + end + + context 'unions' do + it 'builds unions as a type' do + union = structure_shape.member(:union).shape.member_type(:string).new(string: 'string') + type = structure_shape.type.new(union: union) + bytes = subject.build(structure_shape, type) + expect(bytes).to include('string') + end + + it 'builds unions as a hash' do + data = { union: { string: 'string' } } + bytes = subject.build(structure_shape, data) + expect(bytes).to include('string') + end + + it 'builds union unit members as a type' do + union = structure_shape.member(:union).shape.member_type(:unit).new(unit: Schema::EmptyStructure.new) + type = structure_shape.type.new(union: union) + bytes = subject.build(structure_shape, type) + expect(bytes).to include('') + end + + it 'builds union unit members as a hash' do + data = { union: { unit: {} } } + bytes = subject.build(structure_shape, data) + expect(bytes).to include('') + end + + it 'builds a nil union' do + data = { union: nil } + bytes = subject.build(structure_shape, data) + expect(bytes).to eq('') + end + + it 'builds union members with xmlName' do + shapes['smithy.ruby.tests#Union']['members']['string'] = { + 'target' => 'smithy.api#String', + 'traits' => { 'smithy.api#xmlName' => 'NewString' } + } + data = { union: { string: 'string' } } + bytes = subject.build(structure_shape, data) + expect(bytes).to include('string') + end + end + + context 'lists' do + it 'builds lists' do + data = { list: ['string'] } + bytes = subject.build(structure_shape, data) + expect(bytes).to include('string') + end + + it 'builds lists with nil values' do + data = { list: [nil] } + bytes = subject.build(structure_shape, data) + expect(bytes).to include('') + end + end + + context 'maps' do + it 'builds maps' do + data = { map: { 'key' => 'value' } } + bytes = subject.build(structure_shape, data) + expect(bytes).to include('keyvalue') + end + + it 'builds maps with nil values' do + data = { map: { 'key' => nil } } + bytes = subject.build(structure_shape, data) + expect(bytes).to include('key') + end + end + + context 'timestamps' do + it 'builds date-time format by default' do + time = Time.now.utc + data = { timestamp: time } + bytes = subject.build(structure_shape, data) + expect(bytes).to include("#{time.utc.iso8601}") + end + + it 'builds epoch seconds format' do + time = Time.now + shapes['smithy.ruby.tests#Structure']['members']['timestamp']['traits'] = { + 'smithy.api#timestampFormat' => 'epoch-seconds' + } + data = { timestamp: time } + bytes = subject.build(structure_shape, data) + expect(bytes).to include("#{time.to_i}") + end + + it 'builds http-date format' do + time = Time.now.utc + shapes['smithy.ruby.tests#Structure']['members']['timestamp']['traits'] = { + 'smithy.api#timestampFormat' => 'http-date' + } + data = { timestamp: time } + bytes = subject.build(structure_shape, data) + expect(bytes).to include("#{time.httpdate}") + end + end + end + end +end diff --git a/gems/smithy-xml/spec/smithy-xml/parser_spec.rb b/gems/smithy-xml/spec/smithy-xml/parser_spec.rb new file mode 100644 index 000000000..2a4a269fb --- /dev/null +++ b/gems/smithy-xml/spec/smithy-xml/parser_spec.rb @@ -0,0 +1,281 @@ +# frozen_string_literal: true + +require_relative '../spec_helper' + +module Smithy + module Xml + describe Parser do + let(:shapes) { SchemaHelper.sample_shapes } + let(:sample_schema) { SchemaHelper.sample_schema(shapes: shapes) } + let(:structure_shape) { sample_schema.const_get(:Structure) } + + it 'returns an empty structure when given a unit shape' do + expect(subject.parse(Schema::Shapes::Prelude::Unit, '')).to be_a(Schema::EmptyStructure) + end + + context 'structures' do + before { allow(Time).to receive(:at).and_return(time) } + let(:time) { Time.now } + let(:data) do + { + 'bigDecimal' => 0.0, + 'bigInteger' => 0, + 'blob' => 'YmxvYg==', + 'boolean' => false, + 'byte' => 0, + 'double' => 0.0, + 'enum' => 'enum', + 'float' => 0.0, + 'intEnum' => 0, + 'integer' => 0, + 'list' => [], + 'long' => 0, + 'map' => {}, + 'short' => 0, + 'streamingBlob' => 'c3RyZWFtaW5nIGJsb2I=', + 'string' => 'string', + 'structureList' => [], + 'structureMap' => {}, + 'timestamp' => time, + 'union' => { 'string' => 'string' } + } + end + let(:expected) do + { + big_decimal: 0.0, + big_integer: 0, + blob: 'blob', + boolean: false, + byte: 0, + double: 0.0, + enum: 'enum', + float: 0.0, + int_enum: 0, + integer: 0, + list: [], + long: 0, + map: {}, + short: 0, + streaming_blob: 'streaming blob', + string: 'string', + structure_list: [], + structure_map: {}, + timestamp: time, + union: { string: 'string' } + } + end + + it 'parses structures' do + bytes = <<~XML + + 0.0 + 0 + YmxvYg== + false + 0 + 0.0 + enum + 0.0 + 0 + 0 + + 0 + + 0 + c3RyZWFtaW5nIGJsb2I= + string + + + #{time.to_i} + + string + + + XML + expect(subject.parse(structure_shape, bytes).to_h).to eq(expected) + end + + it 'parses structures with jsonName' do + shapes['smithy.ruby.tests#Structure']['members']['string'] = { + 'target' => 'smithy.api#String', + 'traits' => { 'smithy.api#xmlName' => 'NewString' } + } + bytes = <<~XML + + string + + XML + expect(subject.parse(structure_shape, bytes).to_h).to eq(string: 'string') + end + end + + context 'unions' do + it 'parses unions' do + bytes = <<~XML + + + string + + + XML + expect(subject.parse(structure_shape, bytes).to_h).to eq(union: { string: 'string' }) + end + + it 'parses unit members' do + bytes = <<~XML + + + + + + XML + expect(subject.parse(structure_shape, bytes).to_h).to eq(union: { unit: {} }) + end + + it 'parses nil unions' do + bytes = <<~XML + + + + XML + expect(subject.parse(structure_shape, bytes).to_h).to eq(union: {}) + end + + it 'parses unknown members' do + bytes = <<~XML + + + someValue + + + XML + expect(subject.parse(structure_shape, bytes).to_h).to eq(union: { unknown: { 'someThing' => 'someValue' } }) + end + end + + context 'lists' do + it 'parses lists' do + bytes = <<~XML + + + string + + + XML + expect(subject.parse(structure_shape, bytes).to_h).to eq(list: ['string']) + end + + it 'parses lists with nil values' do + bytes = <<~XML + + + + + + XML + expect(subject.parse(structure_shape, bytes).to_h).to eq(list: ['']) + end + end + + context 'maps' do + it 'parses maps' do + bytes = <<~XML + + + + key + value + + + + XML + expect(subject.parse(structure_shape, bytes).to_h).to eq(map: { 'key' => 'value' }) + end + + it 'parses maps with nil values' do + bytes = <<~XML + + + + key + + + + + XML + expect(subject.parse(structure_shape, bytes).to_h).to eq(map: { 'key' => '' }) + end + end + + context 'floats' do + it 'parses infinity' do + bytes = <<~XML + + Infinity + + XML + expect(subject.parse(structure_shape, bytes).to_h).to eq(float: Float::INFINITY) + end + + it 'parses negative infinity' do + bytes = <<~XML + + -Infinity + + XML + expect(subject.parse(structure_shape, bytes).to_h).to eq(float: -Float::INFINITY) + end + + it 'parses NaN' do + bytes = <<~XML + + NaN + + XML + expect(subject.parse(structure_shape, bytes).to_h).to eq(float: Float::NAN) + end + end + + context 'timestamps' do + before { allow(Time).to receive(:at).and_return(time) } + let(:time) { Time.now } + + it 'parses epoch seconds' do + bytes = <<~XML + + #{time.to_i} + + XML + expect(subject.parse(structure_shape, bytes).to_h).to eq(timestamp: time) + end + + it 'parses date-time format' do + bytes = <<~XML + + #{time.utc.iso8601} + + XML + expect(subject.parse(structure_shape, bytes).to_h).to eq(timestamp: time) + end + + it 'parses http-date format' do + bytes = <<~XML + + #{time.utc.httpdate} + + XML + expect(subject.parse(structure_shape, bytes).to_h).to eq(timestamp: time) + end + + it 'handles unrecognized timestamp formats' do + bytes = <<~XML + + unrecognized format + + XML + expect { subject.parse(structure_shape, bytes) }.to raise_error(/unhandled timestamp format/) + end + end + end + end +end diff --git a/gems/smithy/lib/smithy/views/client/protocol_spec.rb b/gems/smithy/lib/smithy/views/client/protocol_spec.rb index 937a11c46..690a92e94 100644 --- a/gems/smithy/lib/smithy/views/client/protocol_spec.rb +++ b/gems/smithy/lib/smithy/views/client/protocol_spec.rb @@ -156,6 +156,9 @@ def body_expect "expect(Smithy::Json.load(request.body.read)).to eq(Smithy::Json.load('#{@test_case['body']}'))" when 'application/x-www-form-urlencoded' "expect(CGI.parse(request.body.read)).to eq(CGI.parse('#{@test_case['body']}'))" + when 'application/xml' + 'expect(Smithy::Xml::Parser.new.parse(response.context.operation.input, request.body.read)).' \ + "to eq(Smithy::Xml::Parser.new.parse(response.context.operation.input, '#{@test_case['body']}'))" else "expect(request.body.read).to eq('#{@test_case['body']}')" end diff --git a/gems/smithy/lib/smithy/views/client/schema.rb b/gems/smithy/lib/smithy/views/client/schema.rb index ca524c890..22efcbbe4 100644 --- a/gems/smithy/lib/smithy/views/client/schema.rb +++ b/gems/smithy/lib/smithy/views/client/schema.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'set' + module Smithy module Views module Client @@ -91,17 +93,14 @@ class OperationShape def initialize(service, id, shape) _, @service = service.first @id = id - @input = ShapeRef.new(@service, nil, shape['input']) - @output = ShapeRef.new(@service, nil, shape['output']) - @errors = build_errors(@service['errors'] || []).concat(build_errors(shape['errors'] || [])) + @name = (@service.dig('rename', @id) || Model::Shape.name(@id)).camelize + @input = build_input(shape['input']) + @output = build_output(shape['output']) + @errors = build_errors(shape.fetch('errors', [])) @traits = shape.fetch('traits', {}) end - attr_reader :id, :input, :output, :errors - - def name - Model::Shape.name(@id) - end + attr_reader :id, :name, :input, :output, :errors def traits @traits.except(*OMITTED_TRAITS) @@ -112,13 +111,22 @@ def paginated? end def paginator - "Paginators::#{Model::Shape.name(@id)}.new" + "Paginators::#{@name}.new" end private + def build_input(input) + ShapeRef.new(@service, Model::Shape.name(input['target']), input) + end + + def build_output(output) + ShapeRef.new(@service, Model::Shape.name(output['target']), output) + end + def build_errors(errors) - errors.map { |shape_ref| ShapeRef.new(@service, nil, shape_ref) } + errors = Set.new(@service.fetch('errors', [])).merge(errors) + errors.map { |error| ShapeRef.new(@service, Model::Shape.name(error['target']), error) } end end @@ -198,7 +206,7 @@ def http_payload private def build_shape_refs(members) - members.map { |name, shape_ref| ShapeRef.new(@service, name, shape_ref) } + members.map { |name, member| ShapeRef.new(@service, name, member) } end end @@ -230,7 +238,7 @@ def initialize(service, id, shape) private def build_shape_refs(members) - members.map { |name, shape_ref| ShapeRef.new(@service, name, shape_ref) } + members.map { |name, member| ShapeRef.new(@service, name, member) } end end @@ -275,7 +283,7 @@ def union_type(shape_ref) private def build_shape_refs(members) - members.map { |name, shape_ref| ShapeRef.new(@service, name, shape_ref) } + members.map { |name, member| ShapeRef.new(@service, name, member) } end end From 6f1318d04da4ce1b18d8a5ce9f20a910bf7a55c8 Mon Sep 17 00:00:00 2001 From: Matt Muller Date: Mon, 11 Aug 2025 13:05:10 -0400 Subject: [PATCH 02/14] member_name -> location_name --- gems/smithy-cbor/lib/smithy-cbor/builder.rb | 8 +- gems/smithy-cbor/lib/smithy-cbor/parser.rb | 6 +- .../lib/smithy-client/plugins/host_prefix.rb | 2 +- .../lib/smithy-client/stubbing/empty_stub.rb | 2 +- gems/smithy-json/lib/smithy-json/builder.rb | 6 +- gems/smithy-json/lib/smithy-json/parser.rb | 6 +- .../document_utils/deserializer.rb | 4 +- .../document_utils/serializer.rb | 8 +- .../smithy-schema/lib/smithy-schema/shapes.rb | 4 +- .../sig/smithy-schema/shapes.rbs | 2 +- .../spec/smithy-schema/shapes_spec.rb | 6 +- gems/smithy-xml/lib/smithy-xml/builder.rb | 12 +-- gems/smithy-xml/lib/smithy-xml/parser.rb | 2 +- .../smithy-xml/lib/smithy-xml/parser/frame.rb | 2 +- .../spec/smithy-xml/builder_spec.rb | 2 +- gems/smithy/lib/smithy/model/shape.rb | 2 +- gems/smithy/lib/smithy/views/client/schema.rb | 2 +- gems/smithy/spec/smithy/model/shape_spec.rb | 6 +- projections/shapes/lib/shapes/schema.rb | 92 +++++++++---------- projections/weather/lib/weather/schema.rb | 48 +++++----- 20 files changed, 111 insertions(+), 111 deletions(-) diff --git a/gems/smithy-cbor/lib/smithy-cbor/builder.rb b/gems/smithy-cbor/lib/smithy-cbor/builder.rb index ff8e3ecba..bd6d95a40 100644 --- a/gems/smithy-cbor/lib/smithy-cbor/builder.rb +++ b/gems/smithy-cbor/lib/smithy-cbor/builder.rb @@ -13,7 +13,7 @@ def initialize(options = {}) end def build(shape, data) - ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, member_name: shape.name) + ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, location_name: shape.name) return if ref.shape == Prelude::Unit Cbor.encode(shape(ref, data)) @@ -61,7 +61,7 @@ def structure(ref, values) value = values[member_name] next if value.nil? - data[member_ref.member_name] = shape(member_ref, value) + data[member_ref.location_name] = shape(member_ref, value) end end @@ -71,12 +71,12 @@ def union(ref, values) # rubocop:disable Metrics/AbcSize data = {} if values.is_a?(Schema::Union) _name, member_ref = ref.shape.member_by_type(values.class) - data[member_ref.member_name] = shape(member_ref, values.value) + data[member_ref.location_name] = shape(member_ref, values.value) else key, value = values.first if ref.shape.member?(key) member_ref = ref.shape.member(key) - data[member_ref.member_name] = shape(member_ref, value) + data[member_ref.location_name] = shape(member_ref, value) end end data diff --git a/gems/smithy-cbor/lib/smithy-cbor/parser.rb b/gems/smithy-cbor/lib/smithy-cbor/parser.rb index cc54e5634..2f29300e8 100644 --- a/gems/smithy-cbor/lib/smithy-cbor/parser.rb +++ b/gems/smithy-cbor/lib/smithy-cbor/parser.rb @@ -15,7 +15,7 @@ def initialize(options = {}) def parse(shape, bytes, target = nil) return {} if bytes.empty? - ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, member_name: shape.name) + ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, location_name: shape.name) shape(ref, Cbor.decode(bytes), target) end @@ -56,7 +56,7 @@ def map(ref, values, target = nil) def structure(ref, values, target = nil) target = ref.shape.type.new if target.nil? ref.shape.members.each do |member_name, member_ref| - value = values[member_ref.member_name] + value = values[member_ref.location_name] target[member_name] = shape(member_ref, value) unless value.nil? end target @@ -64,7 +64,7 @@ def structure(ref, values, target = nil) def union(ref, values, target = nil) # rubocop:disable Metrics/AbcSize ref.shape.members.each do |member_name, member_ref| - value = values[member_ref.member_name] + value = values[member_ref.location_name] next if value.nil? target = ref.shape.member_type(member_name) if target.nil? diff --git a/gems/smithy-client/lib/smithy-client/plugins/host_prefix.rb b/gems/smithy-client/lib/smithy-client/plugins/host_prefix.rb index 73aeba5a9..0e174bd3e 100644 --- a/gems/smithy-client/lib/smithy-client/plugins/host_prefix.rb +++ b/gems/smithy-client/lib/smithy-client/plugins/host_prefix.rb @@ -53,7 +53,7 @@ def label_value(input, label, params) name = nil input.shape.members.each do |member_name, member_ref| next unless member_ref.traits.key?('smithy.api#hostLabel') - next unless member_ref.member_name == label + next unless member_ref.location_name == label name = member_name end diff --git a/gems/smithy-client/lib/smithy-client/stubbing/empty_stub.rb b/gems/smithy-client/lib/smithy-client/stubbing/empty_stub.rb index 6486017ab..ef18755f5 100644 --- a/gems/smithy-client/lib/smithy-client/stubbing/empty_stub.rb +++ b/gems/smithy-client/lib/smithy-client/stubbing/empty_stub.rb @@ -56,7 +56,7 @@ def union(ref, visited) def scalar(ref) case ref.shape when BigDecimalShape then BigDecimal(0) - when BlobShape, EnumShape, StringShape then ref.member_name + when BlobShape, EnumShape, StringShape then ref.location_name when BooleanShape then false when IntegerShape, IntEnumShape then 0 when FloatShape then 0.0 diff --git a/gems/smithy-json/lib/smithy-json/builder.rb b/gems/smithy-json/lib/smithy-json/builder.rb index e040676dc..5641e7afe 100644 --- a/gems/smithy-json/lib/smithy-json/builder.rb +++ b/gems/smithy-json/lib/smithy-json/builder.rb @@ -13,7 +13,7 @@ def initialize(options = {}) end def build(shape, data) - ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, member_name: shape.name) + ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, location_name: shape.name) Smithy::Json.dump(shape(ref, data)) end @@ -104,9 +104,9 @@ def union(ref, values) # rubocop:disable Metrics/AbcSize end def location_name(ref) - return ref.member_name unless @json_name + return ref.location_name unless @json_name - ref.traits['smithy.api#jsonName'] || ref.member_name + ref.traits['smithy.api#jsonName'] || ref.location_name end end end diff --git a/gems/smithy-json/lib/smithy-json/parser.rb b/gems/smithy-json/lib/smithy-json/parser.rb index b9e1403af..662680d8a 100644 --- a/gems/smithy-json/lib/smithy-json/parser.rb +++ b/gems/smithy-json/lib/smithy-json/parser.rb @@ -15,7 +15,7 @@ def initialize(options = {}) def parse(shape, bytes, target = nil) return {} if bytes.empty? - ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, member_name: shape.name) + ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, location_name: shape.name) shape(ref, Smithy::Json.load(bytes), target) end @@ -104,9 +104,9 @@ def union(ref, values, target = nil) # rubocop:disable Metrics/AbcSize end def location_name(ref) - return ref.member_name unless @json_name + return ref.location_name unless @json_name - ref.traits['smithy.api#jsonName'] || ref.member_name + ref.traits['smithy.api#jsonName'] || ref.location_name end def sparse?(shape) diff --git a/gems/smithy-schema/lib/smithy-schema/document_utils/deserializer.rb b/gems/smithy-schema/lib/smithy-schema/document_utils/deserializer.rb index 13d7b09b2..7104a1f34 100644 --- a/gems/smithy-schema/lib/smithy-schema/document_utils/deserializer.rb +++ b/gems/smithy-schema/lib/smithy-schema/document_utils/deserializer.rb @@ -115,9 +115,9 @@ def union(ref, values, target = nil) # rubocop:disable Metrics/AbcSize end def location_name(ref) - return ref.member_name unless @json_name + return ref.location_name unless @json_name - ref.traits['smithy.api#jsonName'] || ref.member_name + ref.traits['smithy.api#jsonName'] || ref.location_name end end end diff --git a/gems/smithy-schema/lib/smithy-schema/document_utils/serializer.rb b/gems/smithy-schema/lib/smithy-schema/document_utils/serializer.rb index f6a1ef676..3f98dfe21 100644 --- a/gems/smithy-schema/lib/smithy-schema/document_utils/serializer.rb +++ b/gems/smithy-schema/lib/smithy-schema/document_utils/serializer.rb @@ -147,9 +147,9 @@ def union(ref, values) end def location_name(ref) - return ref.member_name unless @json_name + return ref.location_name unless @json_name - ref.traits['smithy.api#jsonName'] || ref.member_name + ref.traits['smithy.api#jsonName'] || ref.location_name end def normalize_timestamp_value(value) @@ -164,7 +164,7 @@ def resolve_member_ref(ref, name) return ref.shape.member(name) if ref.shape.member?(name) ref.shape.members.values.find do |member_ref| - member_ref.traits['smithy.api#jsonName'] == name || member_ref.member_name == name + member_ref.traits['smithy.api#jsonName'] == name || member_ref.location_name == name end end @@ -173,7 +173,7 @@ def resolve_value(member_name, member_ref, values) value = values[json_name] return value unless value.nil? end - values[member_name] || values[member_ref.member_name] + values[member_name] || values[member_ref.location_name] end end end diff --git a/gems/smithy-schema/lib/smithy-schema/shapes.rb b/gems/smithy-schema/lib/smithy-schema/shapes.rb index b23bada97..401003842 100644 --- a/gems/smithy-schema/lib/smithy-schema/shapes.rb +++ b/gems/smithy-schema/lib/smithy-schema/shapes.rb @@ -38,7 +38,7 @@ def []=(key, value) class ShapeRef def initialize(options = {}) @shape = options[:shape] - @member_name = options[:member_name] + @member_name = options[:location_name] @traits = options[:traits] || {} @metadata = {} end @@ -47,7 +47,7 @@ def initialize(options = {}) attr_accessor :shape # @return [String, nil] - attr_accessor :member_name + attr_accessor :location_name # @return [Hash] attr_accessor :traits diff --git a/gems/smithy-schema/sig/smithy-schema/shapes.rbs b/gems/smithy-schema/sig/smithy-schema/shapes.rbs index 164c422b0..b21661af6 100644 --- a/gems/smithy-schema/sig/smithy-schema/shapes.rbs +++ b/gems/smithy-schema/sig/smithy-schema/shapes.rbs @@ -15,7 +15,7 @@ module Smithy def initialize: (?Hash[Symbol, untyped]) -> void attr_accessor shape: Shape - attr_accessor member_name: String? + attr_accessor location_name: String? attr_accessor traits: Hash[String, untyped] def []: (Symbol) -> Object def []=: (Symbol, Object) -> void diff --git a/gems/smithy-schema/spec/smithy-schema/shapes_spec.rb b/gems/smithy-schema/spec/smithy-schema/shapes_spec.rb index 69ea42ca3..846b92e3e 100644 --- a/gems/smithy-schema/spec/smithy-schema/shapes_spec.rb +++ b/gems/smithy-schema/spec/smithy-schema/shapes_spec.rb @@ -54,12 +54,12 @@ module Shapes end it 'defaults a location name to nil' do - expect(subject.member_name).to be_nil + expect(subject.location_name).to be_nil end it 'stores the member name as a location name' do - subject = ShapeRef.new(member_name: 'foo') - expect(subject.member_name).to eq('foo') + subject = ShapeRef.new(location_name: 'foo') + expect(subject.location_name).to eq('foo') end it 'defaults traits to empty hash' do diff --git a/gems/smithy-xml/lib/smithy-xml/builder.rb b/gems/smithy-xml/lib/smithy-xml/builder.rb index bbdbd71d9..8a487cbb6 100644 --- a/gems/smithy-xml/lib/smithy-xml/builder.rb +++ b/gems/smithy-xml/lib/smithy-xml/builder.rb @@ -14,10 +14,10 @@ def initialize(options = {}) end def build(shape, data, target = nil) - ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, member_name: shape.name) + ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, location_name: shape.name) target ||= [] @builder = DocBuilder.new(target: target, indent: @indent, pad: @pad) - structure(location_name(ref, ref.member_name), ref, data) + structure(location_name(ref, ref.location_name), ref, data) target.join end @@ -88,7 +88,7 @@ def structure(name, ref, values) next if values[member_name].nil? next if xml_attribute?(member_ref) - shape(location_name(member_ref, member_ref.member_name), member_ref, values[member_name]) + shape(location_name(member_ref, member_ref.location_name), member_ref, values[member_name]) end end end @@ -96,7 +96,7 @@ def structure(name, ref, values) def structure_attrs(ref, values) ref.shape.members.each_with_object({}) do |(member_name, member_ref), attrs| if xml_attribute?(member_ref) && values.key?(member_name) - attrs[location_name(member_ref, member_ref.member_name)] = values[member_name] + attrs[location_name(member_ref, member_ref.location_name)] = values[member_name] end end end @@ -118,12 +118,12 @@ def union(name, ref, values) # rubocop:disable Metrics/AbcSize node(name, ref, structure_attrs(ref, values)) do if values.is_a?(Schema::Union) _name, member_ref = ref.shape.member_by_type(values.class) - shape(location_name(member_ref, member_ref.member_name), member_ref, values.value) + shape(location_name(member_ref, member_ref.location_name), member_ref, values.value) else key, value = values.first if ref.shape.member?(key) member_ref = ref.shape.member(key) - shape(location_name(member_ref, member_ref.member_name), member_ref, value) + shape(location_name(member_ref, member_ref.location_name), member_ref, value) end end end diff --git a/gems/smithy-xml/lib/smithy-xml/parser.rb b/gems/smithy-xml/lib/smithy-xml/parser.rb index be0a1e69f..c0cdfbf1d 100644 --- a/gems/smithy-xml/lib/smithy-xml/parser.rb +++ b/gems/smithy-xml/lib/smithy-xml/parser.rb @@ -27,7 +27,7 @@ def initialize(options = {}) # @param [Object, nil] target (nil) # @return [Object] def parse(shape, bytes, target = nil, &) - ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, member_name: shape.name) + ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, location_name: shape.name) bytes = '' if bytes.nil? || bytes.empty? stack = Stack.new(ref, target, &) @engine.new(stack).parse(bytes.to_s) diff --git a/gems/smithy-xml/lib/smithy-xml/parser/frame.rb b/gems/smithy-xml/lib/smithy-xml/parser/frame.rb index 57074ba96..161464e49 100644 --- a/gems/smithy-xml/lib/smithy-xml/parser/frame.rb +++ b/gems/smithy-xml/lib/smithy-xml/parser/frame.rb @@ -268,7 +268,7 @@ def consume_child_frame(child) # rubocop:disable Metrics/AbcSize private def xml_name(ref) - ref.traits['smithy.api#xmlName'] || ref.member_name + ref.traits['smithy.api#xmlName'] || ref.location_name end end diff --git a/gems/smithy-xml/spec/smithy-xml/builder_spec.rb b/gems/smithy-xml/spec/smithy-xml/builder_spec.rb index 272ee25d6..5938bc313 100644 --- a/gems/smithy-xml/spec/smithy-xml/builder_spec.rb +++ b/gems/smithy-xml/spec/smithy-xml/builder_spec.rb @@ -16,7 +16,7 @@ def rexml(xml) end it 'returns an empty frame when given a unit shape' do - ref = Schema::Shapes::ShapeRef.new(shape: Schema::Shapes::Prelude::Unit, member_name: 'unit') + ref = Schema::Shapes::ShapeRef.new(shape: Schema::Shapes::Prelude::Unit, location_name: 'unit') expect(subject.build(ref, '')).to eq('') end diff --git a/gems/smithy/lib/smithy/model/shape.rb b/gems/smithy/lib/smithy/model/shape.rb index be163e4cd..74db717b1 100644 --- a/gems/smithy/lib/smithy/model/shape.rb +++ b/gems/smithy/lib/smithy/model/shape.rb @@ -39,7 +39,7 @@ def self.name(id) # Optional member name # @param [String] id Shape ID # @return [String, nil] Member name - def self.member_name(id) + def self.location_name(id) return nil unless id.include?('$') id.split('$').last diff --git a/gems/smithy/lib/smithy/views/client/schema.rb b/gems/smithy/lib/smithy/views/client/schema.rb index 22efcbbe4..ed0710f2c 100644 --- a/gems/smithy/lib/smithy/views/client/schema.rb +++ b/gems/smithy/lib/smithy/views/client/schema.rb @@ -330,7 +330,7 @@ def initialize(service, member_name, shape_ref) def initializer options_str = "shape: #{@shape}" - options_str += ", member_name: '#{@member_name}'" if @member_name + options_str += ", location_name: '#{@member_name}'" if @member_name options_str += ", traits: #{@traits}" unless @traits.empty? "Smithy::Schema::Shapes::ShapeRef.new(#{options_str})" end diff --git a/gems/smithy/spec/smithy/model/shape_spec.rb b/gems/smithy/spec/smithy/model/shape_spec.rb index 8f10e864d..8379a4657 100644 --- a/gems/smithy/spec/smithy/model/shape_spec.rb +++ b/gems/smithy/spec/smithy/model/shape_spec.rb @@ -43,13 +43,13 @@ module Model end end - describe '.member_name' do + describe '.location_name' do it 'returns the member name' do - expect(Shape.member_name(absolute_id)).to eq(member_name) + expect(Shape.location_name(absolute_id)).to eq(member_name) end it 'returns nil when there is no member name' do - expect(Shape.member_name(namespaced_id)).to be_nil + expect(Shape.location_name(namespaced_id)).to be_nil end end end diff --git a/projections/shapes/lib/shapes/schema.rb b/projections/shapes/lib/shapes/schema.rb index fb511885d..db700ce1a 100644 --- a/projections/shapes/lib/shapes/schema.rb +++ b/projections/shapes/lib/shapes/schema.rb @@ -28,56 +28,56 @@ module Schema Timestamp = Smithy::Schema::Shapes::TimestampShape.new(id: 'smithy.ruby.tests#Timestamp', name: 'Timestamp', traits: {"smithy.ruby.tests#shape" => {}}) Union = Smithy::Schema::Shapes::UnionShape.new(id: 'smithy.ruby.tests#Union', name: 'Union', traits: {"smithy.ruby.tests#shape" => {}}) - Enum.add_member(:foo, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::Unit, member_name: 'FOO', traits: {"smithy.api#enumValue" => "bar"})) - IntEnum.add_member(:baz, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::Unit, member_name: 'BAZ', traits: {"smithy.api#enumValue" => 1})) + Enum.add_member(:foo, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::Unit, location_name: 'FOO', traits: {"smithy.api#enumValue" => "bar"})) + IntEnum.add_member(:baz, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::Unit, location_name: 'BAZ', traits: {"smithy.api#enumValue" => 1})) List.member = Smithy::Schema::Shapes::ShapeRef.new(shape: String, traits: {"smithy.ruby.tests#shape" => {}}) Map.key = Smithy::Schema::Shapes::ShapeRef.new(shape: String, traits: {"smithy.ruby.tests#shape" => {}}) Map.value = Smithy::Schema::Shapes::ShapeRef.new(shape: String, traits: {"smithy.ruby.tests#shape" => {}}) - OperationInput.add_member(:blob, Smithy::Schema::Shapes::ShapeRef.new(shape: Blob, member_name: 'blob')) - OperationInput.add_member(:boolean, Smithy::Schema::Shapes::ShapeRef.new(shape: Boolean, member_name: 'boolean')) - OperationInput.add_member(:string, Smithy::Schema::Shapes::ShapeRef.new(shape: String, member_name: 'string')) - OperationInput.add_member(:byte, Smithy::Schema::Shapes::ShapeRef.new(shape: Byte, member_name: 'byte')) - OperationInput.add_member(:short, Smithy::Schema::Shapes::ShapeRef.new(shape: Short, member_name: 'short')) - OperationInput.add_member(:integer, Smithy::Schema::Shapes::ShapeRef.new(shape: Integer, member_name: 'integer')) - OperationInput.add_member(:long, Smithy::Schema::Shapes::ShapeRef.new(shape: Long, member_name: 'long')) - OperationInput.add_member(:float, Smithy::Schema::Shapes::ShapeRef.new(shape: Float, member_name: 'float')) - OperationInput.add_member(:double, Smithy::Schema::Shapes::ShapeRef.new(shape: Double, member_name: 'double')) - OperationInput.add_member(:big_integer, Smithy::Schema::Shapes::ShapeRef.new(shape: BigInteger, member_name: 'bigInteger')) - OperationInput.add_member(:big_decimal, Smithy::Schema::Shapes::ShapeRef.new(shape: BigDecimal, member_name: 'bigDecimal')) - OperationInput.add_member(:timestamp, Smithy::Schema::Shapes::ShapeRef.new(shape: Timestamp, member_name: 'timestamp')) - OperationInput.add_member(:document, Smithy::Schema::Shapes::ShapeRef.new(shape: Document, member_name: 'document')) - OperationInput.add_member(:enum, Smithy::Schema::Shapes::ShapeRef.new(shape: Enum, member_name: 'enum')) - OperationInput.add_member(:int_enum, Smithy::Schema::Shapes::ShapeRef.new(shape: IntEnum, member_name: 'intEnum')) - OperationInput.add_member(:list, Smithy::Schema::Shapes::ShapeRef.new(shape: List, member_name: 'list')) - OperationInput.add_member(:map, Smithy::Schema::Shapes::ShapeRef.new(shape: Map, member_name: 'map')) - OperationInput.add_member(:structure, Smithy::Schema::Shapes::ShapeRef.new(shape: Structure, member_name: 'structure')) - OperationInput.add_member(:union, Smithy::Schema::Shapes::ShapeRef.new(shape: Union, member_name: 'union')) + OperationInput.add_member(:blob, Smithy::Schema::Shapes::ShapeRef.new(shape: Blob, location_name: 'blob')) + OperationInput.add_member(:boolean, Smithy::Schema::Shapes::ShapeRef.new(shape: Boolean, location_name: 'boolean')) + OperationInput.add_member(:string, Smithy::Schema::Shapes::ShapeRef.new(shape: String, location_name: 'string')) + OperationInput.add_member(:byte, Smithy::Schema::Shapes::ShapeRef.new(shape: Byte, location_name: 'byte')) + OperationInput.add_member(:short, Smithy::Schema::Shapes::ShapeRef.new(shape: Short, location_name: 'short')) + OperationInput.add_member(:integer, Smithy::Schema::Shapes::ShapeRef.new(shape: Integer, location_name: 'integer')) + OperationInput.add_member(:long, Smithy::Schema::Shapes::ShapeRef.new(shape: Long, location_name: 'long')) + OperationInput.add_member(:float, Smithy::Schema::Shapes::ShapeRef.new(shape: Float, location_name: 'float')) + OperationInput.add_member(:double, Smithy::Schema::Shapes::ShapeRef.new(shape: Double, location_name: 'double')) + OperationInput.add_member(:big_integer, Smithy::Schema::Shapes::ShapeRef.new(shape: BigInteger, location_name: 'bigInteger')) + OperationInput.add_member(:big_decimal, Smithy::Schema::Shapes::ShapeRef.new(shape: BigDecimal, location_name: 'bigDecimal')) + OperationInput.add_member(:timestamp, Smithy::Schema::Shapes::ShapeRef.new(shape: Timestamp, location_name: 'timestamp')) + OperationInput.add_member(:document, Smithy::Schema::Shapes::ShapeRef.new(shape: Document, location_name: 'document')) + OperationInput.add_member(:enum, Smithy::Schema::Shapes::ShapeRef.new(shape: Enum, location_name: 'enum')) + OperationInput.add_member(:int_enum, Smithy::Schema::Shapes::ShapeRef.new(shape: IntEnum, location_name: 'intEnum')) + OperationInput.add_member(:list, Smithy::Schema::Shapes::ShapeRef.new(shape: List, location_name: 'list')) + OperationInput.add_member(:map, Smithy::Schema::Shapes::ShapeRef.new(shape: Map, location_name: 'map')) + OperationInput.add_member(:structure, Smithy::Schema::Shapes::ShapeRef.new(shape: Structure, location_name: 'structure')) + OperationInput.add_member(:union, Smithy::Schema::Shapes::ShapeRef.new(shape: Union, location_name: 'union')) OperationInput.type = Types::OperationInput - OperationOutput.add_member(:blob, Smithy::Schema::Shapes::ShapeRef.new(shape: Blob, member_name: 'blob')) - OperationOutput.add_member(:boolean, Smithy::Schema::Shapes::ShapeRef.new(shape: Boolean, member_name: 'boolean')) - OperationOutput.add_member(:string, Smithy::Schema::Shapes::ShapeRef.new(shape: String, member_name: 'string')) - OperationOutput.add_member(:byte, Smithy::Schema::Shapes::ShapeRef.new(shape: Byte, member_name: 'byte')) - OperationOutput.add_member(:short, Smithy::Schema::Shapes::ShapeRef.new(shape: Short, member_name: 'short')) - OperationOutput.add_member(:integer, Smithy::Schema::Shapes::ShapeRef.new(shape: Integer, member_name: 'integer')) - OperationOutput.add_member(:long, Smithy::Schema::Shapes::ShapeRef.new(shape: Long, member_name: 'long')) - OperationOutput.add_member(:float, Smithy::Schema::Shapes::ShapeRef.new(shape: Float, member_name: 'float')) - OperationOutput.add_member(:double, Smithy::Schema::Shapes::ShapeRef.new(shape: Double, member_name: 'double')) - OperationOutput.add_member(:big_integer, Smithy::Schema::Shapes::ShapeRef.new(shape: BigInteger, member_name: 'bigInteger')) - OperationOutput.add_member(:big_decimal, Smithy::Schema::Shapes::ShapeRef.new(shape: BigDecimal, member_name: 'bigDecimal')) - OperationOutput.add_member(:timestamp, Smithy::Schema::Shapes::ShapeRef.new(shape: Timestamp, member_name: 'timestamp')) - OperationOutput.add_member(:document, Smithy::Schema::Shapes::ShapeRef.new(shape: Document, member_name: 'document')) - OperationOutput.add_member(:enum, Smithy::Schema::Shapes::ShapeRef.new(shape: Enum, member_name: 'enum')) - OperationOutput.add_member(:int_enum, Smithy::Schema::Shapes::ShapeRef.new(shape: IntEnum, member_name: 'intEnum')) - OperationOutput.add_member(:list, Smithy::Schema::Shapes::ShapeRef.new(shape: List, member_name: 'list')) - OperationOutput.add_member(:map, Smithy::Schema::Shapes::ShapeRef.new(shape: Map, member_name: 'map')) - OperationOutput.add_member(:structure, Smithy::Schema::Shapes::ShapeRef.new(shape: Structure, member_name: 'structure')) - OperationOutput.add_member(:union, Smithy::Schema::Shapes::ShapeRef.new(shape: Union, member_name: 'union')) + OperationOutput.add_member(:blob, Smithy::Schema::Shapes::ShapeRef.new(shape: Blob, location_name: 'blob')) + OperationOutput.add_member(:boolean, Smithy::Schema::Shapes::ShapeRef.new(shape: Boolean, location_name: 'boolean')) + OperationOutput.add_member(:string, Smithy::Schema::Shapes::ShapeRef.new(shape: String, location_name: 'string')) + OperationOutput.add_member(:byte, Smithy::Schema::Shapes::ShapeRef.new(shape: Byte, location_name: 'byte')) + OperationOutput.add_member(:short, Smithy::Schema::Shapes::ShapeRef.new(shape: Short, location_name: 'short')) + OperationOutput.add_member(:integer, Smithy::Schema::Shapes::ShapeRef.new(shape: Integer, location_name: 'integer')) + OperationOutput.add_member(:long, Smithy::Schema::Shapes::ShapeRef.new(shape: Long, location_name: 'long')) + OperationOutput.add_member(:float, Smithy::Schema::Shapes::ShapeRef.new(shape: Float, location_name: 'float')) + OperationOutput.add_member(:double, Smithy::Schema::Shapes::ShapeRef.new(shape: Double, location_name: 'double')) + OperationOutput.add_member(:big_integer, Smithy::Schema::Shapes::ShapeRef.new(shape: BigInteger, location_name: 'bigInteger')) + OperationOutput.add_member(:big_decimal, Smithy::Schema::Shapes::ShapeRef.new(shape: BigDecimal, location_name: 'bigDecimal')) + OperationOutput.add_member(:timestamp, Smithy::Schema::Shapes::ShapeRef.new(shape: Timestamp, location_name: 'timestamp')) + OperationOutput.add_member(:document, Smithy::Schema::Shapes::ShapeRef.new(shape: Document, location_name: 'document')) + OperationOutput.add_member(:enum, Smithy::Schema::Shapes::ShapeRef.new(shape: Enum, location_name: 'enum')) + OperationOutput.add_member(:int_enum, Smithy::Schema::Shapes::ShapeRef.new(shape: IntEnum, location_name: 'intEnum')) + OperationOutput.add_member(:list, Smithy::Schema::Shapes::ShapeRef.new(shape: List, location_name: 'list')) + OperationOutput.add_member(:map, Smithy::Schema::Shapes::ShapeRef.new(shape: Map, location_name: 'map')) + OperationOutput.add_member(:structure, Smithy::Schema::Shapes::ShapeRef.new(shape: Structure, location_name: 'structure')) + OperationOutput.add_member(:union, Smithy::Schema::Shapes::ShapeRef.new(shape: Union, location_name: 'union')) OperationOutput.type = Types::OperationOutput - Structure.add_member(:member, Smithy::Schema::Shapes::ShapeRef.new(shape: String, member_name: 'member', traits: {"smithy.ruby.tests#shape" => {}})) + Structure.add_member(:member, Smithy::Schema::Shapes::ShapeRef.new(shape: String, location_name: 'member', traits: {"smithy.ruby.tests#shape" => {}})) Structure.type = Types::Structure - Union.add_member(:string, Types::Union::String, Smithy::Schema::Shapes::ShapeRef.new(shape: String, member_name: 'string', traits: {"smithy.ruby.tests#shape" => {}})) - Union.add_member(:structure, Types::Union::Structure, Smithy::Schema::Shapes::ShapeRef.new(shape: Structure, member_name: 'structure', traits: {"smithy.ruby.tests#shape" => {}})) - Union.add_member(:unit, Types::Union::Unit, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::Unit, member_name: 'unit', traits: {"smithy.ruby.tests#shape" => {}})) + Union.add_member(:string, Types::Union::String, Smithy::Schema::Shapes::ShapeRef.new(shape: String, location_name: 'string', traits: {"smithy.ruby.tests#shape" => {}})) + Union.add_member(:structure, Types::Union::Structure, Smithy::Schema::Shapes::ShapeRef.new(shape: Structure, location_name: 'structure', traits: {"smithy.ruby.tests#shape" => {}})) + Union.add_member(:unit, Types::Union::Unit, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::Unit, location_name: 'unit', traits: {"smithy.ruby.tests#shape" => {}})) Union.add_member(:unknown, Types::Union::Unknown, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::Unit)) Union.type = Types::Union @@ -89,8 +89,8 @@ module Schema service.add_operation(:operation, Smithy::Schema::Shapes::OperationShape.new do |operation| operation.id = "smithy.ruby.tests#Operation" operation.name = "Operation" - operation.input = Smithy::Schema::Shapes::ShapeRef.new(shape: OperationInput) - operation.output = Smithy::Schema::Shapes::ShapeRef.new(shape: OperationOutput) + operation.input = Smithy::Schema::Shapes::ShapeRef.new(shape: OperationInput, location_name: 'OperationInput') + operation.output = Smithy::Schema::Shapes::ShapeRef.new(shape: OperationOutput, location_name: 'OperationOutput') operation.traits = {"smithy.ruby.tests#shape" => {}} end) diff --git a/projections/weather/lib/weather/schema.rb b/projections/weather/lib/weather/schema.rb index 9a372e40e..42570aacd 100644 --- a/projections/weather/lib/weather/schema.rb +++ b/projections/weather/lib/weather/schema.rb @@ -19,31 +19,31 @@ module Schema ListCitiesOutput = Smithy::Schema::Shapes::StructureShape.new(id: 'example.weather#ListCitiesOutput', name: 'ListCitiesOutput') NoSuchResource = Smithy::Schema::Shapes::StructureShape.new(id: 'example.weather#NoSuchResource', name: 'NoSuchResource', traits: {"smithy.api#error" => "client"}) - CityCoordinates.add_member(:latitude, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::Float, member_name: 'latitude', traits: {"smithy.api#required" => {}})) - CityCoordinates.add_member(:longitude, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::Float, member_name: 'longitude', traits: {"smithy.api#required" => {}})) + CityCoordinates.add_member(:latitude, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::Float, location_name: 'latitude', traits: {"smithy.api#required" => {}})) + CityCoordinates.add_member(:longitude, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::Float, location_name: 'longitude', traits: {"smithy.api#required" => {}})) CityCoordinates.type = Types::CityCoordinates CitySummaries.member = Smithy::Schema::Shapes::ShapeRef.new(shape: CitySummary) - CitySummary.add_member(:city_id, Smithy::Schema::Shapes::ShapeRef.new(shape: CityId, member_name: 'cityId', traits: {"smithy.api#required" => {}})) - CitySummary.add_member(:name, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::String, member_name: 'name', traits: {"smithy.api#required" => {}})) + CitySummary.add_member(:city_id, Smithy::Schema::Shapes::ShapeRef.new(shape: CityId, location_name: 'cityId', traits: {"smithy.api#required" => {}})) + CitySummary.add_member(:name, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::String, location_name: 'name', traits: {"smithy.api#required" => {}})) CitySummary.type = Types::CitySummary - GetCityInput.add_member(:city_id, Smithy::Schema::Shapes::ShapeRef.new(shape: CityId, member_name: 'cityId', traits: {"smithy.api#required" => {}})) + GetCityInput.add_member(:city_id, Smithy::Schema::Shapes::ShapeRef.new(shape: CityId, location_name: 'cityId', traits: {"smithy.api#required" => {}})) GetCityInput.type = Types::GetCityInput - GetCityOutput.add_member(:name, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::String, member_name: 'name', traits: {"smithy.api#notProperty" => {}, "smithy.api#required" => {}})) - GetCityOutput.add_member(:coordinates, Smithy::Schema::Shapes::ShapeRef.new(shape: CityCoordinates, member_name: 'coordinates', traits: {"smithy.api#required" => {}})) + GetCityOutput.add_member(:name, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::String, location_name: 'name', traits: {"smithy.api#notProperty" => {}, "smithy.api#required" => {}})) + GetCityOutput.add_member(:coordinates, Smithy::Schema::Shapes::ShapeRef.new(shape: CityCoordinates, location_name: 'coordinates', traits: {"smithy.api#required" => {}})) GetCityOutput.type = Types::GetCityOutput - GetCurrentTimeOutput.add_member(:time, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::Timestamp, member_name: 'time', traits: {"smithy.api#required" => {}})) + GetCurrentTimeOutput.add_member(:time, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::Timestamp, location_name: 'time', traits: {"smithy.api#required" => {}})) GetCurrentTimeOutput.type = Types::GetCurrentTimeOutput - GetForecastInput.add_member(:city_id, Smithy::Schema::Shapes::ShapeRef.new(shape: CityId, member_name: 'cityId', traits: {"smithy.api#required" => {}})) + GetForecastInput.add_member(:city_id, Smithy::Schema::Shapes::ShapeRef.new(shape: CityId, location_name: 'cityId', traits: {"smithy.api#required" => {}})) GetForecastInput.type = Types::GetForecastInput - GetForecastOutput.add_member(:chance_of_rain, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::Float, member_name: 'chanceOfRain')) + GetForecastOutput.add_member(:chance_of_rain, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::Float, location_name: 'chanceOfRain')) GetForecastOutput.type = Types::GetForecastOutput - ListCitiesInput.add_member(:next_token, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::String, member_name: 'nextToken')) - ListCitiesInput.add_member(:page_size, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::Integer, member_name: 'pageSize')) + ListCitiesInput.add_member(:next_token, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::String, location_name: 'nextToken')) + ListCitiesInput.add_member(:page_size, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::Integer, location_name: 'pageSize')) ListCitiesInput.type = Types::ListCitiesInput - ListCitiesOutput.add_member(:next_token, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::String, member_name: 'nextToken')) - ListCitiesOutput.add_member(:items, Smithy::Schema::Shapes::ShapeRef.new(shape: CitySummaries, member_name: 'items', traits: {"smithy.api#required" => {}})) + ListCitiesOutput.add_member(:next_token, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::String, location_name: 'nextToken')) + ListCitiesOutput.add_member(:items, Smithy::Schema::Shapes::ShapeRef.new(shape: CitySummaries, location_name: 'items', traits: {"smithy.api#required" => {}})) ListCitiesOutput.type = Types::ListCitiesOutput - NoSuchResource.add_member(:resource_type, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::String, member_name: 'resourceType', traits: {"smithy.api#required" => {}})) + NoSuchResource.add_member(:resource_type, Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::String, location_name: 'resourceType', traits: {"smithy.api#required" => {}})) NoSuchResource.type = Types::NoSuchResource Weather = Smithy::Schema::Shapes::ServiceShape.new do |service| @@ -54,30 +54,30 @@ module Schema service.add_operation(:get_city, Smithy::Schema::Shapes::OperationShape.new do |operation| operation.id = "example.weather#GetCity" operation.name = "GetCity" - operation.input = Smithy::Schema::Shapes::ShapeRef.new(shape: GetCityInput) - operation.output = Smithy::Schema::Shapes::ShapeRef.new(shape: GetCityOutput) - operation.errors << Smithy::Schema::Shapes::ShapeRef.new(shape: NoSuchResource) + operation.input = Smithy::Schema::Shapes::ShapeRef.new(shape: GetCityInput, location_name: 'GetCityInput') + operation.output = Smithy::Schema::Shapes::ShapeRef.new(shape: GetCityOutput, location_name: 'GetCityOutput') + operation.errors << Smithy::Schema::Shapes::ShapeRef.new(shape: NoSuchResource, location_name: 'NoSuchResource') operation.traits = {"smithy.api#readonly" => {}} end) service.add_operation(:get_current_time, Smithy::Schema::Shapes::OperationShape.new do |operation| operation.id = "example.weather#GetCurrentTime" operation.name = "GetCurrentTime" - operation.input = Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::Unit) - operation.output = Smithy::Schema::Shapes::ShapeRef.new(shape: GetCurrentTimeOutput) + operation.input = Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::Unit, location_name: 'Unit') + operation.output = Smithy::Schema::Shapes::ShapeRef.new(shape: GetCurrentTimeOutput, location_name: 'GetCurrentTimeOutput') operation.traits = {"smithy.api#readonly" => {}} end) service.add_operation(:get_forecast, Smithy::Schema::Shapes::OperationShape.new do |operation| operation.id = "example.weather#GetForecast" operation.name = "GetForecast" - operation.input = Smithy::Schema::Shapes::ShapeRef.new(shape: GetForecastInput) - operation.output = Smithy::Schema::Shapes::ShapeRef.new(shape: GetForecastOutput) + operation.input = Smithy::Schema::Shapes::ShapeRef.new(shape: GetForecastInput, location_name: 'GetForecastInput') + operation.output = Smithy::Schema::Shapes::ShapeRef.new(shape: GetForecastOutput, location_name: 'GetForecastOutput') operation.traits = {"smithy.api#readonly" => {}} end) service.add_operation(:list_cities, Smithy::Schema::Shapes::OperationShape.new do |operation| operation.id = "example.weather#ListCities" operation.name = "ListCities" - operation.input = Smithy::Schema::Shapes::ShapeRef.new(shape: ListCitiesInput) - operation.output = Smithy::Schema::Shapes::ShapeRef.new(shape: ListCitiesOutput) + operation.input = Smithy::Schema::Shapes::ShapeRef.new(shape: ListCitiesInput, location_name: 'ListCitiesInput') + operation.output = Smithy::Schema::Shapes::ShapeRef.new(shape: ListCitiesOutput, location_name: 'ListCitiesOutput') operation.traits = {"smithy.api#readonly" => {}} operation[:paginator] = Paginators::ListCities.new end) From 132387f5e4b2f3f78b42044f9da8f5bc3af599c8 Mon Sep 17 00:00:00 2001 From: Matt Muller Date: Mon, 11 Aug 2025 13:18:58 -0400 Subject: [PATCH 03/14] Fix building --- gems/smithy-schema/lib/smithy-schema/shapes.rb | 2 +- gems/smithy-schema/lib/smithy-schema/structure.rb | 1 + gems/smithy-schema/spec/smithy-schema/shapes_spec.rb | 2 +- gems/smithy/lib/smithy/views/client/schema.rb | 10 ++++------ 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/gems/smithy-schema/lib/smithy-schema/shapes.rb b/gems/smithy-schema/lib/smithy-schema/shapes.rb index 401003842..f7efd7936 100644 --- a/gems/smithy-schema/lib/smithy-schema/shapes.rb +++ b/gems/smithy-schema/lib/smithy-schema/shapes.rb @@ -38,7 +38,7 @@ def []=(key, value) class ShapeRef def initialize(options = {}) @shape = options[:shape] - @member_name = options[:location_name] + @location_name = options[:location_name] @traits = options[:traits] || {} @metadata = {} end diff --git a/gems/smithy-schema/lib/smithy-schema/structure.rb b/gems/smithy-schema/lib/smithy-schema/structure.rb index 755e15eeb..3990736c4 100644 --- a/gems/smithy-schema/lib/smithy-schema/structure.rb +++ b/gems/smithy-schema/lib/smithy-schema/structure.rb @@ -26,6 +26,7 @@ def empty? values.compact == [] end + # @param [Symbol] member_name # @return [Boolean] def key?(member_name) !self[member_name].nil? diff --git a/gems/smithy-schema/spec/smithy-schema/shapes_spec.rb b/gems/smithy-schema/spec/smithy-schema/shapes_spec.rb index 846b92e3e..9ac332fa2 100644 --- a/gems/smithy-schema/spec/smithy-schema/shapes_spec.rb +++ b/gems/smithy-schema/spec/smithy-schema/shapes_spec.rb @@ -57,7 +57,7 @@ module Shapes expect(subject.location_name).to be_nil end - it 'stores the member name as a location name' do + it 'stores a location name' do subject = ShapeRef.new(location_name: 'foo') expect(subject.location_name).to eq('foo') end diff --git a/gems/smithy/lib/smithy/views/client/schema.rb b/gems/smithy/lib/smithy/views/client/schema.rb index ed0710f2c..3c699aa7e 100644 --- a/gems/smithy/lib/smithy/views/client/schema.rb +++ b/gems/smithy/lib/smithy/views/client/schema.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'set' - module Smithy module Views module Client @@ -318,10 +316,10 @@ class ShapeRef 'smithy.api#Unit' => 'Prelude::Unit' }.freeze - def initialize(service, member_name, shape_ref) + def initialize(service, location_name, shape_ref) @service = service - @name = member_name.underscore if member_name - @member_name = member_name + @name = location_name.underscore if location_name + @location_name = location_name @shape = shape(shape_ref['target']) @traits = shape_ref.fetch('traits', {}) end @@ -330,7 +328,7 @@ def initialize(service, member_name, shape_ref) def initializer options_str = "shape: #{@shape}" - options_str += ", location_name: '#{@member_name}'" if @member_name + options_str += ", location_name: '#{@location_name}'" if @location_name options_str += ", traits: #{@traits}" unless @traits.empty? "Smithy::Schema::Shapes::ShapeRef.new(#{options_str})" end From ab52a0d954eeb649532c0424da955488ed177e0f Mon Sep 17 00:00:00 2001 From: Matt Muller Date: Mon, 11 Aug 2025 13:23:40 -0400 Subject: [PATCH 04/14] Fix rbs --- .../smithy-schema/lib/smithy-schema/shapes.rb | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/gems/smithy-schema/lib/smithy-schema/shapes.rb b/gems/smithy-schema/lib/smithy-schema/shapes.rb index f7efd7936..3faabed6b 100644 --- a/gems/smithy-schema/lib/smithy-schema/shapes.rb +++ b/gems/smithy-schema/lib/smithy-schema/shapes.rb @@ -326,49 +326,57 @@ def member_by_type(type) # Prelude shape definitions. module Prelude - BigDecimal = BigDecimalShape.new(id: 'smithy.api#BigDecimal') - BigInteger = IntegerShape.new(id: 'smithy.api#BigInteger') - Blob = BlobShape.new(id: 'smithy.api#Blob') - Boolean = BooleanShape.new(id: 'smithy.api#Boolean') - Byte = IntegerShape.new(id: 'smithy.api#Byte') - Document = DocumentShape.new(id: 'smithy.api#Document') - Double = FloatShape.new(id: 'smithy.api#Double') - Float = FloatShape.new(id: 'smithy.api#Float') - Integer = IntegerShape.new(id: 'smithy.api#Integer') - Long = IntegerShape.new(id: 'smithy.api#Long') + BigDecimal = BigDecimalShape.new(id: 'smithy.api#BigDecimal', name: 'BigDecimal') + BigInteger = IntegerShape.new(id: 'smithy.api#BigInteger', name: 'BigInteger') + Blob = BlobShape.new(id: 'smithy.api#Blob', name: 'Blob') + Boolean = BooleanShape.new(id: 'smithy.api#Boolean', name: 'Boolean') + Byte = IntegerShape.new(id: 'smithy.api#Byte', name: 'Byte') + Document = DocumentShape.new(id: 'smithy.api#Document', name: 'Document') + Double = FloatShape.new(id: 'smithy.api#Double', name: 'Double') + Float = FloatShape.new(id: 'smithy.api#Float', name: 'Float') + Integer = IntegerShape.new(id: 'smithy.api#Integer', name: 'Integer') + Long = IntegerShape.new(id: 'smithy.api#Long', name: 'Long') PrimitiveBoolean = BooleanShape.new( id: 'smithy.api#PrimitiveBoolean', + name: 'PrimitiveBoolean', traits: { 'smithy.api#default' => false } ) PrimitiveByte = IntegerShape.new( id: 'smithy.api#PrimitiveByte', + name: 'PrimitiveByte', traits: { 'smithy.api#default' => 0 } ) PrimitiveDouble = FloatShape.new( id: 'smithy.api#PrimitiveDouble', + name: 'PrimitiveDouble', traits: { 'smithy.api#default' => 0 } ) PrimitiveFloat = FloatShape.new( id: 'smithy.api#PrimitiveFloat', + name: 'PrimitiveFloat', traits: { 'smithy.api#default' => 0 } ) PrimitiveInteger = IntegerShape.new( id: 'smithy.api#PrimitiveInteger', + name: 'PrimitiveInteger', traits: { 'smithy.api#default' => 0 } ) PrimitiveShort = IntegerShape.new( id: 'smithy.api#PrimitiveShort', + name: 'PrimitiveShort', traits: { 'smithy.api#default' => 0 } ) PrimitiveLong = IntegerShape.new( id: 'smithy.api#PrimitiveLong', + name: 'PrimitiveLong', traits: { 'smithy.api#default' => 0 } ) - Short = IntegerShape.new(id: 'smithy.api#Short') - String = StringShape.new(id: 'smithy.api#String') - Timestamp = TimestampShape.new(id: 'smithy.api#Timestamp') + Short = IntegerShape.new(id: 'smithy.api#Short', name: 'Short') + String = StringShape.new(id: 'smithy.api#String', name: 'String') + Timestamp = TimestampShape.new(id: 'smithy.api#Timestamp', name: 'Timestamp',) Unit = StructureShape.new( id: 'smithy.api#Unit', + name: 'Unit', traits: { 'smithy.api#unitType' => {} } ) Unit.type = EmptyStructure From 6856b31d6b086d6cc6f7b88d112f1d2dfd3c69bb Mon Sep 17 00:00:00 2001 From: Matt Muller Date: Mon, 11 Aug 2025 13:26:04 -0400 Subject: [PATCH 05/14] Fix rubocop --- gems/smithy-schema/lib/smithy-schema/shapes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gems/smithy-schema/lib/smithy-schema/shapes.rb b/gems/smithy-schema/lib/smithy-schema/shapes.rb index 3faabed6b..caa8e94ba 100644 --- a/gems/smithy-schema/lib/smithy-schema/shapes.rb +++ b/gems/smithy-schema/lib/smithy-schema/shapes.rb @@ -373,7 +373,7 @@ module Prelude ) Short = IntegerShape.new(id: 'smithy.api#Short', name: 'Short') String = StringShape.new(id: 'smithy.api#String', name: 'String') - Timestamp = TimestampShape.new(id: 'smithy.api#Timestamp', name: 'Timestamp',) + Timestamp = TimestampShape.new(id: 'smithy.api#Timestamp', name: 'Timestamp') Unit = StructureShape.new( id: 'smithy.api#Unit', name: 'Unit', From c8f68303627fc48c3905f2f27f1fbfa7512a73dd Mon Sep 17 00:00:00 2001 From: Matt Muller Date: Tue, 12 Aug 2025 12:15:18 -0400 Subject: [PATCH 06/14] Fix incorrect renaming --- gems/smithy-xml/spec/smithy-xml/parser_spec.rb | 2 +- gems/smithy/lib/smithy/model/shape.rb | 2 +- gems/smithy/spec/smithy/model/shape_spec.rb | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gems/smithy-xml/spec/smithy-xml/parser_spec.rb b/gems/smithy-xml/spec/smithy-xml/parser_spec.rb index 2a4a269fb..a2ea76671 100644 --- a/gems/smithy-xml/spec/smithy-xml/parser_spec.rb +++ b/gems/smithy-xml/spec/smithy-xml/parser_spec.rb @@ -95,7 +95,7 @@ module Xml expect(subject.parse(structure_shape, bytes).to_h).to eq(expected) end - it 'parses structures with jsonName' do + it 'parses structures with xmlName' do shapes['smithy.ruby.tests#Structure']['members']['string'] = { 'target' => 'smithy.api#String', 'traits' => { 'smithy.api#xmlName' => 'NewString' } diff --git a/gems/smithy/lib/smithy/model/shape.rb b/gems/smithy/lib/smithy/model/shape.rb index 74db717b1..be163e4cd 100644 --- a/gems/smithy/lib/smithy/model/shape.rb +++ b/gems/smithy/lib/smithy/model/shape.rb @@ -39,7 +39,7 @@ def self.name(id) # Optional member name # @param [String] id Shape ID # @return [String, nil] Member name - def self.location_name(id) + def self.member_name(id) return nil unless id.include?('$') id.split('$').last diff --git a/gems/smithy/spec/smithy/model/shape_spec.rb b/gems/smithy/spec/smithy/model/shape_spec.rb index 8379a4657..8f10e864d 100644 --- a/gems/smithy/spec/smithy/model/shape_spec.rb +++ b/gems/smithy/spec/smithy/model/shape_spec.rb @@ -43,13 +43,13 @@ module Model end end - describe '.location_name' do + describe '.member_name' do it 'returns the member name' do - expect(Shape.location_name(absolute_id)).to eq(member_name) + expect(Shape.member_name(absolute_id)).to eq(member_name) end it 'returns nil when there is no member name' do - expect(Shape.location_name(namespaced_id)).to be_nil + expect(Shape.member_name(namespaced_id)).to be_nil end end end From 55165b60e8757c13fcb6ac674a65edf83fcb1705 Mon Sep 17 00:00:00 2001 From: Matt Muller Date: Tue, 12 Aug 2025 17:33:26 -0400 Subject: [PATCH 07/14] Working tests? --- gems/smithy-cbor/lib/smithy-cbor/builder.rb | 2 +- gems/smithy-cbor/lib/smithy-cbor/parser.rb | 2 +- gems/smithy-json/lib/smithy-json/builder.rb | 2 +- gems/smithy-json/lib/smithy-json/parser.rb | 2 +- gems/smithy-xml/lib/smithy-xml/builder.rb | 12 ++- gems/smithy-xml/lib/smithy-xml/parser.rb | 2 +- .../spec/smithy-xml/builder_spec.rb | 78 ++++++++++++++++++- .../smithy-xml/spec/smithy-xml/parser_spec.rb | 11 +++ .../lib/smithy/views/client/protocol_spec.rb | 3 +- gems/smithy/lib/smithy/views/client/schema.rb | 6 +- 10 files changed, 99 insertions(+), 21 deletions(-) diff --git a/gems/smithy-cbor/lib/smithy-cbor/builder.rb b/gems/smithy-cbor/lib/smithy-cbor/builder.rb index bd6d95a40..076e718dd 100644 --- a/gems/smithy-cbor/lib/smithy-cbor/builder.rb +++ b/gems/smithy-cbor/lib/smithy-cbor/builder.rb @@ -13,7 +13,7 @@ def initialize(options = {}) end def build(shape, data) - ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, location_name: shape.name) + ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape) return if ref.shape == Prelude::Unit Cbor.encode(shape(ref, data)) diff --git a/gems/smithy-cbor/lib/smithy-cbor/parser.rb b/gems/smithy-cbor/lib/smithy-cbor/parser.rb index 2f29300e8..18b1fcb96 100644 --- a/gems/smithy-cbor/lib/smithy-cbor/parser.rb +++ b/gems/smithy-cbor/lib/smithy-cbor/parser.rb @@ -15,7 +15,7 @@ def initialize(options = {}) def parse(shape, bytes, target = nil) return {} if bytes.empty? - ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, location_name: shape.name) + ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape) shape(ref, Cbor.decode(bytes), target) end diff --git a/gems/smithy-json/lib/smithy-json/builder.rb b/gems/smithy-json/lib/smithy-json/builder.rb index 5641e7afe..c55cf456d 100644 --- a/gems/smithy-json/lib/smithy-json/builder.rb +++ b/gems/smithy-json/lib/smithy-json/builder.rb @@ -13,7 +13,7 @@ def initialize(options = {}) end def build(shape, data) - ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, location_name: shape.name) + ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape) Smithy::Json.dump(shape(ref, data)) end diff --git a/gems/smithy-json/lib/smithy-json/parser.rb b/gems/smithy-json/lib/smithy-json/parser.rb index 662680d8a..e21c05c6a 100644 --- a/gems/smithy-json/lib/smithy-json/parser.rb +++ b/gems/smithy-json/lib/smithy-json/parser.rb @@ -15,7 +15,7 @@ def initialize(options = {}) def parse(shape, bytes, target = nil) return {} if bytes.empty? - ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, location_name: shape.name) + ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape) shape(ref, Smithy::Json.load(bytes), target) end diff --git a/gems/smithy-xml/lib/smithy-xml/builder.rb b/gems/smithy-xml/lib/smithy-xml/builder.rb index 8a487cbb6..4369136c6 100644 --- a/gems/smithy-xml/lib/smithy-xml/builder.rb +++ b/gems/smithy-xml/lib/smithy-xml/builder.rb @@ -14,10 +14,10 @@ def initialize(options = {}) end def build(shape, data, target = nil) - ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, location_name: shape.name) + ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape) target ||= [] @builder = DocBuilder.new(target: target, indent: @indent, pad: @pad) - structure(location_name(ref, ref.location_name), ref, data) + structure(ref.location_name || ref.shape.traits['smithy.api#xmlName'] || ref.shape.name, ref, data) target.join end @@ -40,8 +40,6 @@ def blob(value) end def list(name, ref, values) - return node(name, ref) if values.empty? - member_ref = ref.shape.member if flat?(ref) values.each do |value| @@ -57,8 +55,6 @@ def list(name, ref, values) end def map(name, ref, values) # rubocop:disable Metrics/AbcSize - return node(name, ref) if values.empty? - key_ref = ref.shape.key value_ref = ref.shape.value if flat?(ref) @@ -159,7 +155,9 @@ def node(name, ref, *args, &) end def shape_attrs(ref) - return {} unless (xmlns = ref.traits['smithy.api#xmlNamespace']) + trait = 'smithy.api#xmlNamespace' + xmlns = ref.traits[trait] || (ref.shape && ref.shape.traits[trait]) + return {} unless xmlns if (prefix = xmlns['prefix']) { "xmlns:#{prefix}" => xmlns['uri'] } diff --git a/gems/smithy-xml/lib/smithy-xml/parser.rb b/gems/smithy-xml/lib/smithy-xml/parser.rb index c0cdfbf1d..9f54726a4 100644 --- a/gems/smithy-xml/lib/smithy-xml/parser.rb +++ b/gems/smithy-xml/lib/smithy-xml/parser.rb @@ -27,7 +27,7 @@ def initialize(options = {}) # @param [Object, nil] target (nil) # @return [Object] def parse(shape, bytes, target = nil, &) - ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape, location_name: shape.name) + ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape) bytes = '' if bytes.nil? || bytes.empty? stack = Stack.new(ref, target, &) @engine.new(stack).parse(bytes.to_s) diff --git a/gems/smithy-xml/spec/smithy-xml/builder_spec.rb b/gems/smithy-xml/spec/smithy-xml/builder_spec.rb index 5938bc313..0bf408d23 100644 --- a/gems/smithy-xml/spec/smithy-xml/builder_spec.rb +++ b/gems/smithy-xml/spec/smithy-xml/builder_spec.rb @@ -11,8 +11,8 @@ module Xml let(:sample_schema) { SchemaHelper.sample_schema(shapes: shapes) } let(:structure_shape) { sample_schema.const_get(:Structure) } - def rexml(xml) - REXML::Document.new(xml).to_s.gsub(/>\s+?<').strip + def inline(xml) + xml.gsub(/>\n\s*<').strip end it 'returns an empty frame when given a unit shape' do @@ -71,16 +71,68 @@ def rexml(xml) 'union' => { 'string' => 'string' } } end + let(:xml) do + <<~XML + + 0.0 + 0 + YmxvYg== + false + 0 + 0.0 + enum + 0.0 + 0 + 0 + + 0 + + 0 + c3RyZWFtaW5nIGJsb2I= + string + + 0.0 + 0 + YmxvYg== + false + 0 + 0.0 + enum + 0.0 + 0 + 0 + + 0 + + 0 + c3RyZWFtaW5nIGJsb2I= + string + + + #{time.utc.iso8601} + + string + + + + + #{time.utc.iso8601} + + string + + + XML + end it 'builds structures as a type' do type = structure_shape.type.new(data.merge(structure: data)) bytes = subject.build(structure_shape, type) - expect(bytes).to eq(rexml(bytes)) + expect(bytes).to eq(inline(xml)) end it 'builds structures as a hash' do bytes = subject.build(structure_shape, data.merge(structure: data)) - expect(bytes).to eq(rexml(bytes)) + expect(bytes).to eq(inline(xml)) end it 'builds structures with xmlName' do @@ -92,6 +144,24 @@ def rexml(xml) bytes = subject.build(structure_shape, data) expect(bytes).to include('string') end + + it 'builds structures with xmlNamespace' do + shapes['smithy.ruby.tests#Structure']['traits'] = { + 'smithy.api#xmlNamespace' => { 'uri' => 'http://example.com/ns' } + } + data = { string: 'string' } + bytes = subject.build(structure_shape, data) + expect(bytes).to include('') + end + + it 'builds structures with xmlAttributes' do + shapes['smithy.ruby.tests#Structure']['members']['string']['traits'] = { + 'smithy.api#xmlAttribute' => {} + } + data = { string: 'string' } + bytes = subject.build(structure_shape, data) + expect(bytes).to include('') + end end context 'unions' do diff --git a/gems/smithy-xml/spec/smithy-xml/parser_spec.rb b/gems/smithy-xml/spec/smithy-xml/parser_spec.rb index a2ea76671..c902aa669 100644 --- a/gems/smithy-xml/spec/smithy-xml/parser_spec.rb +++ b/gems/smithy-xml/spec/smithy-xml/parser_spec.rb @@ -107,6 +107,17 @@ module Xml XML expect(subject.parse(structure_shape, bytes).to_h).to eq(string: 'string') end + + it 'parses structures with xmlAttribute' do + shapes['smithy.ruby.tests#Structure']['members']['string'] = { + 'target' => 'smithy.api#String', + 'traits' => { 'smithy.api#xmlAttribute' => true } + } + bytes = <<~XML + + XML + expect(subject.parse(structure_shape, bytes).to_h).to eq(string: 'string') + end end context 'unions' do diff --git a/gems/smithy/lib/smithy/views/client/protocol_spec.rb b/gems/smithy/lib/smithy/views/client/protocol_spec.rb index 690a92e94..fa7580b61 100644 --- a/gems/smithy/lib/smithy/views/client/protocol_spec.rb +++ b/gems/smithy/lib/smithy/views/client/protocol_spec.rb @@ -157,8 +157,7 @@ def body_expect when 'application/x-www-form-urlencoded' "expect(CGI.parse(request.body.read)).to eq(CGI.parse('#{@test_case['body']}'))" when 'application/xml' - 'expect(Smithy::Xml::Parser.new.parse(response.context.operation.input, request.body.read)).' \ - "to eq(Smithy::Xml::Parser.new.parse(response.context.operation.input, '#{@test_case['body']}'))" + "expect(request.body.read).to eq('#{@test_case['body'].gsub(/>\n\s*<').strip}')" else "expect(request.body.read).to eq('#{@test_case['body']}')" end diff --git a/gems/smithy/lib/smithy/views/client/schema.rb b/gems/smithy/lib/smithy/views/client/schema.rb index 3c699aa7e..4ef5c040e 100644 --- a/gems/smithy/lib/smithy/views/client/schema.rb +++ b/gems/smithy/lib/smithy/views/client/schema.rb @@ -115,16 +115,16 @@ def paginator private def build_input(input) - ShapeRef.new(@service, Model::Shape.name(input['target']), input) + ShapeRef.new(@service, nil, input) end def build_output(output) - ShapeRef.new(@service, Model::Shape.name(output['target']), output) + ShapeRef.new(@service, nil, output) end def build_errors(errors) errors = Set.new(@service.fetch('errors', [])).merge(errors) - errors.map { |error| ShapeRef.new(@service, Model::Shape.name(error['target']), error) } + errors.map { |error| ShapeRef.new(@service, nil, error) } end end From 01991c27cbd26bff4691c551f15d2023f60bade8 Mon Sep 17 00:00:00 2001 From: Matt Muller Date: Wed, 13 Aug 2025 10:06:20 -0400 Subject: [PATCH 08/14] Regenerate, minor change --- gems/smithy-xml/lib/smithy-xml/builder.rb | 4 ++-- projections/shapes/lib/shapes/schema.rb | 4 ++-- projections/weather/lib/weather/schema.rb | 18 +++++++++--------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/gems/smithy-xml/lib/smithy-xml/builder.rb b/gems/smithy-xml/lib/smithy-xml/builder.rb index 4369136c6..3ef193a17 100644 --- a/gems/smithy-xml/lib/smithy-xml/builder.rb +++ b/gems/smithy-xml/lib/smithy-xml/builder.rb @@ -67,7 +67,7 @@ def map(name, ref, values) # rubocop:disable Metrics/AbcSize else node(name, ref) do values.each do |key, value| - node('entry', ShapeRef.new) do + node('entry', ShapeRef.new(shape: MapShape.new)) do shape(location_name(key_ref, 'key'), key_ref, key) shape(location_name(value_ref, 'value'), value_ref, value) end @@ -156,7 +156,7 @@ def node(name, ref, *args, &) def shape_attrs(ref) trait = 'smithy.api#xmlNamespace' - xmlns = ref.traits[trait] || (ref.shape && ref.shape.traits[trait]) + xmlns = ref.traits[trait] || ref.shape.traits[trait] return {} unless xmlns if (prefix = xmlns['prefix']) diff --git a/projections/shapes/lib/shapes/schema.rb b/projections/shapes/lib/shapes/schema.rb index db700ce1a..5b792d37c 100644 --- a/projections/shapes/lib/shapes/schema.rb +++ b/projections/shapes/lib/shapes/schema.rb @@ -89,8 +89,8 @@ module Schema service.add_operation(:operation, Smithy::Schema::Shapes::OperationShape.new do |operation| operation.id = "smithy.ruby.tests#Operation" operation.name = "Operation" - operation.input = Smithy::Schema::Shapes::ShapeRef.new(shape: OperationInput, location_name: 'OperationInput') - operation.output = Smithy::Schema::Shapes::ShapeRef.new(shape: OperationOutput, location_name: 'OperationOutput') + operation.input = Smithy::Schema::Shapes::ShapeRef.new(shape: OperationInput) + operation.output = Smithy::Schema::Shapes::ShapeRef.new(shape: OperationOutput) operation.traits = {"smithy.ruby.tests#shape" => {}} end) diff --git a/projections/weather/lib/weather/schema.rb b/projections/weather/lib/weather/schema.rb index 42570aacd..d6904e350 100644 --- a/projections/weather/lib/weather/schema.rb +++ b/projections/weather/lib/weather/schema.rb @@ -54,30 +54,30 @@ module Schema service.add_operation(:get_city, Smithy::Schema::Shapes::OperationShape.new do |operation| operation.id = "example.weather#GetCity" operation.name = "GetCity" - operation.input = Smithy::Schema::Shapes::ShapeRef.new(shape: GetCityInput, location_name: 'GetCityInput') - operation.output = Smithy::Schema::Shapes::ShapeRef.new(shape: GetCityOutput, location_name: 'GetCityOutput') - operation.errors << Smithy::Schema::Shapes::ShapeRef.new(shape: NoSuchResource, location_name: 'NoSuchResource') + operation.input = Smithy::Schema::Shapes::ShapeRef.new(shape: GetCityInput) + operation.output = Smithy::Schema::Shapes::ShapeRef.new(shape: GetCityOutput) + operation.errors << Smithy::Schema::Shapes::ShapeRef.new(shape: NoSuchResource) operation.traits = {"smithy.api#readonly" => {}} end) service.add_operation(:get_current_time, Smithy::Schema::Shapes::OperationShape.new do |operation| operation.id = "example.weather#GetCurrentTime" operation.name = "GetCurrentTime" - operation.input = Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::Unit, location_name: 'Unit') - operation.output = Smithy::Schema::Shapes::ShapeRef.new(shape: GetCurrentTimeOutput, location_name: 'GetCurrentTimeOutput') + operation.input = Smithy::Schema::Shapes::ShapeRef.new(shape: Smithy::Schema::Shapes::Prelude::Unit) + operation.output = Smithy::Schema::Shapes::ShapeRef.new(shape: GetCurrentTimeOutput) operation.traits = {"smithy.api#readonly" => {}} end) service.add_operation(:get_forecast, Smithy::Schema::Shapes::OperationShape.new do |operation| operation.id = "example.weather#GetForecast" operation.name = "GetForecast" - operation.input = Smithy::Schema::Shapes::ShapeRef.new(shape: GetForecastInput, location_name: 'GetForecastInput') - operation.output = Smithy::Schema::Shapes::ShapeRef.new(shape: GetForecastOutput, location_name: 'GetForecastOutput') + operation.input = Smithy::Schema::Shapes::ShapeRef.new(shape: GetForecastInput) + operation.output = Smithy::Schema::Shapes::ShapeRef.new(shape: GetForecastOutput) operation.traits = {"smithy.api#readonly" => {}} end) service.add_operation(:list_cities, Smithy::Schema::Shapes::OperationShape.new do |operation| operation.id = "example.weather#ListCities" operation.name = "ListCities" - operation.input = Smithy::Schema::Shapes::ShapeRef.new(shape: ListCitiesInput, location_name: 'ListCitiesInput') - operation.output = Smithy::Schema::Shapes::ShapeRef.new(shape: ListCitiesOutput, location_name: 'ListCitiesOutput') + operation.input = Smithy::Schema::Shapes::ShapeRef.new(shape: ListCitiesInput) + operation.output = Smithy::Schema::Shapes::ShapeRef.new(shape: ListCitiesOutput) operation.traits = {"smithy.api#readonly" => {}} operation[:paginator] = Paginators::ListCities.new end) From 77afe4295dccf0f2c69f2c1cb1c686c35d7542fb Mon Sep 17 00:00:00 2001 From: Matt Muller Date: Wed, 13 Aug 2025 10:46:59 -0400 Subject: [PATCH 09/14] Support skipping tests by type --- .../lib/smithy/templates/client/protocol_spec.erb | 10 +++++----- gems/smithy/lib/smithy/views/client/protocol_spec.rb | 4 ++-- gems/smithy/model/skip_tests.smithy | 3 +++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/gems/smithy/lib/smithy/templates/client/protocol_spec.erb b/gems/smithy/lib/smithy/templates/client/protocol_spec.erb index c4cbf6fdb..a5eaf0161 100644 --- a/gems/smithy/lib/smithy/templates/client/protocol_spec.erb +++ b/gems/smithy/lib/smithy/templates/client/protocol_spec.erb @@ -15,7 +15,7 @@ module <%= module_name %> <% test.docstrings.each do |line| -%> # <%= line %> <% end -%> -<% if test.skip? -%> +<% if test.skip?('request') -%> it '<%= test['id'] %>', skip: '<%= test.skip_reason %>' do <% else -%> it '<%= test['id'] %>' do @@ -73,7 +73,7 @@ module <%= module_name %> <% test.docstrings.each do |line| -%> # <%= line %> <% end -%> -<% if test.skip? -%> +<% if test.skip?('response') -%> it '<%= test['id'] %>', skip: '<%= test.skip_reason %>' do <% else -%> it '<%= test['id'] %>' do @@ -92,7 +92,7 @@ module <%= module_name %> describe 'response stubs' do <% operation_tests.response_tests.each do |test| -%> -<% if test.skip? -%> +<% if test.skip?('stub') -%> it '<%= test['id'] %>', skip: '<%= test.skip_reason %>' do <% else -%> it '<%= test['id'] %>' do @@ -115,7 +115,7 @@ module <%= module_name %> <% test.docstrings.each do |line| -%> # <%= line %> <% end -%> -<% if test.skip? -%> +<% if test.skip?('response') -%> it '<%= test['id'] %>: <%= test.error_name %>', skip: '<%= test.skip_reason %>' do <% else -%> it '<%= test['id'] %>: <%= test.error_name %>' do @@ -134,7 +134,7 @@ module <%= module_name %> describe 'response error stubs' do <% operation_tests.error_tests.each do |test| -%> -<% if test.skip? -%> +<% if test.skip?('stub') -%> it '<%= test['id'] %>: <%= test.error_name %>', skip: '<%= test.skip_reason %>' do <% else -%> it '<%= test['id'] %>: <%= test.error_name %>' do diff --git a/gems/smithy/lib/smithy/views/client/protocol_spec.rb b/gems/smithy/lib/smithy/views/client/protocol_spec.rb index fa7580b61..fe40b69b0 100644 --- a/gems/smithy/lib/smithy/views/client/protocol_spec.rb +++ b/gems/smithy/lib/smithy/views/client/protocol_spec.rb @@ -119,11 +119,11 @@ def docstrings @test_case.fetch('documentation', '').split("\n") end - def skip? + def skip?(type) @operation .fetch('traits', {}) .fetch('smithy.ruby#skipTests', []) - .any? { |skip| skip['id'] == @test_case['id'] } + .any? { |skip| skip['id'] == @test_case['id'] && skip['type'] == type } end def skip_reason diff --git a/gems/smithy/model/skip_tests.smithy b/gems/smithy/model/skip_tests.smithy index 539e66e0f..dfd4b0b61 100644 --- a/gems/smithy/model/skip_tests.smithy +++ b/gems/smithy/model/skip_tests.smithy @@ -20,4 +20,7 @@ enum TestType { @enumValue("response") RESPONSE + + @enumValue("stub") + STUB } From 1f65c377a6f35affcfdb19f0c9a7802cade082e2 Mon Sep 17 00:00:00 2001 From: Matt Muller Date: Thu, 14 Aug 2025 11:34:37 -0400 Subject: [PATCH 10/14] Loosen skipping requirements --- gems/smithy/lib/smithy/views/client/protocol_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gems/smithy/lib/smithy/views/client/protocol_spec.rb b/gems/smithy/lib/smithy/views/client/protocol_spec.rb index fe40b69b0..86756a8ee 100644 --- a/gems/smithy/lib/smithy/views/client/protocol_spec.rb +++ b/gems/smithy/lib/smithy/views/client/protocol_spec.rb @@ -123,7 +123,8 @@ def skip?(type) @operation .fetch('traits', {}) .fetch('smithy.ruby#skipTests', []) - .any? { |skip| skip['id'] == @test_case['id'] && skip['type'] == type } + .select { |skip| skip['type'] == type if type } + .any? { |skip| skip['id'] == @test_case['id'] } end def skip_reason From b6481aebb692ab1a77f7f0c12b6d2a2285e87310 Mon Sep 17 00:00:00 2001 From: Matt Muller Date: Thu, 14 Aug 2025 11:35:54 -0400 Subject: [PATCH 11/14] Revert "Loosen skipping requirements" This reverts commit 1f65c377a6f35affcfdb19f0c9a7802cade082e2. --- gems/smithy/lib/smithy/views/client/protocol_spec.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gems/smithy/lib/smithy/views/client/protocol_spec.rb b/gems/smithy/lib/smithy/views/client/protocol_spec.rb index 86756a8ee..fe40b69b0 100644 --- a/gems/smithy/lib/smithy/views/client/protocol_spec.rb +++ b/gems/smithy/lib/smithy/views/client/protocol_spec.rb @@ -123,8 +123,7 @@ def skip?(type) @operation .fetch('traits', {}) .fetch('smithy.ruby#skipTests', []) - .select { |skip| skip['type'] == type if type } - .any? { |skip| skip['id'] == @test_case['id'] } + .any? { |skip| skip['id'] == @test_case['id'] && skip['type'] == type } end def skip_reason From dcb198e813e01ba4afb103d55cbb657b69efa75f Mon Sep 17 00:00:00 2001 From: Matt Muller Date: Thu, 14 Aug 2025 12:09:27 -0400 Subject: [PATCH 12/14] Potentially correct codec building --- gems/smithy-xml/lib/smithy-xml/builder.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gems/smithy-xml/lib/smithy-xml/builder.rb b/gems/smithy-xml/lib/smithy-xml/builder.rb index 3ef193a17..c3984b49e 100644 --- a/gems/smithy-xml/lib/smithy-xml/builder.rb +++ b/gems/smithy-xml/lib/smithy-xml/builder.rb @@ -17,7 +17,7 @@ def build(shape, data, target = nil) ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape) target ||= [] @builder = DocBuilder.new(target: target, indent: @indent, pad: @pad) - structure(ref.location_name || ref.shape.traits['smithy.api#xmlName'] || ref.shape.name, ref, data) + structure(location_name(ref, ref.shape.traits['smithy.api#xmlName'] || ref.shape.name), ref, data) target.join end From a24ce1bcacd3da9c1e2b3a16a9aba6ba2a9292ba Mon Sep 17 00:00:00 2001 From: Matt Muller Date: Thu, 14 Aug 2025 12:11:24 -0400 Subject: [PATCH 13/14] Fix builder spec --- gems/smithy-xml/spec/smithy-xml/builder_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gems/smithy-xml/spec/smithy-xml/builder_spec.rb b/gems/smithy-xml/spec/smithy-xml/builder_spec.rb index 0bf408d23..ff78c8bdd 100644 --- a/gems/smithy-xml/spec/smithy-xml/builder_spec.rb +++ b/gems/smithy-xml/spec/smithy-xml/builder_spec.rb @@ -16,8 +16,8 @@ def inline(xml) end it 'returns an empty frame when given a unit shape' do - ref = Schema::Shapes::ShapeRef.new(shape: Schema::Shapes::Prelude::Unit, location_name: 'unit') - expect(subject.build(ref, '')).to eq('') + ref = Schema::Shapes::ShapeRef.new(shape: Schema::Shapes::Prelude::Unit) + expect(subject.build(ref, '')).to eq('') end context 'structures' do From b0d76fba65844529882ead2c5507f8681d4cfed6 Mon Sep 17 00:00:00 2001 From: Matt Muller Date: Thu, 14 Aug 2025 12:23:32 -0400 Subject: [PATCH 14/14] Revert --- gems/smithy-xml/lib/smithy-xml/builder.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gems/smithy-xml/lib/smithy-xml/builder.rb b/gems/smithy-xml/lib/smithy-xml/builder.rb index c3984b49e..3ef193a17 100644 --- a/gems/smithy-xml/lib/smithy-xml/builder.rb +++ b/gems/smithy-xml/lib/smithy-xml/builder.rb @@ -17,7 +17,7 @@ def build(shape, data, target = nil) ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape) target ||= [] @builder = DocBuilder.new(target: target, indent: @indent, pad: @pad) - structure(location_name(ref, ref.shape.traits['smithy.api#xmlName'] || ref.shape.name), ref, data) + structure(ref.location_name || ref.shape.traits['smithy.api#xmlName'] || ref.shape.name, ref, data) target.join end