diff --git a/go.mod b/go.mod index 5f36935..7740696 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,11 @@ module github.com/lyraproj/servicesdk require ( github.com/golang/protobuf v1.2.0 github.com/hashicorp/go-hclog v0.0.0-20190109152822-4783caec6f2e - github.com/hashicorp/go-plugin v0.0.0-20181212150838-f444068e8f5a + github.com/hashicorp/go-plugin v0.0.0-20190129155509-362c99b11937 github.com/lyraproj/data-protobuf v0.0.0-20181217135414-3d508204b820 github.com/lyraproj/issue v0.0.0-20190122215520-5efbea1d1edb - github.com/lyraproj/puppet-evaluator v0.0.0-20190124220224-0b2cf0dd23a8 + github.com/lyraproj/puppet-evaluator v0.0.0-20190206101254-33da261b6686 github.com/lyraproj/semver v0.0.0-20181213164306-02ecea2cd6a2 - golang.org/x/net v0.0.0-20190119204137-ed066c81e75e + golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3 google.golang.org/grpc v1.18.0 ) diff --git a/go.sum b/go.sum index 1c55ba5..18f5e86 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -8,8 +9,8 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= github.com/hashicorp/go-hclog v0.0.0-20190109152822-4783caec6f2e h1:SS6R03q1M5bxjbOL2JziQUUu7opiRocL4R2H5Y2I6rY= github.com/hashicorp/go-hclog v0.0.0-20190109152822-4783caec6f2e/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-plugin v0.0.0-20181212150838-f444068e8f5a h1:z9eTtDWoxYrJvtAD+xAepmTEfEmYgouWUytJ84UWAr8= -github.com/hashicorp/go-plugin v0.0.0-20181212150838-f444068e8f5a/go.mod h1:Ft7ju2vWzhO0ETMKUVo12XmXmII6eSUS4rsPTkY/siA= +github.com/hashicorp/go-plugin v0.0.0-20190129155509-362c99b11937 h1:F3biNWiyQYD6ch5Y/Kua5DKZKH3R0NtCvnv+KhZei20= +github.com/hashicorp/go-plugin v0.0.0-20190129155509-362c99b11937/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -18,8 +19,8 @@ github.com/lyraproj/data-protobuf v0.0.0-20181217135414-3d508204b820/go.mod h1:o github.com/lyraproj/issue v0.0.0-20181204205859-7ed1f9741f4a/go.mod h1:F3Zu9SjR6zROUIVdxgxuX0/Mi4npwgDRalQCNzCyzU0= github.com/lyraproj/issue v0.0.0-20190122215520-5efbea1d1edb h1:R3ukQUNWJTypfOAZwyJ5kcIyWjbm8KZnpxLaH29HWbw= github.com/lyraproj/issue v0.0.0-20190122215520-5efbea1d1edb/go.mod h1:F3Zu9SjR6zROUIVdxgxuX0/Mi4npwgDRalQCNzCyzU0= -github.com/lyraproj/puppet-evaluator v0.0.0-20190124220224-0b2cf0dd23a8 h1:Oo+0o/N6h29OvBrOZfnrQyVzw2CTNC/dAz3TVtA97kM= -github.com/lyraproj/puppet-evaluator v0.0.0-20190124220224-0b2cf0dd23a8/go.mod h1:Z0RDGXCJwnba8AZttdopo2/JzUiGsN7CECdUqZPR3wU= +github.com/lyraproj/puppet-evaluator v0.0.0-20190206101254-33da261b6686 h1:XJ0XkNSxZ5X+LQhdCAqQjRJ6Akem9fs6uvU0EnIh8lw= +github.com/lyraproj/puppet-evaluator v0.0.0-20190206101254-33da261b6686/go.mod h1:5gMxdOhUGjegM+AFGahiw59yoek+F6txIBhm8YCK/uk= github.com/lyraproj/puppet-parser v0.0.0-20181212205830-31c3104fe78d h1:iDn6XlJAiA+BuwG6L8xsCapPpc7jz24SGj9z7NQA1sg= github.com/lyraproj/puppet-parser v0.0.0-20181212205830-31c3104fe78d/go.mod h1:8va5g/XEw+jP9jnwEXPmanUy/hD9+6iggnaioihPLP0= github.com/lyraproj/semver v0.0.0-20181213164306-02ecea2cd6a2 h1:vb4PbiMtIXdhsOUinkkcqZiASDIZzXRhSG4yvNfE0tg= @@ -29,16 +30,19 @@ github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go. github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190119204137-ed066c81e75e h1:MDa3fSUp6MdYHouVmCCNz/zaH2a6CRcxY3VhT/K3C5Q= -golang.org/x/net v0.0.0-20190119204137-ed066c81e75e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3 h1:ulvT7fqt0yHWzpJwI57MezWnYDVpCAYBVuYst/L+fAY= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522 h1:Ve1ORMCxvRmSXBwJK+t3Oy+V2vRW2OetUQBq4rJIkZE= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc h1:WiYx1rIFmx8c0mXAFtv5D/mHyKe1+jmuP7PViuwqwuQ= +golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/lang/generator.go b/lang/generator.go new file mode 100644 index 0000000..dee908a --- /dev/null +++ b/lang/generator.go @@ -0,0 +1,18 @@ +package lang + +import ( + "bytes" + "github.com/lyraproj/puppet-evaluator/eval" +) + +// The Generator interface is implemented by generators that can transform Pcore types +// to types in some specific language. +type Generator interface { + // GenerateTypes produces types in some language for all types in the given TypeSet and + // appends them to the given buffer. + GenerateTypes(ts eval.TypeSet, ns []string, indent int, bld *bytes.Buffer) + + // GenerateType produces a type in some language for the given Type and appends it to + // the given buffer. + GenerateType(t eval.Type, ns []string, indent int, bld *bytes.Buffer) +} diff --git a/lang/typegen/testdata/aws.pp b/lang/typegen/testdata/aws.pp new file mode 100644 index 0000000..f589891 --- /dev/null +++ b/lang/typegen/testdata/aws.pp @@ -0,0 +1,2149 @@ +# this file is called aaws.pp so that it is processed before attach.pp as it contains types that are needed by the attach workflow +# the content of this file can be generated, ref TestGeneratePuppetTypes in register_types_test.go +type Aws = TypeSet[{ + pcore_uri => 'http://puppet.com/2016.1/pcore', + pcore_version => '1.0.0', + name_authority => 'http://puppet.com/2016.1/runtime', + name => 'Aws', + version => '0.1.0', + types => { + BlockDeviceMapping => { + attributes => { + 'device_name' => { + 'type' => String, + 'value' => '' + }, + 'ebs' => { + 'type' => Optional[EbsBlockDevice], + 'value' => undef + }, + 'no_device' => { + 'type' => String, + 'value' => '' + }, + 'virtual_name' => { + 'type' => String, + 'value' => '' + } + } + }, + CpuOptions => { + attributes => { + 'core_count' => { + 'type' => Integer, + 'value' => 0 + }, + 'threads_per_core' => { + 'type' => Integer, + 'value' => 0 + } + } + }, + EbsBlockDevice => { + attributes => { + 'delete_on_termination' => { + 'type' => Boolean, + 'value' => false + }, + 'encrypted' => { + 'type' => Boolean, + 'value' => false + }, + 'iops' => { + 'type' => Integer, + 'value' => 0 + }, + 'kms_key_id' => { + 'type' => String, + 'value' => '' + }, + 'snapshot_id' => { + 'type' => String, + 'value' => '' + }, + 'volume_size' => { + 'type' => Integer, + 'value' => 0 + }, + 'volume_type' => { + 'type' => String, + 'value' => '' + } + } + }, + GroupIdentifier => { + attributes => { + 'group_id' => { + 'type' => String, + 'value' => '' + }, + 'group_name' => { + 'type' => String, + 'value' => '' + } + } + }, + IamInstanceProfile => { + attributes => { + 'arn' => { + 'type' => String, + 'value' => '' + }, + 'name' => { + 'type' => String, + 'value' => '' + }, + 'id' => { + 'type' => String, + 'value' => '' + } + } + }, + IamRole => { + attributes => { + 'description' => { + 'type' => Optional[String], + 'value' => undef + }, + 'role_name' => String, + 'assume_role_policy_document' => String, + 'path' => { + 'type' => Optional[String], + 'value' => undef + }, + 'tags' => Hash[String, String] + } + }, + Instance => { + attributes => { + 'additional_info' => { + 'type' => String, + 'value' => '' + }, + 'block_device_mappings' => { + 'type' => Array[BlockDeviceMapping], + 'value' => [] + }, + 'client_token' => { + 'type' => String, + 'value' => '' + }, + 'cpu_options' => { + 'type' => Optional[CpuOptions], + 'value' => undef + }, + 'disable_api_termination' => { + 'type' => Boolean, + 'value' => false + }, + 'ebs_optimized' => { + 'type' => Boolean, + 'value' => false + }, + 'iam_instance_profile' => { + 'type' => Optional[IamInstanceProfile], + 'value' => undef + }, + 'image_id' => String, + 'instance_initiated_shutdown_behavior' => { + 'type' => String, + 'value' => '' + }, + 'instance_type' => String, + 'ipv6_address_count' => { + 'type' => Integer, + 'value' => 0 + }, + 'ipv6_addresses' => { + 'type' => Array[InstanceIpv6Address], + 'value' => [] + }, + 'kernel_id' => { + 'type' => String, + 'value' => '' + }, + 'key_name' => { + 'type' => String, + 'value' => '' + }, + 'launch_template' => { + 'type' => Optional[LaunchTemplateSpecification], + 'value' => undef + }, + 'max_count' => Integer, + 'min_count' => Integer, + 'monitoring' => { + 'type' => Optional[Monitoring], + 'value' => undef + }, + 'placement' => { + 'type' => Optional[Placement], + 'value' => undef + }, + 'private_ip_address' => { + 'type' => String, + 'value' => '' + }, + 'ramdisk_id' => { + 'type' => String, + 'value' => '' + }, + 'subnet_id' => { + 'type' => String, + 'value' => '' + }, + 'user_data' => { + 'type' => String, + 'value' => '' + }, + 'owner_id' => { + 'type' => String, + 'value' => '' + }, + 'requester_id' => { + 'type' => String, + 'value' => '' + }, + 'reservation_id' => { + 'type' => String, + 'value' => '' + }, + 'ami_launch_index' => { + 'type' => Integer, + 'value' => 0 + }, + 'architecture' => { + 'type' => String, + 'value' => '' + }, + 'ena_support' => { + 'type' => Boolean, + 'value' => false + }, + 'hypervisor' => { + 'type' => String, + 'value' => '' + }, + 'instance_id' => { + 'type' => String, + 'value' => '' + }, + 'instance_lifecycle' => { + 'type' => String, + 'value' => '' + }, + 'platform' => { + 'type' => String, + 'value' => '' + }, + 'private_dns_name' => { + 'type' => String, + 'value' => '' + }, + 'product_codes' => { + 'type' => Array[ProductCode], + 'value' => [] + }, + 'public_dns_name' => { + 'type' => String, + 'value' => '' + }, + 'public_ip_address' => { + 'type' => String, + 'value' => '' + }, + 'ram_disk_id' => { + 'type' => String, + 'value' => '' + }, + 'root_device_name' => { + 'type' => String, + 'value' => '' + }, + 'root_device_type' => { + 'type' => String, + 'value' => '' + }, + 'security_groups' => { + 'type' => Array[GroupIdentifier], + 'value' => [] + }, + 'source_dest_check' => { + 'type' => Boolean, + 'value' => false + }, + 'spot_instance_request_id' => { + 'type' => String, + 'value' => '' + }, + 'sriov_net_support' => { + 'type' => String, + 'value' => '' + }, + 'state' => { + 'type' => Optional[InstanceState], + 'value' => undef + }, + 'state_reason' => { + 'type' => Optional[StateReason], + 'value' => undef + }, + 'state_transition_reason' => { + 'type' => String, + 'value' => '' + }, + 'tags' => { + 'type' => Optional[Hash[String, String]], + 'kind' => 'given_or_derived' + }, + 'virtualization_type' => { + 'type' => String, + 'value' => '' + }, + 'vpc_id' => { + 'type' => String, + 'value' => '' + } + } + }, + InstanceHandler => { + functions => { + 'create' => Callable[ + [Optional[Instance]], + Tuple[Optional[Instance], String]], + 'delete' => Callable[String], + 'read' => Callable[ + [String], + Optional[Instance]] + } + }, + InstanceIpv6Address => { + attributes => { + 'ipv6_address' => { + 'type' => String, + 'value' => '' + } + } + }, + InstanceState => { + attributes => { + 'code' => { + 'type' => Integer, + 'value' => 0 + }, + 'name' => { + 'type' => String, + 'value' => '' + } + } + }, + InternetGateway => { + annotations => { + Lyra::Resource => { + 'immutable_attributes' => ['tags'], + 'provided_attributes' => ['internet_gateway_id'] + } + }, + attributes => { + 'internet_gateway_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'tags' => Hash[String, String], + 'attachments' => { + 'type' => Array[InternetGatewayAttachment], + 'value' => [] + } + } + }, + InternetGatewayAttachment => { + attributes => { + 'state' => String, + 'vpc_id' => String + } + }, + InternetGatewayHandler => { + functions => { + 'create' => Callable[ + [Optional[InternetGateway]], + Tuple[Optional[InternetGateway], String]], + 'delete' => Callable[String], + 'read' => Callable[ + [String], + Optional[InternetGateway]] + } + }, + IpPermission => { + attributes => { + 'from_port' => { + 'type' => Integer, + 'value' => 0 + }, + 'ip_protocol' => { + 'type' => String, + 'value' => '' + }, + 'ip_ranges' => { + 'type' => Array[IpRange], + 'value' => [] + }, + 'ipv6_ranges' => { + 'type' => Array[Ipv6Range], + 'value' => [] + }, + 'prefix_list_ids' => { + 'type' => Array[PrefixListId], + 'value' => [] + }, + 'to_port' => { + 'type' => Integer, + 'value' => 0 + }, + 'user_id_group_pairs' => { + 'type' => Array[UserIdGroupPair], + 'value' => [] + } + } + }, + IpRange => { + attributes => { + 'cidr_ip' => { + 'type' => String, + 'value' => '' + }, + 'description' => { + 'type' => String, + 'value' => '' + } + } + }, + Ipv6Range => { + attributes => { + 'cidr_ipv6' => { + 'type' => String, + 'value' => '' + }, + 'description' => { + 'type' => String, + 'value' => '' + } + } + }, + KeyPair => { + attributes => { + 'public_key_material' => String, + 'key_name' => String, + 'key_fingerprint' => { + 'type' => String, + 'value' => '' + } + } + }, + KeyPairHandler => { + functions => { + 'create' => Callable[ + [Optional[KeyPair]], + Tuple[Optional[KeyPair], String]], + 'delete' => Callable[String], + 'read' => Callable[ + [String], + Optional[KeyPair]] + } + }, + LaunchTemplateSpecification => { + attributes => { + 'launch_template_id' => { + 'type' => String, + 'value' => '' + }, + 'launch_template_name' => { + 'type' => String, + 'value' => '' + }, + 'version' => { + 'type' => String, + 'value' => '' + } + } + }, + Monitoring => { + attributes => { + 'enabled' => { + 'type' => Boolean, + 'value' => false + }, + 'state' => { + 'type' => String, + 'value' => '' + } + } + }, + Native => TypeSet[{ + pcore_uri => 'http://puppet.com/2016.1/pcore', + pcore_version => '1.0.0', + name_authority => 'http://puppet.com/2016.1/runtime', + name => 'Aws::Native', + version => '0.1.0', + types => { + CapacityReservationSpecificationResponse => { + attributes => { + 'capacity_reservation_preference' => { + 'type' => Optional[String], + 'value' => undef + }, + 'capacity_reservation_target' => { + 'type' => Optional[CapacityReservationTargetResponse], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + CapacityReservationTargetResponse => { + attributes => { + 'capacity_reservation_id' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + CpuOptions => { + attributes => { + 'core_count' => { + 'type' => Optional[Integer], + 'value' => undef + }, + 'threads_per_core' => { + 'type' => Optional[Integer], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + EbsInstanceBlockDevice => { + attributes => { + 'attach_time' => { + 'type' => Optional[Timestamp], + 'value' => undef + }, + 'delete_on_termination' => { + 'type' => Optional[Boolean], + 'value' => undef + }, + 'status' => { + 'type' => Optional[String], + 'value' => undef + }, + 'volume_id' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + ElasticGpuAssociation => { + attributes => { + 'elastic_gpu_association_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'elastic_gpu_association_state' => { + 'type' => Optional[String], + 'value' => undef + }, + 'elastic_gpu_association_time' => { + 'type' => Optional[String], + 'value' => undef + }, + 'elastic_gpu_id' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + ElasticInferenceAcceleratorAssociation => { + attributes => { + 'elastic_inference_accelerator_arn' => { + 'type' => Optional[String], + 'value' => undef + }, + 'elastic_inference_accelerator_association_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'elastic_inference_accelerator_association_state' => { + 'type' => Optional[String], + 'value' => undef + }, + 'elastic_inference_accelerator_association_time' => { + 'type' => Optional[Timestamp], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + GroupIdentifier => { + attributes => { + 'group_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'group_name' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + HibernationOptions => { + attributes => { + 'configured' => { + 'type' => Optional[Boolean], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + IamInstanceProfile => { + attributes => { + 'arn' => { + 'type' => Optional[String], + 'value' => undef + }, + 'id' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + Instance => { + attributes => { + 'ami_launch_index' => { + 'type' => Optional[Integer], + 'value' => undef + }, + 'architecture' => { + 'type' => Optional[String], + 'value' => undef + }, + 'block_device_mappings' => Array[Optional[InstanceBlockDeviceMapping]], + 'capacity_reservation_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'capacity_reservation_specification' => { + 'type' => Optional[CapacityReservationSpecificationResponse], + 'value' => undef + }, + 'client_token' => { + 'type' => Optional[String], + 'value' => undef + }, + 'cpu_options' => { + 'type' => Optional[CpuOptions], + 'value' => undef + }, + 'ebs_optimized' => { + 'type' => Optional[Boolean], + 'value' => undef + }, + 'elastic_gpu_associations' => Array[Optional[ElasticGpuAssociation]], + 'elastic_inference_accelerator_associations' => Array[Optional[ElasticInferenceAcceleratorAssociation]], + 'ena_support' => { + 'type' => Optional[Boolean], + 'value' => undef + }, + 'hibernation_options' => { + 'type' => Optional[HibernationOptions], + 'value' => undef + }, + 'hypervisor' => { + 'type' => Optional[String], + 'value' => undef + }, + 'iam_instance_profile' => { + 'type' => Optional[IamInstanceProfile], + 'value' => undef + }, + 'image_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'instance_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'instance_lifecycle' => { + 'type' => Optional[String], + 'value' => undef + }, + 'instance_type' => { + 'type' => Optional[String], + 'value' => undef + }, + 'kernel_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'key_name' => { + 'type' => Optional[String], + 'value' => undef + }, + 'launch_time' => { + 'type' => Optional[Timestamp], + 'value' => undef + }, + 'licenses' => Array[Optional[LicenseConfiguration]], + 'monitoring' => { + 'type' => Optional[Monitoring], + 'value' => undef + }, + 'network_interfaces' => Array[Optional[InstanceNetworkInterface]], + 'placement' => { + 'type' => Optional[Placement], + 'value' => undef + }, + 'platform' => { + 'type' => Optional[String], + 'value' => undef + }, + 'private_dns_name' => { + 'type' => Optional[String], + 'value' => undef + }, + 'private_ip_address' => { + 'type' => Optional[String], + 'value' => undef + }, + 'product_codes' => Array[Optional[ProductCode]], + 'public_dns_name' => { + 'type' => Optional[String], + 'value' => undef + }, + 'public_ip_address' => { + 'type' => Optional[String], + 'value' => undef + }, + 'ramdisk_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'root_device_name' => { + 'type' => Optional[String], + 'value' => undef + }, + 'root_device_type' => { + 'type' => Optional[String], + 'value' => undef + }, + 'security_groups' => Array[Optional[GroupIdentifier]], + 'source_dest_check' => { + 'type' => Optional[Boolean], + 'value' => undef + }, + 'spot_instance_request_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'sriov_net_support' => { + 'type' => Optional[String], + 'value' => undef + }, + 'state' => { + 'type' => Optional[InstanceState], + 'value' => undef + }, + 'state_reason' => { + 'type' => Optional[StateReason], + 'value' => undef + }, + 'state_transition_reason' => { + 'type' => Optional[String], + 'value' => undef + }, + 'subnet_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'tags' => Array[Optional[Tag]], + 'virtualization_type' => { + 'type' => Optional[String], + 'value' => undef + }, + 'vpc_id' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + InstanceBlockDeviceMapping => { + attributes => { + 'device_name' => { + 'type' => Optional[String], + 'value' => undef + }, + 'ebs' => { + 'type' => Optional[EbsInstanceBlockDevice], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + InstanceIpv6Address => { + attributes => { + 'ipv6_address' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + InstanceNetworkInterface => { + attributes => { + 'association' => { + 'type' => Optional[InstanceNetworkInterfaceAssociation], + 'value' => undef + }, + 'attachment' => { + 'type' => Optional[InstanceNetworkInterfaceAttachment], + 'value' => undef + }, + 'description' => { + 'type' => Optional[String], + 'value' => undef + }, + 'groups' => Array[Optional[GroupIdentifier]], + 'ipv6_addresses' => Array[Optional[InstanceIpv6Address]], + 'mac_address' => { + 'type' => Optional[String], + 'value' => undef + }, + 'network_interface_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'owner_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'private_dns_name' => { + 'type' => Optional[String], + 'value' => undef + }, + 'private_ip_address' => { + 'type' => Optional[String], + 'value' => undef + }, + 'private_ip_addresses' => Array[Optional[InstancePrivateIpAddress]], + 'source_dest_check' => { + 'type' => Optional[Boolean], + 'value' => undef + }, + 'status' => { + 'type' => Optional[String], + 'value' => undef + }, + 'subnet_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'vpc_id' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + InstanceNetworkInterfaceAssociation => { + attributes => { + 'ip_owner_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'public_dns_name' => { + 'type' => Optional[String], + 'value' => undef + }, + 'public_ip' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + InstanceNetworkInterfaceAttachment => { + attributes => { + 'attach_time' => { + 'type' => Optional[Timestamp], + 'value' => undef + }, + 'attachment_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'delete_on_termination' => { + 'type' => Optional[Boolean], + 'value' => undef + }, + 'device_index' => { + 'type' => Optional[Integer], + 'value' => undef + }, + 'status' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + InstancePrivateIpAddress => { + attributes => { + 'association' => { + 'type' => Optional[InstanceNetworkInterfaceAssociation], + 'value' => undef + }, + 'primary' => { + 'type' => Optional[Boolean], + 'value' => undef + }, + 'private_dns_name' => { + 'type' => Optional[String], + 'value' => undef + }, + 'private_ip_address' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + InstanceState => { + attributes => { + 'code' => { + 'type' => Optional[Integer], + 'value' => undef + }, + 'name' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + InternetGateway => { + attributes => { + 'attachments' => Array[Optional[InternetGatewayAttachment]], + 'internet_gateway_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'owner_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'tags' => Array[Optional[Tag]] + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + InternetGatewayAttachment => { + attributes => { + 'state' => { + 'type' => Optional[String], + 'value' => undef + }, + 'vpc_id' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + IpPermission => { + attributes => { + 'from_port' => { + 'type' => Optional[Integer], + 'value' => undef + }, + 'ip_protocol' => { + 'type' => Optional[String], + 'value' => undef + }, + 'ip_ranges' => Array[Optional[IpRange]], + 'ipv6_ranges' => Array[Optional[Ipv6Range]], + 'prefix_list_ids' => Array[Optional[PrefixListId]], + 'to_port' => { + 'type' => Optional[Integer], + 'value' => undef + }, + 'user_id_group_pairs' => Array[Optional[UserIdGroupPair]] + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + IpRange => { + attributes => { + 'cidr_ip' => { + 'type' => Optional[String], + 'value' => undef + }, + 'description' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + Ipv6Range => { + attributes => { + 'cidr_ipv6' => { + 'type' => Optional[String], + 'value' => undef + }, + 'description' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + LicenseConfiguration => { + attributes => { + 'license_configuration_arn' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + Monitoring => { + attributes => { + 'state' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + Placement => { + attributes => { + 'affinity' => { + 'type' => Optional[String], + 'value' => undef + }, + 'availability_zone' => { + 'type' => Optional[String], + 'value' => undef + }, + 'group_name' => { + 'type' => Optional[String], + 'value' => undef + }, + 'host_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'partition_number' => { + 'type' => Optional[Integer], + 'value' => undef + }, + 'spread_domain' => { + 'type' => Optional[String], + 'value' => undef + }, + 'tenancy' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + PrefixListId => { + attributes => { + 'description' => { + 'type' => Optional[String], + 'value' => undef + }, + 'prefix_list_id' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + ProductCode => { + attributes => { + 'product_code_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'product_code_type' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + PropagatingVgw => { + attributes => { + 'gateway_id' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + Route => { + attributes => { + 'destination_cidr_block' => { + 'type' => Optional[String], + 'value' => undef + }, + 'destination_ipv6_cidr_block' => { + 'type' => Optional[String], + 'value' => undef + }, + 'destination_prefix_list_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'egress_only_internet_gateway_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'gateway_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'instance_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'instance_owner_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'nat_gateway_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'network_interface_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'origin' => { + 'type' => Optional[String], + 'value' => undef + }, + 'state' => { + 'type' => Optional[String], + 'value' => undef + }, + 'transit_gateway_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'vpc_peering_connection_id' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + RouteTable => { + attributes => { + 'associations' => Array[Optional[RouteTableAssociation]], + 'owner_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'propagating_vgws' => Array[Optional[PropagatingVgw]], + 'route_table_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'routes' => Array[Optional[Route]], + 'tags' => Array[Optional[Tag]], + 'vpc_id' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + RouteTableAssociation => { + attributes => { + 'main' => { + 'type' => Optional[Boolean], + 'value' => undef + }, + 'route_table_association_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'route_table_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'subnet_id' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + SecurityGroup => { + attributes => { + 'description' => { + 'type' => Optional[String], + 'value' => undef + }, + 'group_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'group_name' => { + 'type' => Optional[String], + 'value' => undef + }, + 'ip_permissions' => Array[Optional[IpPermission]], + 'ip_permissions_egress' => Array[Optional[IpPermission]], + 'owner_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'tags' => Array[Optional[Tag]], + 'vpc_id' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + StateReason => { + attributes => { + 'code' => { + 'type' => Optional[String], + 'value' => undef + }, + 'message' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + Subnet => { + attributes => { + 'assign_ipv6_address_on_creation' => { + 'type' => Optional[Boolean], + 'value' => undef + }, + 'availability_zone' => { + 'type' => Optional[String], + 'value' => undef + }, + 'availability_zone_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'available_ip_address_count' => { + 'type' => Optional[Integer], + 'value' => undef + }, + 'cidr_block' => { + 'type' => Optional[String], + 'value' => undef + }, + 'default_for_az' => { + 'type' => Optional[Boolean], + 'value' => undef + }, + 'ipv6_cidr_block_association_set' => Array[Optional[SubnetIpv6CidrBlockAssociation]], + 'map_public_ip_on_launch' => { + 'type' => Optional[Boolean], + 'value' => undef + }, + 'owner_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'state' => { + 'type' => Optional[String], + 'value' => undef + }, + 'subnet_arn' => { + 'type' => Optional[String], + 'value' => undef + }, + 'subnet_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'tags' => Array[Optional[Tag]], + 'vpc_id' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + SubnetCidrBlockState => { + attributes => { + 'state' => { + 'type' => Optional[String], + 'value' => undef + }, + 'status_message' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + SubnetIpv6CidrBlockAssociation => { + attributes => { + 'association_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'ipv6_cidr_block' => { + 'type' => Optional[String], + 'value' => undef + }, + 'ipv6_cidr_block_state' => { + 'type' => Optional[SubnetCidrBlockState], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + Tag => { + attributes => { + 'key' => { + 'type' => Optional[String], + 'value' => undef + }, + 'value' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + UserIdGroupPair => { + attributes => { + 'description' => { + 'type' => Optional[String], + 'value' => undef + }, + 'group_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'group_name' => { + 'type' => Optional[String], + 'value' => undef + }, + 'peering_status' => { + 'type' => Optional[String], + 'value' => undef + }, + 'user_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'vpc_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'vpc_peering_connection_id' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + Vpc => { + attributes => { + 'cidr_block' => { + 'type' => Optional[String], + 'value' => undef + }, + 'cidr_block_association_set' => Array[Optional[VpcCidrBlockAssociation]], + 'dhcp_options_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'instance_tenancy' => { + 'type' => Optional[String], + 'value' => undef + }, + 'ipv6_cidr_block_association_set' => Array[Optional[VpcIpv6CidrBlockAssociation]], + 'is_default' => { + 'type' => Optional[Boolean], + 'value' => undef + }, + 'owner_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'state' => { + 'type' => Optional[String], + 'value' => undef + }, + 'tags' => Array[Optional[Tag]], + 'vpc_id' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + VpcCidrBlockAssociation => { + attributes => { + 'association_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'cidr_block' => { + 'type' => Optional[String], + 'value' => undef + }, + 'cidr_block_state' => { + 'type' => Optional[VpcCidrBlockState], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + VpcCidrBlockState => { + attributes => { + 'state' => { + 'type' => Optional[String], + 'value' => undef + }, + 'status_message' => { + 'type' => Optional[String], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + }, + VpcIpv6CidrBlockAssociation => { + attributes => { + 'association_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'ipv6_cidr_block' => { + 'type' => Optional[String], + 'value' => undef + }, + 'ipv6_cidr_block_state' => { + 'type' => Optional[VpcCidrBlockState], + 'value' => undef + } + }, + functions => { + 'go_string' => Callable[ + [0, 0], + String], + 'string' => Callable[ + [0, 0], + String] + } + } + } + }], + NativeInstanceHandler => { + functions => { + 'create' => Callable[ + [Optional[Native::Instance]], + Tuple[Optional[Native::Instance], String]], + 'delete' => Callable[String], + 'read' => Callable[ + [String], + Optional[Native::Instance]] + } + }, + NativeInternetGatewayHandler => { + functions => { + 'create' => Callable[ + [Optional[Native::InternetGateway]], + Tuple[Optional[Native::InternetGateway], String]], + 'delete' => Callable[String], + 'read' => Callable[ + [String], + Optional[Native::InternetGateway]] + } + }, + NativeRouteTableHandler => { + functions => { + 'create' => Callable[ + [Optional[Native::RouteTable]], + Tuple[Optional[Native::RouteTable], String]], + 'delete' => Callable[String], + 'read' => Callable[ + [String], + Optional[Native::RouteTable]] + } + }, + NativeSecurityGroupHandler => { + functions => { + 'create' => Callable[ + [Optional[Native::SecurityGroup]], + Tuple[Optional[Native::SecurityGroup], String]], + 'delete' => Callable[String], + 'read' => Callable[ + [String], + Optional[Native::SecurityGroup]] + } + }, + NativeSubnetHandler => { + functions => { + 'create' => Callable[ + [Optional[Native::Subnet]], + Tuple[Optional[Native::Subnet], String]], + 'delete' => Callable[String], + 'read' => Callable[ + [String], + Optional[Native::Subnet]] + } + }, + NativeVpcHandler => { + functions => { + 'create' => Callable[ + [Optional[Native::Vpc]], + Tuple[Optional[Native::Vpc], String]], + 'delete' => Callable[String], + 'read' => Callable[ + [String], + Optional[Native::Vpc]] + } + }, + Placement => { + attributes => { + 'affinity' => { + 'type' => String, + 'value' => '' + }, + 'availability_zone' => { + 'type' => String, + 'value' => '' + }, + 'group_name' => { + 'type' => String, + 'value' => '' + }, + 'host_id' => { + 'type' => String, + 'value' => '' + }, + 'spread_domain' => { + 'type' => String, + 'value' => '' + }, + 'tenancy' => { + 'type' => String, + 'value' => '' + } + } + }, + PrefixListId => { + attributes => { + 'description' => { + 'type' => String, + 'value' => '' + }, + 'prefix_list_id' => { + 'type' => String, + 'value' => '' + } + } + }, + ProductCode => { + attributes => { + 'product_code_id' => { + 'type' => String, + 'value' => '' + }, + 'product_code_type' => { + 'type' => String, + 'value' => '' + } + } + }, + PropagatingVgw => { + attributes => { + 'gateway_id' => String + } + }, + RoleHandler => { + functions => { + 'create' => Callable[ + [Optional[IamRole]], + Tuple[Optional[IamRole], String]], + 'delete' => Callable[String], + 'read' => Callable[ + [String], + Optional[IamRole]] + } + }, + Route => { + attributes => { + 'destination_cidr_block' => { + 'type' => String, + 'value' => '' + }, + 'destination_ipv6_cidr_block' => { + 'type' => String, + 'value' => '' + }, + 'destination_prefix_list_id' => { + 'type' => String, + 'value' => '' + }, + 'egress_only_internet_gateway_id' => { + 'type' => String, + 'value' => '' + }, + 'gateway_id' => { + 'type' => String, + 'value' => '' + }, + 'instance_id' => { + 'type' => String, + 'value' => '' + }, + 'instance_owner_id' => { + 'type' => String, + 'value' => '' + }, + 'nat_gateway_id' => { + 'type' => String, + 'value' => '' + }, + 'network_interface_id' => { + 'type' => String, + 'value' => '' + }, + 'origin' => { + 'type' => String, + 'value' => '' + }, + 'state' => { + 'type' => String, + 'value' => '' + }, + 'vpc_peering_connection_id' => { + 'type' => String, + 'value' => '' + }, + 'tags' => Hash[String, String] + } + }, + RouteTable => { + annotations => { + Lyra::Resource => { + 'immutable_attributes' => ['tags'], + 'provided_attributes' => ['route_table_id', 'routes'] + } + }, + attributes => { + 'vpc_id' => String, + 'route_table_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'subnet_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'routes' => { + 'type' => Array[Route], + 'value' => [] + }, + 'associations' => { + 'type' => Array[RouteTableAssociation], + 'value' => [] + }, + 'propagating_vgws' => { + 'type' => Array[PropagatingVgw], + 'value' => [] + }, + 'tags' => Hash[String, String] + } + }, + RouteTableAssociation => { + attributes => { + 'main' => Boolean, + 'route_table_association_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'route_table_id' => String, + 'subnet_id' => String + } + }, + RouteTableHandler => { + functions => { + 'create' => Callable[ + [Optional[RouteTable]], + Tuple[Optional[RouteTable], String]], + 'delete' => Callable[String], + 'read' => Callable[ + [String], + Optional[RouteTable]] + } + }, + SecurityGroup => { + attributes => { + 'description' => String, + 'group_name' => String, + 'vpc_id' => { + 'type' => String, + 'value' => '' + }, + 'group_id' => { + 'type' => String, + 'value' => '' + }, + 'ip_permissions' => { + 'type' => Array[IpPermission], + 'value' => [] + }, + 'ip_permissions_egress' => { + 'type' => Array[IpPermission], + 'value' => [] + }, + 'owner_id' => { + 'type' => String, + 'value' => '' + }, + 'tags' => { + 'type' => Optional[Hash[String, String]], + 'kind' => 'given_or_derived' + } + } + }, + SecurityGroupHandler => { + functions => { + 'create' => Callable[ + [Optional[SecurityGroup]], + Tuple[Optional[SecurityGroup], String]], + 'delete' => Callable[String], + 'read' => Callable[ + [String], + Optional[SecurityGroup]] + } + }, + StateReason => { + attributes => { + 'code' => { + 'type' => String, + 'value' => '' + }, + 'message' => { + 'type' => String, + 'value' => '' + } + } + }, + Subnet => { + annotations => { + Lyra::Resource => { + 'immutable_attributes' => ['tags'], + 'provided_attributes' => ['subnet_id', 'availability_zone', 'available_ip_address_count'] + } + }, + attributes => { + 'vpc_id' => String, + 'cidr_block' => String, + 'availability_zone' => { + 'type' => Optional[String], + 'value' => undef + }, + 'ipv6_cidr_block' => String, + 'tags' => Hash[String, String], + 'assign_ipv6_address_on_creation' => Boolean, + 'map_public_ip_on_launch' => Boolean, + 'available_ip_address_count' => { + 'type' => Optional[Integer], + 'value' => undef + }, + 'default_for_az' => Boolean, + 'state' => String, + 'subnet_id' => { + 'type' => Optional[String], + 'value' => undef + } + } + }, + SubnetHandler => { + functions => { + 'create' => Callable[ + [Optional[Subnet]], + Tuple[Optional[Subnet], String]], + 'delete' => Callable[String], + 'read' => Callable[ + [String], + Optional[Subnet]] + } + }, + UserIdGroupPair => { + attributes => { + 'description' => { + 'type' => String, + 'value' => '' + }, + 'group_id' => { + 'type' => String, + 'value' => '' + }, + 'group_name' => { + 'type' => String, + 'value' => '' + }, + 'peering_status' => { + 'type' => String, + 'value' => '' + }, + 'user_id' => { + 'type' => String, + 'value' => '' + }, + 'vpc_id' => { + 'type' => String, + 'value' => '' + }, + 'vpc_peering_connection_id' => { + 'type' => String, + 'value' => '' + } + } + }, + VPCHandler => { + functions => { + 'create' => Callable[ + [Optional[Vpc]], + Tuple[Optional[Vpc], String]], + 'delete' => Callable[String], + 'read' => Callable[ + [String], + Optional[Vpc]] + } + }, + Vpc => { + attributes => { + 'amazon_provided_ipv6_cidr_block' => Boolean, + 'cidr_block' => String, + 'instance_tenancy' => { + 'type' => Optional[String], + 'value' => 'default' + }, + 'enable_dns_hostnames' => Boolean, + 'enable_dns_support' => Boolean, + 'tags' => Hash[String, String], + 'vpc_id' => { + 'type' => Optional[String], + 'value' => undef + }, + 'is_default' => Boolean, + 'state' => String, + 'dhcp_options_id' => { + 'type' => Optional[String], + 'value' => undef + } + } + } + } + }] diff --git a/lang/typegen/typescript.go b/lang/typegen/typescript.go new file mode 100644 index 0000000..f2dd608 --- /dev/null +++ b/lang/typegen/typescript.go @@ -0,0 +1,387 @@ +package typegen + +import ( + "bytes" + "fmt" + "github.com/lyraproj/issue/issue" + "github.com/lyraproj/puppet-evaluator/eval" + "github.com/lyraproj/puppet-evaluator/types" + "github.com/lyraproj/puppet-evaluator/utils" + "github.com/lyraproj/servicesdk/lang" + "strings" +) + +type tsGenerator struct { + ctx eval.Context + excludes []string +} + +// NewTsGenerator creates and returns a lang.Generator that will generate TypeScript types +func NewTsGenerator(ctx eval.Context, excludes ...string) lang.Generator { + return &tsGenerator{ctx, excludes} +} + +// GenerateTypes produces TypeScript types for all types in the given TypeSet and appends them to +// the given buffer. +func (g *tsGenerator) GenerateTypes(ts eval.TypeSet, ns []string, indent int, bld *bytes.Buffer) { + rns := relativeNs(ns, ts.Name()) + for _, n := range rns { + newLine(indent, bld) + bld.WriteString(`export namespace `) + bld.WriteString(n) + bld.WriteString(` {`) + indent += 2 + ns = append(ns, n) + } + newLine(indent, bld) + leafName := nsName(ns, ts.Name()) + bld.WriteString(`export namespace `) + bld.WriteString(leafName) + bld.WriteString(` {`) + indent += 2 + ns = append(ns, leafName) + ts.Types().EachValue(func(t eval.Value) { g.GenerateType(t.(eval.Type), ns, indent, bld) }) + for i := len(rns); i > 0; i-- { + indent -= 2 + newLine(indent, bld) + bld.WriteByte('}') + } + indent -= 2 + newLine(indent, bld) + bld.WriteByte('}') + bld.WriteByte('\n') +} + +// GenerateType produces a TypeScript type for the given Type and appends it to +// the given buffer. +func (g *tsGenerator) GenerateType(t eval.Type, ns []string, indent int, bld *bytes.Buffer) { + if ts, ok := t.(eval.TypeSet); ok { + g.GenerateTypes(ts, ns, indent, bld) + return + } + + if pt, ok := t.(eval.ObjectType); ok { + bld.WriteByte('\n') + newLine(indent, bld) + bld.WriteString(`export class `) + bld.WriteString(nsName(ns, pt.Name())) + if ppt, ok := pt.Parent().(eval.ObjectType); ok { + bld.WriteString(` extends `) + bld.WriteString(nsName(ns, ppt.Name())) + } else { + bld.WriteString(` implements PcoreValue`) + } + bld.WriteString(` {`) + indent += 2 + ai := pt.AttributesInfo() + allAttrs, thisAttrs, superAttrs := g.toTsAttrs(pt, ns, ai.Attributes()) + appendFields(thisAttrs, indent, bld) + bld.WriteByte('\n') + if len(allAttrs) > 0 { + appendConstructor(allAttrs, thisAttrs, superAttrs, indent, bld) + bld.WriteByte('\n') + } + hasSuper := len(superAttrs) > 0 + if len(thisAttrs) > 0 || !hasSuper { + appendPValueGetter(hasSuper, thisAttrs, indent, bld) + bld.WriteByte('\n') + } + appendPTypeGetter(pt.Name(), indent, bld) + indent -= 2 + newLine(indent, bld) + bld.WriteByte('}') + } else { + appendTsType(ns, t, bld) + } +} + +// ToTsType converts the given pType to a string representation of a TypeScript type. The given +// pType can not be a TypeSet. +func (g *tsGenerator) ToTsType(ns []string, pType eval.Type) string { + bld := bytes.NewBufferString(``) + appendTsType(ns, pType, bld) + return bld.String() +} + +type tsAttribute struct { + name string + typ string + value string +} + +func (g *tsGenerator) toTsAttrs(t eval.ObjectType, ns []string, attrs []eval.Attribute) (allAttrs, thisAttrs, superAttrs []*tsAttribute) { + allAttrs = make([]*tsAttribute, len(attrs)) + superAttrs = make([]*tsAttribute, 0) + thisAttrs = make([]*tsAttribute, 0) + for i, attr := range attrs { + tsAttr := &tsAttribute{name: issue.CamelToSnakeCase(attr.Name()), typ: g.ToTsType(ns, attr.Type())} + if attr.HasValue() { + tsAttr.value = toTsValue(attr.Value()) + } + if attr.Container() == t { + thisAttrs = append(thisAttrs, tsAttr) + } else { + superAttrs = append(superAttrs, tsAttr) + } + allAttrs[i] = tsAttr + } + return +} + +func appendFields(thisAttrs []*tsAttribute, indent int, bld *bytes.Buffer) { + for _, attr := range thisAttrs { + newLine(indent, bld) + bld.WriteString(`readonly `) + bld.WriteString(attr.name) + bld.WriteString(`: `) + bld.WriteString(attr.typ) + bld.WriteString(`;`) + } + return +} + +func appendConstructor(allAttrs, thisAttrs, superAttrs []*tsAttribute, indent int, bld *bytes.Buffer) { + newLine(indent, bld) + bld.WriteString(`constructor(`) + appendParameters(allAttrs, indent, bld) + bld.WriteString(`) {`) + indent += 2 + if len(superAttrs) > 0 { + newLine(indent, bld) + bld.WriteString(`super({`) + for i, attr := range superAttrs { + if i > 0 { + bld.WriteString(`, `) + } + bld.WriteString(attr.name) + bld.WriteString(`: `) + bld.WriteString(attr.name) + } + bld.WriteString(`});`) + } + for _, attr := range thisAttrs { + newLine(indent, bld) + bld.WriteString(`this.`) + bld.WriteString(attr.name) + bld.WriteString(` = `) + bld.WriteString(attr.name) + bld.WriteByte(';') + } + indent -= 2 + newLine(indent, bld) + bld.WriteByte('}') +} + +func appendPValueGetter(hasSuper bool, thisAttrs []*tsAttribute, indent int, bld *bytes.Buffer) { + newLine(indent, bld) + bld.WriteString(`__pvalue() : {[s: string]: any} {`) + indent += 2 + newLine(indent, bld) + if len(thisAttrs) == 0 { + if hasSuper { + bld.WriteString(`return super.__pvalue();`) + } else { + bld.WriteString(`return {};`) + } + } else { + if hasSuper { + bld.WriteString(`let ih = super.__pvalue();`) + } else { + bld.WriteString(`let ih: {[s: string]: any} = {};`) + } + for _, attr := range thisAttrs { + newLine(indent, bld) + if attr.value != `` { + bld.WriteString(`if(this.`) + bld.WriteString(attr.name) + bld.WriteString(` !== `) + bld.WriteString(attr.value) + bld.WriteString(`)`) + indent += 2 + newLine(indent, bld) + } + bld.WriteString(`ih['`) + bld.WriteString(attr.name) + bld.WriteString(`'] = this.`) + bld.WriteString(attr.name) + bld.WriteString(`;`) + if attr.value != `` { + indent -= 2 + } + } + newLine(indent, bld) + bld.WriteString(`return ih;`) + } + indent -= 2 + newLine(indent, bld) + bld.WriteByte('}') +} + +func appendPTypeGetter(name string, indent int, bld *bytes.Buffer) { + newLine(indent, bld) + bld.WriteString(`__ptype() : string {`) + indent += 2 + newLine(indent, bld) + bld.WriteString(`return '`) + bld.WriteString(name) + bld.WriteString(`';`) + indent -= 2 + newLine(indent, bld) + bld.WriteByte('}') +} + +func appendParameters(params []*tsAttribute, indent int, bld *bytes.Buffer) { + indent += 2 + bld.WriteString(`{`) + indent += 2 + for _, attr := range params { + newLine(indent, bld) + bld.WriteString(attr.name) + if attr.value != `` { + bld.WriteString(` = `) + bld.WriteString(attr.value) + } + bld.WriteString(`,`) + } + bld.Truncate(bld.Len() - 1) // Truncate last comma + indent -= 2 + newLine(indent, bld) + bld.WriteString(`}: {`) + indent += 2 + + for _, attr := range params { + newLine(indent, bld) + bld.WriteString(attr.name) + if attr.value != `` { + bld.WriteByte('?') + } + bld.WriteString(`: `) + bld.WriteString(attr.typ) + bld.WriteByte(',') + } + + bld.Truncate(bld.Len() - 1) // Truncate last comma + indent -= 2 + newLine(indent, bld) + bld.WriteString(`}`) +} + +func toTsValue(value eval.Value) string { + bld := bytes.NewBufferString(``) + appendTsValue(value, bld) + return bld.String() +} + +func appendTsValue(value eval.Value, bld *bytes.Buffer) { + switch value.(type) { + case *types.UndefValue: + bld.WriteString(`null`) + case eval.StringValue: + utils.PuppetQuote(bld, value.String()) + case eval.BooleanValue, eval.IntegerValue, eval.FloatValue: + bld.WriteString(value.String()) + case *types.ArrayValue: + bld.WriteByte('[') + value.(*types.ArrayValue).EachWithIndex(func(e eval.Value, i int) { + if i > 0 { + bld.WriteString(`, `) + } + appendTsValue(e, bld) + }) + bld.WriteByte(']') + case *types.HashValue: + bld.WriteByte('{') + value.(*types.HashValue).EachWithIndex(func(e eval.Value, i int) { + ev := e.(*types.HashEntry) + if i > 0 { + bld.WriteString(`, `) + } + utils.PuppetQuote(bld, ev.Key().String()) + bld.WriteString(`: `) + appendTsValue(ev.Value(), bld) + }) + bld.WriteByte('}') + } +} + +func appendTsType(ns []string, pType eval.Type, bld *bytes.Buffer) { + switch pType.(type) { + case *types.BooleanType: + bld.WriteString(`boolean`) + case *types.IntegerType, *types.FloatType: + bld.WriteString(`number`) + case eval.StringType: + bld.WriteString(`string`) + case *types.OptionalType: + appendTsType(ns, pType.(*types.OptionalType).ContainedType(), bld) + bld.WriteString(` | null`) + case *types.ArrayType: + bld.WriteString(`Array<`) + appendTsType(ns, pType.(*types.ArrayType).ElementType(), bld) + bld.WriteString(`>`) + case *types.VariantType: + for i, v := range pType.(*types.VariantType).Types() { + if i > 0 { + bld.WriteString(` | `) + } + appendTsType(ns, v, bld) + } + case *types.HashType: + ht := pType.(*types.HashType) + bld.WriteString(`{[s: `) + appendTsType(ns, ht.KeyType(), bld) + bld.WriteString(`]: `) + appendTsType(ns, ht.ValueType(), bld) + bld.WriteString(`}`) + case *types.EnumType: + for i, s := range pType.(*types.EnumType).Parameters() { + if i > 0 { + bld.WriteString(` | `) + } + appendTsValue(s, bld) + } + case *types.TypeAliasType: + bld.WriteString(nsName(ns, pType.(*types.TypeAliasType).Name())) + case eval.ObjectType: + bld.WriteString(nsName(ns, pType.(eval.ObjectType).Name())) + } +} + +func newLine(indent int, bld *bytes.Buffer) { + bld.WriteByte('\n') + for n := 0; n < indent; n++ { + bld.WriteByte(' ') + } +} + +func relativeNs(ns []string, name string) []string { + parts := strings.Split(name, `::`) + if len(parts) == 1 { + return []string{} + } + if len(ns) == 0 || isParent(ns, parts) { + return parts[len(ns) : len(parts)-1] + } + panic(fmt.Errorf("cannot generate %s in namespace %s", name, ns)) +} + +func nsName(ns []string, name string) string { + parts := strings.Split(name, `::`) + if isParent(ns, parts) { + return strings.Join(parts[len(ns):], `.`) + } + return strings.Join(parts, `.`) +} + +func isParent(ns, n []string) bool { + top := len(ns) + if top < len(n) { + for idx := 0; idx < top; idx++ { + if n[idx] != ns[idx] { + return false + } + } + return true + } + return false +} diff --git a/lang/typegen/typescript_test.go b/lang/typegen/typescript_test.go new file mode 100644 index 0000000..3755e11 --- /dev/null +++ b/lang/typegen/typescript_test.go @@ -0,0 +1,179 @@ +package typegen + +import ( + "bytes" + "github.com/lyraproj/puppet-evaluator/eval" + "github.com/lyraproj/semver/semver" + "io/ioutil" + "reflect" + "testing" + + // Initialize pcore + "fmt" + _ "github.com/lyraproj/puppet-evaluator/pcore" + _ "github.com/lyraproj/servicesdk/annotation" +) + +func TestGetAllNestedTypes(t *testing.T) { + eval.Puppet.Do(func(c eval.Context) { + typesFile := "testdata/aws.pp" + content, err := ioutil.ReadFile(typesFile) + if err != nil { + panic(err.Error()) + } + ast := c.ParseAndValidate(typesFile, string(content), false) + c.AddDefinitions(ast) + _, err = eval.TopEvaluate(c, ast) + if err != nil { + panic(err.Error()) + } + + var l interface{} + var ts eval.TypeSet + var ok bool + + if l, ok = eval.Load(c, eval.NewTypedName(eval.NsType, `Aws`)); ok { + ts, ok = l.(eval.TypeSet) + } + if !ok { + panic("Failed to load Aws TypeSet") + } + + bld := bytes.NewBufferString(``) + g := NewTsGenerator(c) + g.GenerateTypes(ts, []string{}, 0, bld) + fmt.Println(bld.String()) + }) +} + +func ExampleGenerator_GenerateTypes() { + type Address struct { + Street string + Zip string `puppet:"name=>zip_code"` + } + type Person struct { + Name string + Gender string `puppet:"type=>Enum[male,female,other]"` + Address *Address + } + type ExtendedPerson struct { + Person + Age *int `puppet:"type=>Optional[Integer],value=>undef"` + Active bool `puppet:"name=>enabled"` + } + + c := eval.Puppet.RootContext() + + // Create a TypeSet from a list of Go structs + typeSet := c.Reflector().TypeSetFromReflect(`My::Own`, semver.MustParseVersion(`1.0.0`), nil, + reflect.TypeOf(&Address{}), reflect.TypeOf(&Person{}), reflect.TypeOf(&ExtendedPerson{})) + + // Make the types known to the current loader + c.AddTypes(typeSet) + + bld := bytes.NewBufferString(``) + g := NewTsGenerator(c) + g.GenerateTypes(typeSet, []string{}, 0, bld) + fmt.Println(bld.String()) + + // Output: + // export namespace My { + // export namespace Own { + // + // export class Address implements PcoreValue { + // readonly street: string; + // readonly zip_code: string; + // + // constructor({ + // street, + // zip_code + // }: { + // street: string, + // zip_code: string + // }) { + // this.street = street; + // this.zip_code = zip_code; + // } + // + // __pvalue() : {[s: string]: any} { + // let ih: {[s: string]: any} = {}; + // ih['street'] = this.street; + // ih['zip_code'] = this.zip_code; + // return ih; + // } + // + // __ptype() : string { + // return 'My::Own::Address'; + // } + // } + // + // export class Person implements PcoreValue { + // readonly name: string; + // readonly gender: 'male' | 'female' | 'other'; + // readonly address: Address | null; + // + // constructor({ + // name, + // gender, + // address = null + // }: { + // name: string, + // gender: 'male' | 'female' | 'other', + // address?: Address | null + // }) { + // this.name = name; + // this.gender = gender; + // this.address = address; + // } + // + // __pvalue() : {[s: string]: any} { + // let ih: {[s: string]: any} = {}; + // ih['name'] = this.name; + // ih['gender'] = this.gender; + // if(this.address !== null) + // ih['address'] = this.address; + // return ih; + // } + // + // __ptype() : string { + // return 'My::Own::Person'; + // } + // } + // + // export class ExtendedPerson extends Person { + // readonly enabled: boolean; + // readonly age: number | null; + // + // constructor({ + // name, + // gender, + // enabled, + // address = null, + // age = null + // }: { + // name: string, + // gender: 'male' | 'female' | 'other', + // enabled: boolean, + // address?: Address | null, + // age?: number | null + // }) { + // super({name: name, gender: gender, address: address}); + // this.enabled = enabled; + // this.age = age; + // } + // + // __pvalue() : {[s: string]: any} { + // let ih = super.__pvalue(); + // ih['enabled'] = this.enabled; + // if(this.age !== null) + // ih['age'] = this.age; + // return ih; + // } + // + // __ptype() : string { + // return 'My::Own::ExtendedPerson'; + // } + // } + // } + // } +}