diff --git a/src/Riverside.JsonBinder.Console/InteractiveMode.cs b/src/Riverside.JsonBinder.Console/InteractiveMode.cs index 1517fbe..b3f360f 100644 --- a/src/Riverside.JsonBinder.Console/InteractiveMode.cs +++ b/src/Riverside.JsonBinder.Console/InteractiveMode.cs @@ -100,6 +100,7 @@ private static void ConvertJsonToClasses() } catch (Exception ex) { + throw; ConsoleHelpers.DisplayError("An unexpected error occurred.", ex.Message); } } diff --git a/src/Riverside.JsonBinder.Console/Riverside.JsonBinder.Console.csproj b/src/Riverside.JsonBinder.Console/Riverside.JsonBinder.Console.csproj index e089dd7..f109463 100644 --- a/src/Riverside.JsonBinder.Console/Riverside.JsonBinder.Console.csproj +++ b/src/Riverside.JsonBinder.Console/Riverside.JsonBinder.Console.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/src/Riverside.JsonBinder/Serialization/CSharpSerializer.cs b/src/Riverside.JsonBinder/Serialization/CSharpSerializer.cs index 453c08d..9f16bbe 100644 --- a/src/Riverside.JsonBinder/Serialization/CSharpSerializer.cs +++ b/src/Riverside.JsonBinder/Serialization/CSharpSerializer.cs @@ -1,4 +1,5 @@ using System.Text.Json.Nodes; +using System.Text.Json.Serialization; namespace Riverside.JsonBinder.Serialization; @@ -33,7 +34,8 @@ private void ProcessNode(JsonNode node, string className, List classes) var classDef = $"public class {className}\n{{"; foreach (var property in obj) { - var propType = GetType(property.Value, ToPascalCase(property.Key)); + var propType = GetType(property.Value, className + '_' + ToPascalCase(property.Key)); + classDef += $"\n\n [JsonPropertyName(\"{property.Key}\")]"; classDef += $"\n public {propType} {ToPascalCase(property.Key)} {{ get; set; }}"; } classDef += "\n}"; @@ -41,18 +43,15 @@ private void ProcessNode(JsonNode node, string className, List classes) foreach (var property in obj) { - if (property.Value is JsonObject || property.Value is JsonArray) + if (property.Value is JsonObject) { - ProcessNode(property.Value, ToPascalCase(property.Key), classes); + ProcessNode(property.Value, className + '_' + ToPascalCase(property.Key), classes); + } + else if (property.Value is JsonArray array && array.Count > 0 && array[0] is JsonObject) + { + // Only process arrays of objects + ProcessNode(array[0], className + '_' + ToPascalCase(property.Key + "Item"), classes); } - } - } - else if (node is JsonArray array && array.Count > 0) - { - var firstElement = array[0]; - if (firstElement is JsonObject || firstElement is JsonArray) - { - ProcessNode(firstElement, className + "Item", classes); } } } @@ -65,15 +64,21 @@ private void ProcessNode(JsonNode node, string className, List classes) /// The C# type as a string. public override string GetType(JsonNode? node, string propertyName) { - return node switch + if (node is JsonArray array && array.Count > 0) { - JsonObject => propertyName, - JsonArray => $"List<{propertyName}Item>", - JsonValue value when value.TryGetValue(out _) => "int", - JsonValue value when value.TryGetValue(out _) => "double", - JsonValue value when value.TryGetValue(out _) => "string", - JsonValue value when value.TryGetValue(out _) => "bool", - _ => "object" - }; + var firstElement = array[0]; + if (firstElement is JsonValue val) + { + return $"List<{GetValueType(val, SerializableLanguage.CSharp)}>"; + } + // Handle complex object arrays + return $"List<{propertyName}Item>"; + } + else if (node is JsonObject) + return propertyName; + else if (node is JsonValue val) + return GetValueType(val, SerializableLanguage.CSharp); + + return "object"; } } diff --git a/src/Riverside.JsonBinder/Serialization/LanguageSerializer.cs b/src/Riverside.JsonBinder/Serialization/LanguageSerializer.cs index 6cbb401..bf4a273 100644 --- a/src/Riverside.JsonBinder/Serialization/LanguageSerializer.cs +++ b/src/Riverside.JsonBinder/Serialization/LanguageSerializer.cs @@ -1,4 +1,5 @@ using System.Text.Json.Nodes; +using System.Xml.Linq; namespace Riverside.JsonBinder.Serialization; @@ -29,10 +30,81 @@ public string ToPascalCase(string input) return input; } - // Split the input into words using non-alphanumeric characters as delimiters. - var words = input.Split(new[] { '_', '-', ' ', '.' }, StringSplitOptions.RemoveEmptyEntries); + // Use a regular expression to split by non-alphanumeric delimiters and case transitions. + var words = System.Text.RegularExpressions.Regex + .Split(input, @"(? !string.IsNullOrEmpty(word)); // Capitalize the first letter of each word and join them. return string.Concat(words.Select(word => char.ToUpper(word[0]) + word.Substring(1).ToLower())); } + + public string GetValueType(JsonValue jsonValue, SerializableLanguage language) + { + if (language.Equals(SerializableLanguage.CSharp)) + return jsonValue switch + { + JsonValue value when value.TryGetValue(out _) => "int", + JsonValue value when value.TryGetValue(out _) => "double", + JsonValue value when value.TryGetValue(out _) => "string", + JsonValue value when value.TryGetValue(out _) => "bool", + _ => "object" + }; + else if (language.Equals(SerializableLanguage.JavaScript) || language.Equals(SerializableLanguage.TypeScript)) + return jsonValue switch + { + JsonValue value when value.TryGetValue(out _) => "number", + JsonValue value when value.TryGetValue(out _) => "number", + JsonValue value when value.TryGetValue(out _) => "string", + JsonValue value when value.TryGetValue(out _) => "boolean", + _ => "any" + }; + else if (language.Equals(SerializableLanguage.Java)) + return jsonValue switch + { + JsonValue value when value.TryGetValue(out _) => "int", + JsonValue value when value.TryGetValue(out _) => "double", + JsonValue value when value.TryGetValue(out _) => "String", + JsonValue value when value.TryGetValue(out _) => "boolean", + _ => "Object" + }; + else if (language.Equals(SerializableLanguage.PHP)) + return jsonValue switch + { + JsonValue value when value.TryGetValue(out _) => "int", + JsonValue value when value.TryGetValue(out _) => "float", + JsonValue value when value.TryGetValue(out _) => "string", + JsonValue value when value.TryGetValue(out _) => "bool", + _ => "mixed" // PHP 8+ type hint + }; + else if (language.Equals(SerializableLanguage.Python)) + return jsonValue switch + { + JsonValue value when value.TryGetValue(out _) => "int", + JsonValue value when value.TryGetValue(out _) => "float", + JsonValue value when value.TryGetValue(out _) => "str", + JsonValue value when value.TryGetValue(out _) => "bool", + _ => "object" + }; + else if(language.Equals(SerializableLanguage.Ruby)) + return jsonValue switch + { + JsonValue value when value.TryGetValue(out _) => "Integer", + JsonValue value when value.TryGetValue(out _) => "Float", + JsonValue value when value.TryGetValue(out _) => "String", + JsonValue value when value.TryGetValue(out _) => "T::Boolean", + _ => "T.untyped" + }; + else if (language.Equals(SerializableLanguage.Swift)) + return jsonValue switch + { + JsonValue value when value.TryGetValue(out _) => "Int", + JsonValue value when value.TryGetValue(out _) => "Double", + JsonValue value when value.TryGetValue(out _) => "String", + JsonValue value when value.TryGetValue(out _) => "Bool", + _ => "Any" + }; + + return "unknown"; + } }