From 1c01047ad274a393b4d52e4970c906048617bc6f Mon Sep 17 00:00:00 2001
From: Andrzej Ressel <github@andrzejressel.pl>
Date: Sun, 15 Dec 2024 16:23:02 +0100
Subject: [PATCH] Enum

---
 examples/typesystem/src/lib.rs                |  37 ++++--
 .../src/types/builder_version.rs              |  11 ++
 .../src/types/cache_from.rs                   |   2 +
 .../src/types/docker_build.rs                 |   2 +
 .../src/types/mod.rs                          |   3 +-
 .../src/types/registry.rs                     |   2 +
 .../src/resource/typesystem_server.rs         |   6 +-
 .../src/types/mod.rs                          |  10 +-
 .../src/types/my_enum.rs                      |   6 +
 .../types/{enum_case_1.rs => union_case_1.rs} |   2 +-
 .../types/{enum_case_2.rs => union_case_2.rs} |   2 +-
 providers/typesystem.json                     |  28 ++--
 .../src/code_generation/yaml/model.rs         |   3 +-
 pulumi_wasm_generator_lib/src/model.rs        |  10 +-
 .../src/output/rust/source_code_types_code.rs |  98 ++++++++++----
 .../src/output/rust/source_code_types_mod.rs  |   8 +-
 .../src/output/rust/types_code.rs.handlebars  |   4 +
 .../output/rust/types_code_enum.rs.handlebars |  16 +++
 pulumi_wasm_generator_lib/src/schema.rs       | 120 +++++++++++-------
 .../lib/src/types/ignore_tags.rs              |   2 +
 .../mini-awsnative/lib/src/types/mod.rs       |   3 +-
 .../mini-awsnative/lib/src/types/region.rs    |  80 ++++++++++++
 pulumi_wasm_generator_lib/tests/test.rs       |   4 +-
 23 files changed, 357 insertions(+), 102 deletions(-)
 create mode 100644 providers/pulumi_wasm_provider_docker_rust/src/types/builder_version.rs
 create mode 100644 providers/pulumi_wasm_provider_typesystem_rust/src/types/my_enum.rs
 rename providers/pulumi_wasm_provider_typesystem_rust/src/types/{enum_case_1.rs => union_case_1.rs} (89%)
 rename providers/pulumi_wasm_provider_typesystem_rust/src/types/{enum_case_2.rs => union_case_2.rs} (89%)
 create mode 100644 pulumi_wasm_generator_lib/src/output/rust/types_code_enum.rs.handlebars
 create mode 100644 pulumi_wasm_generator_lib/tests/output/mini-awsnative/lib/src/types/region.rs

diff --git a/examples/typesystem/src/lib.rs b/examples/typesystem/src/lib.rs
index 28c752ca4..6bc262088 100644
--- a/examples/typesystem/src/lib.rs
+++ b/examples/typesystem/src/lib.rs
@@ -3,7 +3,7 @@ mod tests {
     use pulumi_wasm_provider_common::OneOf2;
     use pulumi_wasm_rust::Output;
     use pulumi_wasm_typesystem::typesystem_server::TypesystemServerArgs;
-    use pulumi_wasm_typesystem::{EnumCase1, EnumCase2};
+    use pulumi_wasm_typesystem::{MyEnum, UnionCase1, UnionCase2};
     use std::panic::catch_unwind;
 
     #[test]
@@ -12,11 +12,11 @@ mod tests {
     }
 
     #[test]
-    fn test_deserialization() {
-        let case1 = EnumCase1::builder()
+    fn test_case_deserialization() {
+        let case1 = UnionCase1::builder()
             .field_1("value1".to_string())
             .build_struct();
-        let case2 = EnumCase2::builder()
+        let case2 = UnionCase2::builder()
             .field_2("value2".to_string())
             .build_struct();
 
@@ -25,13 +25,28 @@ mod tests {
         assert_eq!(case1_json, r#"{"field1":"value1"}"#);
         assert_eq!(case2_json, r#"{"field2":"value2"}"#);
 
-        let deserialized_case1: EnumCase1 = serde_json::from_str(&case1_json).unwrap();
+        let deserialized_case1: UnionCase1 = serde_json::from_str(&case1_json).unwrap();
+        let deserialized_case2: UnionCase2 = serde_json::from_str(&case2_json).unwrap();
         assert_eq!(deserialized_case1, case1);
-
-        let deserialized_case2: EnumCase2 = serde_json::from_str(&case2_json).unwrap();
         assert_eq!(deserialized_case2, case2);
     }
 
+    #[test]
+    fn test_enum_deserialization() {
+        let enum1 = MyEnum::Value1;
+        let enum2 = MyEnum::Value2;
+
+        let enum1_json = serde_json::to_string(&enum1).unwrap();
+        let enum2_json = serde_json::to_string(&enum2).unwrap();
+        assert_eq!(enum1_json, r#""VALUE1""#);
+        assert_eq!(enum2_json, r#""Value2""#);
+
+        let deserialized_enum1: MyEnum = serde_json::from_str(&enum1_json).unwrap();
+        let deserialized_enum2: MyEnum = serde_json::from_str(&enum2_json).unwrap();
+        assert_eq!(deserialized_enum1, enum1);
+        assert_eq!(deserialized_enum2, enum2);
+    }
+
     fn compilation_test() {
         // String
         let output = Output::new(&"Hello, World!".to_string());
@@ -67,10 +82,10 @@ mod tests {
         // let _ = TypesystemServerArgs::builder().optional_string_array([string_output]);
 
         // Union
-        let case1 = EnumCase1::builder()
+        let case1 = UnionCase1::builder()
             .field_1("value1".to_string())
             .build_struct();
-        let case2 = EnumCase2::builder()
+        let case2 = UnionCase2::builder()
             .field_2("value2".to_string())
             .build_struct();
         let enum_case1_output = Output::new(&case1);
@@ -81,10 +96,10 @@ mod tests {
         let _ =
             TypesystemServerArgs::builder().required_union(enum_case2_output.map(OneOf2::right));
 
-        let case1 = EnumCase1::builder()
+        let case1 = UnionCase1::builder()
             .field_1("value1".to_string())
             .build_struct();
-        let case2 = EnumCase2::builder()
+        let case2 = UnionCase2::builder()
             .field_2("value2".to_string())
             .build_struct();
         let _ = TypesystemServerArgs::builder().optional_union(OneOf2::left(case1));
diff --git a/providers/pulumi_wasm_provider_docker_rust/src/types/builder_version.rs b/providers/pulumi_wasm_provider_docker_rust/src/types/builder_version.rs
new file mode 100644
index 000000000..4f33d1191
--- /dev/null
+++ b/providers/pulumi_wasm_provider_docker_rust/src/types/builder_version.rs
@@ -0,0 +1,11 @@
+//! The version of the Docker builder.
+
+#[derive(serde::Deserialize, serde::Serialize, Debug, PartialEq, Clone)]
+pub enum BuilderVersion {
+    /// The first generation builder for Docker Daemon
+    #[serde(rename = "BuilderV1")]
+    BuilderV1,
+    /// The builder based on moby/buildkit project
+    #[serde(rename = "BuilderBuildKit")]
+    BuilderBuildKit,
+}
diff --git a/providers/pulumi_wasm_provider_docker_rust/src/types/cache_from.rs b/providers/pulumi_wasm_provider_docker_rust/src/types/cache_from.rs
index 1651bc7d7..9c4ceccfc 100644
--- a/providers/pulumi_wasm_provider_docker_rust/src/types/cache_from.rs
+++ b/providers/pulumi_wasm_provider_docker_rust/src/types/cache_from.rs
@@ -1,3 +1,5 @@
+//! Contains a list of images to reference when building using a cache
+
 #[derive(serde::Deserialize, serde::Serialize, bon::Builder, Debug, PartialEq, Clone)]
 #[builder(finish_fn = build_struct)]
 pub struct CacheFrom {
diff --git a/providers/pulumi_wasm_provider_docker_rust/src/types/docker_build.rs b/providers/pulumi_wasm_provider_docker_rust/src/types/docker_build.rs
index 100325201..3eee7b44e 100644
--- a/providers/pulumi_wasm_provider_docker_rust/src/types/docker_build.rs
+++ b/providers/pulumi_wasm_provider_docker_rust/src/types/docker_build.rs
@@ -1,3 +1,5 @@
+//! The Docker build context
+
 #[derive(serde::Deserialize, serde::Serialize, bon::Builder, Debug, PartialEq, Clone)]
 #[builder(finish_fn = build_struct)]
 pub struct DockerBuild {
diff --git a/providers/pulumi_wasm_provider_docker_rust/src/types/mod.rs b/providers/pulumi_wasm_provider_docker_rust/src/types/mod.rs
index 3d8bdcb49..de0341fb6 100644
--- a/providers/pulumi_wasm_provider_docker_rust/src/types/mod.rs
+++ b/providers/pulumi_wasm_provider_docker_rust/src/types/mod.rs
@@ -1,3 +1,5 @@
+mod builder_version;
+pub use builder_version::*;
 mod cache_from;
 pub use cache_from::*;
 mod container_capabilities;
@@ -127,4 +129,3 @@ pub use get_network_ipam_config::*;
 mod registry_auth;
 pub use registry_auth::*;
 
-pub type BuilderVersion = String;
diff --git a/providers/pulumi_wasm_provider_docker_rust/src/types/registry.rs b/providers/pulumi_wasm_provider_docker_rust/src/types/registry.rs
index c53b46b29..447e5014c 100644
--- a/providers/pulumi_wasm_provider_docker_rust/src/types/registry.rs
+++ b/providers/pulumi_wasm_provider_docker_rust/src/types/registry.rs
@@ -1,3 +1,5 @@
+//! Describes a Docker container registry
+
 #[derive(serde::Deserialize, serde::Serialize, bon::Builder, Debug, PartialEq, Clone)]
 #[builder(finish_fn = build_struct)]
 pub struct Registry {
diff --git a/providers/pulumi_wasm_provider_typesystem_rust/src/resource/typesystem_server.rs b/providers/pulumi_wasm_provider_typesystem_rust/src/resource/typesystem_server.rs
index 7b2ae0037..5ceb1065d 100644
--- a/providers/pulumi_wasm_provider_typesystem_rust/src/resource/typesystem_server.rs
+++ b/providers/pulumi_wasm_provider_typesystem_rust/src/resource/typesystem_server.rs
@@ -7,15 +7,15 @@ pub struct TypesystemServerArgs {
     #[builder(into, default = ::pulumi_wasm_rust::Output::empty())]
     pub optional_string_input: pulumi_wasm_rust::Output<Option<String>>,
     #[builder(into, default = ::pulumi_wasm_rust::Output::empty())]
-    pub optional_union: pulumi_wasm_rust::Output<Option<pulumi_wasm_provider_common::OneOf2<crate::types::EnumCase1, crate::types::EnumCase2>>>,
+    pub optional_union: pulumi_wasm_rust::Output<Option<pulumi_wasm_provider_common::OneOf2<crate::types::UnionCase1, crate::types::UnionCase2>>>,
     #[builder(into, default = ::pulumi_wasm_rust::Output::empty())]
-    pub properties_collection: pulumi_wasm_rust::Output<Option<Vec<pulumi_wasm_provider_common::OneOf2<crate::types::EnumCase1, crate::types::EnumCase2>>>>,
+    pub properties_collection: pulumi_wasm_rust::Output<Option<Vec<pulumi_wasm_provider_common::OneOf2<crate::types::UnionCase1, crate::types::UnionCase2>>>>,
     #[builder(into)]
     pub required_string_array: pulumi_wasm_rust::Output<Vec<String>>,
     #[builder(into)]
     pub required_string_input: pulumi_wasm_rust::Output<String>,
     #[builder(into)]
-    pub required_union: pulumi_wasm_rust::Output<pulumi_wasm_provider_common::OneOf2<crate::types::EnumCase1, crate::types::EnumCase2>>,
+    pub required_union: pulumi_wasm_rust::Output<pulumi_wasm_provider_common::OneOf2<crate::types::UnionCase1, crate::types::UnionCase2>>,
 }
 
 pub struct TypesystemServerResult {
diff --git a/providers/pulumi_wasm_provider_typesystem_rust/src/types/mod.rs b/providers/pulumi_wasm_provider_typesystem_rust/src/types/mod.rs
index cce8fed51..265512f4c 100644
--- a/providers/pulumi_wasm_provider_typesystem_rust/src/types/mod.rs
+++ b/providers/pulumi_wasm_provider_typesystem_rust/src/types/mod.rs
@@ -1,5 +1,7 @@
-mod enum_case_1;
-pub use enum_case_1::*;
-mod enum_case_2;
-pub use enum_case_2::*;
+mod my_enum;
+pub use my_enum::*;
+mod union_case_1;
+pub use union_case_1::*;
+mod union_case_2;
+pub use union_case_2::*;
 
diff --git a/providers/pulumi_wasm_provider_typesystem_rust/src/types/my_enum.rs b/providers/pulumi_wasm_provider_typesystem_rust/src/types/my_enum.rs
new file mode 100644
index 000000000..bb11851f4
--- /dev/null
+++ b/providers/pulumi_wasm_provider_typesystem_rust/src/types/my_enum.rs
@@ -0,0 +1,6 @@
+#[derive(serde::Deserialize, serde::Serialize, Debug, PartialEq, Clone)]
+pub enum MyEnum {
+    #[serde(rename = "VALUE1")]
+    Value1,
+    Value2,
+}
diff --git a/providers/pulumi_wasm_provider_typesystem_rust/src/types/enum_case_1.rs b/providers/pulumi_wasm_provider_typesystem_rust/src/types/union_case_1.rs
similarity index 89%
rename from providers/pulumi_wasm_provider_typesystem_rust/src/types/enum_case_1.rs
rename to providers/pulumi_wasm_provider_typesystem_rust/src/types/union_case_1.rs
index 72513d167..6577f484d 100644
--- a/providers/pulumi_wasm_provider_typesystem_rust/src/types/enum_case_1.rs
+++ b/providers/pulumi_wasm_provider_typesystem_rust/src/types/union_case_1.rs
@@ -1,6 +1,6 @@
 #[derive(serde::Deserialize, serde::Serialize, bon::Builder, Debug, PartialEq, Clone)]
 #[builder(finish_fn = build_struct)]
-pub struct EnumCase1 {
+pub struct UnionCase1 {
     #[builder(into)]
     #[serde(rename = "field1")]
     pub r#field_1: Box<String>,
diff --git a/providers/pulumi_wasm_provider_typesystem_rust/src/types/enum_case_2.rs b/providers/pulumi_wasm_provider_typesystem_rust/src/types/union_case_2.rs
similarity index 89%
rename from providers/pulumi_wasm_provider_typesystem_rust/src/types/enum_case_2.rs
rename to providers/pulumi_wasm_provider_typesystem_rust/src/types/union_case_2.rs
index e58d2fe78..b24e8a1b0 100644
--- a/providers/pulumi_wasm_provider_typesystem_rust/src/types/enum_case_2.rs
+++ b/providers/pulumi_wasm_provider_typesystem_rust/src/types/union_case_2.rs
@@ -1,6 +1,6 @@
 #[derive(serde::Deserialize, serde::Serialize, bon::Builder, Debug, PartialEq, Clone)]
 #[builder(finish_fn = build_struct)]
-pub struct EnumCase2 {
+pub struct UnionCase2 {
     #[builder(into)]
     #[serde(rename = "field2")]
     pub r#field_2: Box<String>,
diff --git a/providers/typesystem.json b/providers/typesystem.json
index 62798835d..0a53c859d 100644
--- a/providers/typesystem.json
+++ b/providers/typesystem.json
@@ -26,11 +26,11 @@
           "oneOf": [
             {
               "type": "object",
-              "$ref": "#/types/typesystem:index:EnumCase1"
+              "$ref": "#/types/typesystem:index:UnionCase1"
             },
             {
               "type": "object",
-              "$ref": "#/types/typesystem:index:EnumCase2"
+              "$ref": "#/types/typesystem:index:UnionCase2"
             }
           ]
         },
@@ -38,11 +38,11 @@
           "oneOf": [
             {
               "type": "object",
-              "$ref": "#/types/typesystem:index:EnumCase1"
+              "$ref": "#/types/typesystem:index:UnionCase1"
             },
             {
               "type": "object",
-              "$ref": "#/types/typesystem:index:EnumCase2"
+              "$ref": "#/types/typesystem:index:UnionCase2"
             }
           ]
         },
@@ -52,11 +52,11 @@
             "oneOf": [
               {
                 "type": "object",
-                "$ref": "#/types/typesystem:index:EnumCase1"
+                "$ref": "#/types/typesystem:index:UnionCase1"
               },
               {
                 "type": "object",
-                "$ref": "#/types/typesystem:index:EnumCase2"
+                "$ref": "#/types/typesystem:index:UnionCase2"
               }
             ]
           }
@@ -71,7 +71,7 @@
     }
   },
   "types": {
-    "typesystem:index:EnumCase1": {
+    "typesystem:index:UnionCase1": {
       "type": "object",
       "properties": {
         "field1": {
@@ -82,7 +82,7 @@
         "field1"
       ]
     },
-    "typesystem:index:EnumCase2": {
+    "typesystem:index:UnionCase2": {
       "type": "object",
       "properties": {
         "field2": {
@@ -92,6 +92,18 @@
       "required": [
         "field2"
       ]
+    },
+    "typesystem:index:MyEnum": {
+      "type": "string",
+      "enum": [
+        {
+          "name": "Value1",
+          "value": "VALUE1"
+        },
+        {
+          "name": "Value2"
+        }
+      ]
     }
   },
   "language": {
diff --git a/pulumi_wasm_generator_lib/src/code_generation/yaml/model.rs b/pulumi_wasm_generator_lib/src/code_generation/yaml/model.rs
index 7f670d5ad..4ed3c1478 100644
--- a/pulumi_wasm_generator_lib/src/code_generation/yaml/model.rs
+++ b/pulumi_wasm_generator_lib/src/code_generation/yaml/model.rs
@@ -251,7 +251,8 @@ fn map_type(
     let tpe = &context.package.types[element_id];
 
     let gtp = match tpe {
-        GlobalType::Object(gtp) => gtp,
+        GlobalType::Object(_, gtp) => gtp,
+        GlobalType::StringEnum(_, _) => panic!("StringEnum type is not supported"),
         GlobalType::String => panic!("String type is not supported"),
         GlobalType::Boolean => panic!("Boolean type is not supported"),
         GlobalType::Number => panic!("Number type is not supported"),
diff --git a/pulumi_wasm_generator_lib/src/model.rs b/pulumi_wasm_generator_lib/src/model.rs
index dac81da9d..977980f32 100644
--- a/pulumi_wasm_generator_lib/src/model.rs
+++ b/pulumi_wasm_generator_lib/src/model.rs
@@ -108,13 +108,21 @@ pub(crate) struct GlobalTypeProperty {
 
 #[derive(Debug, PartialEq, Hash, Ord, PartialOrd, Eq)]
 pub(crate) enum GlobalType {
-    Object(Vec<GlobalTypeProperty>),
+    Object(Option<String>, Vec<GlobalTypeProperty>),
+    StringEnum(Option<String>, Vec<StringEnumElement>),
     String,
     Boolean,
     Number,
     Integer,
 }
 
+#[derive(Debug, PartialEq, Hash, Ord, PartialOrd, Eq)]
+pub(crate) struct StringEnumElement {
+    pub(crate) name: String,
+    pub(crate) value: Option<String>,
+    pub(crate) description: Option<String>,
+}
+
 #[derive(Debug, PartialEq, Hash, Ord, PartialOrd, Eq)]
 pub(crate) struct Resource {
     pub(crate) element_id: ElementId,
diff --git a/pulumi_wasm_generator_lib/src/output/rust/source_code_types_code.rs b/pulumi_wasm_generator_lib/src/output/rust/source_code_types_code.rs
index f3767d514..044b58855 100644
--- a/pulumi_wasm_generator_lib/src/output/rust/source_code_types_code.rs
+++ b/pulumi_wasm_generator_lib/src/output/rust/source_code_types_code.rs
@@ -7,6 +7,7 @@ use std::collections::HashMap;
 use std::path::PathBuf;
 
 static TEMPLATE: &str = include_str!("types_code.rs.handlebars");
+static ENUM_TEMPLATE: &str = include_str!("types_code_enum.rs.handlebars");
 
 #[derive(Serialize)]
 struct Property {
@@ -21,10 +22,26 @@ struct Property {
 struct RefType {
     // name: String,
     fields: Vec<Property>,
+    description_lines: Vec<String>,
     struct_name: String,
     file_name: String,
 }
 
+#[derive(Serialize)]
+struct Enum {
+    struct_name: String,
+    file_name: String,
+    description_lines: Vec<String>,
+    values: Vec<EnumValue>,
+}
+
+#[derive(Serialize)]
+struct EnumValue {
+    name: String,
+    description_lines: Vec<String>,
+    value: Option<String>,
+}
+
 #[derive(Serialize)]
 struct AliasType {
     name: String,
@@ -35,21 +52,22 @@ struct AliasType {
 struct Package {
     name: String,
     types: Vec<RefType>,
-    aliases: Vec<AliasType>,
+    enums: Vec<Enum>,
 }
 
 fn convert_model(package: &crate::model::Package) -> Package {
     let mut real_types = Vec::new();
-    let mut aliases = Vec::new();
+    let mut enums = Vec::new();
 
     package
         .types
         .iter()
         .for_each(|(element_id, resource)| match resource {
-            GlobalType::Object(properties) => {
+            GlobalType::Object(description, properties) => {
                 let ref_type = RefType {
                     struct_name: element_id.get_rust_struct_name(),
                     file_name: element_id.get_rust_struct_name().to_case(Case::Snake),
+                    description_lines: crate::utils::to_lines(description.clone(), package, None),
                     fields: properties
                         .iter()
                         .map(|global_type_property| Property {
@@ -71,28 +89,36 @@ fn convert_model(package: &crate::model::Package) -> Package {
                 };
                 real_types.push(ref_type);
             }
-            GlobalType::String => aliases.push(AliasType {
-                name: element_id.name.to_string(),
-                type_: "String".to_string(),
-            }),
-            GlobalType::Boolean => aliases.push(AliasType {
-                name: element_id.name.to_string(),
-                type_: "bool".to_string(),
-            }),
-            GlobalType::Number => aliases.push(AliasType {
-                name: element_id.name.to_string(),
-                type_: "f64".to_string(),
-            }),
-            GlobalType::Integer => aliases.push(AliasType {
-                name: element_id.name.to_string(),
-                type_: "i32".to_string(),
-            }),
+            GlobalType::StringEnum(description, enum_values) => {
+                let enum_type = Enum {
+                    struct_name: element_id.get_rust_struct_name(),
+                    file_name: element_id.get_rust_struct_name().to_case(Case::Snake),
+                    description_lines: crate::utils::to_lines(description.clone(), package, None),
+                    values: enum_values
+                        .iter()
+                        .map(|enum_value| EnumValue {
+                            name: enum_value.name.clone(),
+                            value: enum_value.value.clone(),
+                            description_lines: crate::utils::to_lines(
+                                enum_value.description.clone(),
+                                package,
+                                None,
+                            ),
+                        })
+                        .collect(),
+                };
+                enums.push(enum_type);
+            }
+            GlobalType::String => {}
+            GlobalType::Boolean => {}
+            GlobalType::Number => {}
+            GlobalType::Integer => {}
         });
 
     Package {
         name: package.name.clone(),
         types: real_types,
-        aliases,
+        enums,
     }
 }
 
@@ -100,17 +126,43 @@ pub(crate) fn generate_source_code(package: &crate::model::Package) -> HashMap<P
     let handlebars = Handlebars::new();
     let package = convert_model(package);
 
-    package
+    let types: HashMap<_, _> = package
         .types
         .iter()
         .map(|type_| {
             let rendered_file = handlebars
                 .render_template(TEMPLATE, &json!({"type": type_}))
-                .unwrap();
+                .unwrap()
+                .trim_start()
+                .to_string(); //FIXME
             (
                 PathBuf::from(format!("{}.rs", type_.file_name)),
                 rendered_file,
             )
         })
-        .collect()
+        .collect();
+
+    let enums: HashMap<_, _> = package
+        .enums
+        .iter()
+        .map(|enum_| {
+            let rendered_file = handlebars
+                .render_template(ENUM_TEMPLATE, &json!({"enum": enum_}))
+                .unwrap()
+                .trim_start()
+                .to_string(); //FIXME
+            (
+                PathBuf::from(format!("{}.rs", enum_.file_name)),
+                rendered_file,
+            )
+        })
+        .collect();
+
+    let mut result = HashMap::new();
+    result.extend(types);
+    result.extend(enums);
+
+    result
+
+    // let enums =
 }
diff --git a/pulumi_wasm_generator_lib/src/output/rust/source_code_types_mod.rs b/pulumi_wasm_generator_lib/src/output/rust/source_code_types_mod.rs
index 6638a31d6..0f8cf114c 100644
--- a/pulumi_wasm_generator_lib/src/output/rust/source_code_types_mod.rs
+++ b/pulumi_wasm_generator_lib/src/output/rust/source_code_types_mod.rs
@@ -31,7 +31,13 @@ fn convert_model(package: &crate::model::Package) -> Package {
         .types
         .iter()
         .for_each(|(element_id, resource)| match resource {
-            GlobalType::Object(_properties) => {
+            GlobalType::Object(_, _) => {
+                let ref_type = RefType {
+                    file_name: element_id.get_rust_struct_name().to_case(Case::Snake),
+                };
+                real_types.push(ref_type);
+            }
+            GlobalType::StringEnum(_, _) => {
                 let ref_type = RefType {
                     file_name: element_id.get_rust_struct_name().to_case(Case::Snake),
                 };
diff --git a/pulumi_wasm_generator_lib/src/output/rust/types_code.rs.handlebars b/pulumi_wasm_generator_lib/src/output/rust/types_code.rs.handlebars
index 5c8e96930..cb969be55 100644
--- a/pulumi_wasm_generator_lib/src/output/rust/types_code.rs.handlebars
+++ b/pulumi_wasm_generator_lib/src/output/rust/types_code.rs.handlebars
@@ -1,3 +1,7 @@
+{{#each type.description_lines}}
+    //! {{&this}}
+{{/each}}
+
 #[derive(serde::Deserialize, serde::Serialize, bon::Builder, Debug, PartialEq, Clone)]
 #[builder(finish_fn = build_struct)]
 pub struct {{type.struct_name}} {
diff --git a/pulumi_wasm_generator_lib/src/output/rust/types_code_enum.rs.handlebars b/pulumi_wasm_generator_lib/src/output/rust/types_code_enum.rs.handlebars
new file mode 100644
index 000000000..690c8381a
--- /dev/null
+++ b/pulumi_wasm_generator_lib/src/output/rust/types_code_enum.rs.handlebars
@@ -0,0 +1,16 @@
+{{#each enum.description_lines}}
+    //! {{&this}}
+{{/each}}
+
+#[derive(serde::Deserialize, serde::Serialize, Debug, PartialEq, Clone)]
+pub enum {{enum.struct_name}} {
+    {{#each enum.values as |value|}}
+    {{#each value.description_lines}}
+    /// {{&this}}
+    {{/each}}
+    {{#if value.value}}
+    #[serde(rename = "{{value.value}}")]
+    {{/if}}
+    {{value.name}},
+    {{/each}}
+}
diff --git a/pulumi_wasm_generator_lib/src/schema.rs b/pulumi_wasm_generator_lib/src/schema.rs
index c455af11d..3af951260 100644
--- a/pulumi_wasm_generator_lib/src/schema.rs
+++ b/pulumi_wasm_generator_lib/src/schema.rs
@@ -1,4 +1,7 @@
-use crate::model::{ElementId, GlobalType, GlobalTypeProperty, InputProperty, OutputProperty, Ref};
+use crate::model::{
+    ElementId, GlobalType, GlobalTypeProperty, InputProperty, OutputProperty, Ref,
+    StringEnumElement,
+};
 use anyhow::{anyhow, Context, Result};
 use serde::Deserialize;
 use std::collections::{BTreeMap, BTreeSet, HashSet};
@@ -55,6 +58,8 @@ struct ObjectType {
     properties: PulumiMap<Property>,
     #[serde(default)]
     required: BTreeSet<String>,
+    #[serde(rename = "enum")]
+    enum_: Option<Vec<EnumValue>>,
 }
 
 #[derive(Deserialize, Debug)]
@@ -69,17 +74,15 @@ struct Resource {
 
 #[derive(Deserialize, Debug)]
 struct EnumValue {
-    name: Option<String>,
+    name: String,
     description: Option<String>,
-    // value: Option<String>, //apparently any
+    value: Option<String>,
 }
 
 #[derive(Deserialize, Debug)]
 struct ComplexType {
     #[serde(flatten)]
     object_type: ObjectType,
-    #[serde(default)]
-    r#enum: Vec<EnumValue>,
 }
 
 #[derive(Deserialize, Debug)]
@@ -305,45 +308,7 @@ pub(crate) fn to_model(package: &Package) -> Result<crate::model::Package> {
         .iter()
         .map(|(type_name, type_)| {
             //TODO: Enums, support non objects
-            let element_id = ElementId::new(type_name)?;
-            let tpe = match type_.object_type {
-                ObjectType { r#type: None, .. } => Err(anyhow!("Unknown complex type")),
-                ObjectType {
-                    r#type: Some(TypeEnum::Object),
-                    ..
-                } => Ok(GlobalType::Object(
-                    convert_output_property_object_type(&element_id, &type_.object_type)?
-                        .iter()
-                        .map(|p| GlobalTypeProperty {
-                            name: p.name.clone(),
-                            r#type: p.r#type.clone(),
-                            description: p.description.clone(),
-                        })
-                        .collect(),
-                )),
-                ObjectType {
-                    r#type: Some(TypeEnum::Array),
-                    ..
-                } => Err(anyhow!("Array not supported")),
-                ObjectType {
-                    r#type: Some(TypeEnum::Boolean),
-                    ..
-                } => Ok(GlobalType::Boolean),
-                ObjectType {
-                    r#type: Some(TypeEnum::Integer),
-                    ..
-                } => Ok(GlobalType::Integer),
-                ObjectType {
-                    r#type: Some(TypeEnum::Number),
-                    ..
-                } => Ok(GlobalType::Number),
-                ObjectType {
-                    r#type: Some(TypeEnum::String),
-                    ..
-                } => Ok(GlobalType::String),
-            }
-            .context(format!("Cannot convert type [{type_name}]"))?;
-            Ok((element_id, tpe))
+            convert_to_global_type(type_name, &type_)
         })
         .collect::<Result<BTreeMap<_, _>>>()
         .context("Cannot handle types")?;
@@ -357,6 +322,73 @@ pub(crate) fn to_model(package: &Package) -> Result<crate::model::Package> {
     })
 }
 
+fn convert_to_global_type(
+    type_name: &String,
+    type_: &&ComplexType,
+) -> Result<(ElementId, GlobalType)> {
+    let element_id = ElementId::new(type_name)?;
+    println!("Converting type: {:?}", type_);
+    let tpe = match &type_.object_type {
+        ObjectType { r#type: None, .. } => Err(anyhow!("Unknown complex type")),
+        ObjectType {
+            r#type: Some(TypeEnum::Object),
+            ..
+        } => Ok(GlobalType::Object(
+            type_.object_type.description.clone(),
+            convert_output_property_object_type(&element_id, &type_.object_type)?
+                .iter()
+                .map(|p| GlobalTypeProperty {
+                    name: p.name.clone(),
+                    r#type: p.r#type.clone(),
+                    description: p.description.clone(),
+                })
+                .collect(),
+        )),
+        ObjectType {
+            r#type: Some(TypeEnum::Array),
+            ..
+        } => Err(anyhow!("Array not supported")),
+        ObjectType {
+            r#type: Some(TypeEnum::Boolean),
+            ..
+        } => Ok(GlobalType::Boolean),
+        ObjectType {
+            r#type: Some(TypeEnum::Integer),
+            ..
+        } => Ok(GlobalType::Integer),
+        ObjectType {
+            r#type: Some(TypeEnum::Number),
+            ..
+        } => Ok(GlobalType::Number),
+        ObjectType {
+            r#type: Some(TypeEnum::String),
+            enum_: Some(enum_cases),
+            description,
+            ..
+        } => Ok(create_string_enum(description, enum_cases)),
+        ObjectType {
+            r#type: Some(TypeEnum::String),
+            ..
+        } => Ok(GlobalType::String),
+    }
+    .context(format!("Cannot convert type [{type_name}]"))?;
+    Ok((element_id, tpe))
+}
+
+fn create_string_enum(description: &Option<String>, enum_values: &[EnumValue]) -> GlobalType {
+    GlobalType::StringEnum(
+        description.clone(),
+        enum_values
+            .iter()
+            .map(|enum_value| StringEnumElement {
+                name: enum_value.name.clone(),
+                value: enum_value.value.clone(),
+                description: enum_value.description.clone(),
+            })
+            .collect(),
+    )
+}
+
 fn invalid_required_complextype_required_fields() -> HashSet<(ElementId, String)> {
     HashSet::from([
         // https://github.com/pulumi/pulumi-docker/issues/1052
diff --git a/pulumi_wasm_generator_lib/tests/output/mini-awsnative/lib/src/types/ignore_tags.rs b/pulumi_wasm_generator_lib/tests/output/mini-awsnative/lib/src/types/ignore_tags.rs
index f050aff79..49246def4 100644
--- a/pulumi_wasm_generator_lib/tests/output/mini-awsnative/lib/src/types/ignore_tags.rs
+++ b/pulumi_wasm_generator_lib/tests/output/mini-awsnative/lib/src/types/ignore_tags.rs
@@ -1,3 +1,5 @@
+//! The configuration with resource tag settings to ignore across all resources handled by this provider (except any individual service tag resources such as `ec2.Tag`) for situations where external systems are managing certain resource tags.
+
 #[derive(serde::Deserialize, serde::Serialize, bon::Builder, Debug, PartialEq, Clone)]
 #[builder(finish_fn = build_struct)]
 pub struct IgnoreTags {
diff --git a/pulumi_wasm_generator_lib/tests/output/mini-awsnative/lib/src/types/mod.rs b/pulumi_wasm_generator_lib/tests/output/mini-awsnative/lib/src/types/mod.rs
index 01b9af633..ec4b65b8b 100644
--- a/pulumi_wasm_generator_lib/tests/output/mini-awsnative/lib/src/types/mod.rs
+++ b/pulumi_wasm_generator_lib/tests/output/mini-awsnative/lib/src/types/mod.rs
@@ -1,4 +1,5 @@
+mod region;
+pub use region::*;
 mod ignore_tags;
 pub use ignore_tags::*;
 
-pub type Region = String;
diff --git a/pulumi_wasm_generator_lib/tests/output/mini-awsnative/lib/src/types/region.rs b/pulumi_wasm_generator_lib/tests/output/mini-awsnative/lib/src/types/region.rs
new file mode 100644
index 000000000..5a617bd0a
--- /dev/null
+++ b/pulumi_wasm_generator_lib/tests/output/mini-awsnative/lib/src/types/region.rs
@@ -0,0 +1,80 @@
+//! A Region represents any valid Amazon region that may be targeted with deployments.
+
+#[derive(serde::Deserialize, serde::Serialize, Debug, PartialEq, Clone)]
+pub enum Region {
+    /// Africa (Cape Town)
+    #[serde(rename = "af-south-1")]
+    AFSouth1,
+    /// Asia Pacific (Hong Kong)
+    #[serde(rename = "ap-east-1")]
+    APEast1,
+    /// Asia Pacific (Tokyo)
+    #[serde(rename = "ap-northeast-1")]
+    APNortheast1,
+    /// Asia Pacific (Seoul)
+    #[serde(rename = "ap-northeast-2")]
+    APNortheast2,
+    /// Asia Pacific (Osaka)
+    #[serde(rename = "ap-northeast-3")]
+    APNortheast3,
+    /// Asia Pacific (Mumbai)
+    #[serde(rename = "ap-south-1")]
+    APSouth1,
+    /// Asia Pacific (Singapore)
+    #[serde(rename = "ap-southeast-1")]
+    APSoutheast1,
+    /// Asia Pacific (Sydney)
+    #[serde(rename = "ap-southeast-2")]
+    APSoutheast2,
+    /// Canada (Central)
+    #[serde(rename = "ca-central-1")]
+    CACentral,
+    /// China (Beijing)
+    #[serde(rename = "cn-north-1")]
+    CNNorth1,
+    /// China (Ningxia)
+    #[serde(rename = "cn-northwest-1")]
+    CNNorthwest1,
+    /// Europe (Frankfurt)
+    #[serde(rename = "eu-central-1")]
+    EUCentral1,
+    /// Europe (Stockholm)
+    #[serde(rename = "eu-north-1")]
+    EUNorth1,
+    /// Europe (Ireland)
+    #[serde(rename = "eu-west-1")]
+    EUWest1,
+    /// Europe (London)
+    #[serde(rename = "eu-west-2")]
+    EUWest2,
+    /// Europe (Paris)
+    #[serde(rename = "eu-west-3")]
+    EUWest3,
+    /// Europe (Milan)
+    #[serde(rename = "eu-south-1")]
+    EUSouth1,
+    /// Middle East (Bahrain)
+    #[serde(rename = "me-south-1")]
+    MESouth1,
+    /// South America (São Paulo)
+    #[serde(rename = "sa-east-1")]
+    SAEast1,
+    /// AWS GovCloud (US-East)
+    #[serde(rename = "us-gov-east-1")]
+    USGovEast1,
+    /// AWS GovCloud (US-West)
+    #[serde(rename = "us-gov-west-1")]
+    USGovWest1,
+    /// US East (N. Virginia)
+    #[serde(rename = "us-east-1")]
+    USEast1,
+    /// US East (Ohio)
+    #[serde(rename = "us-east-2")]
+    USEast2,
+    /// US West (N. California)
+    #[serde(rename = "us-west-1")]
+    USWest1,
+    /// US West (Oregon)
+    #[serde(rename = "us-west-2")]
+    USWest2,
+}
diff --git a/pulumi_wasm_generator_lib/tests/test.rs b/pulumi_wasm_generator_lib/tests/test.rs
index 5ba39597b..5468ce981 100644
--- a/pulumi_wasm_generator_lib/tests/test.rs
+++ b/pulumi_wasm_generator_lib/tests/test.rs
@@ -22,14 +22,14 @@ fn functions_secrets() -> Result<()> {
 }
 
 #[test]
-// https://github.com/andrzejressel/pulumi-wasm/issues/394
+// https://github.com/andrzejressel/pulumi-wasm/issues/564
 #[ignore]
 fn output_funcs() -> Result<()> {
     run_pulumi_generator_test("output-funcs", "mypkg")
 }
 
 #[test]
-// https://github.com/andrzejressel/pulumi-wasm/issues/394
+// https://github.com/andrzejressel/pulumi-wasm/issues/563
 #[ignore]
 fn output_funcs_edgeorder() -> Result<()> {
     run_pulumi_generator_test("output-funcs-edgeorder", "myedgeorder")