|
1 | 1 | using System; |
2 | 2 | using System.Collections.Generic; |
3 | | -using System.ComponentModel; |
4 | 3 | using System.Linq; |
5 | 4 | using System.Reflection; |
| 5 | +using System.Text.RegularExpressions; |
| 6 | +using NUnit.Framework; |
6 | 7 | using Pandora.Data.Helpers; |
7 | 8 | using Pandora.Data.Models; |
8 | 9 | using Pandora.Definitions.Attributes; |
| 10 | +using DescriptionAttribute = System.ComponentModel.DescriptionAttribute; |
9 | 11 |
|
10 | 12 | namespace Pandora.Data.Transformers |
11 | 13 | { |
12 | 14 | public static class Constant |
13 | 15 | { |
14 | | - public static List<ConstantDefinition> FromObject(Type input) |
| 16 | + public static List<ConstantDefinition> WithinObject(Type input) |
15 | 17 | { |
16 | 18 | try |
17 | 19 | { |
18 | | - if (!input.IsClass) |
| 20 | + var actualType = input.GetActualType(true); |
| 21 | + if (actualType == null) |
19 | 22 | { |
20 | | - throw new NotSupportedException("expected a class"); |
| 23 | + return new List<ConstantDefinition>(); |
21 | 24 | } |
22 | 25 |
|
23 | | - var constantDefinitions = new List<ConstantDefinition>(); |
24 | | - foreach (var property in input.GetProperties()) |
| 26 | + if (actualType.IsEnum) |
25 | 27 | { |
26 | | - var propertyType = property.PropertyType; |
27 | | - if (propertyType.IsGenericType && (propertyType.GetGenericTypeDefinition() == typeof(List<>) || propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))) |
| 28 | + return new List<ConstantDefinition> |
28 | 29 | { |
29 | | - propertyType = propertyType.GetGenericArguments()[0]; |
30 | | - } |
31 | | - |
32 | | - if (propertyType.FullName == input.FullName) |
33 | | - { |
34 | | - continue; |
35 | | - } |
| 30 | + FromEnum(input) |
| 31 | + }; |
| 32 | + } |
36 | 33 |
|
37 | | - if (propertyType.IsEnum) |
38 | | - { |
39 | | - var definition = FromEnum(propertyType); |
40 | | - constantDefinitions.Add(definition); |
41 | | - continue; |
42 | | - } |
| 34 | + return WithinObject(input, new List<Type>()); |
| 35 | + } |
| 36 | + catch (Exception ex) |
| 37 | + { |
| 38 | + throw new Exception($"Mapping Constants WithinObject {input.FullName}", ex); |
| 39 | + } |
| 40 | + } |
43 | 41 |
|
44 | | - if (Helpers.IsNativeType(propertyType) || Helpers.IsPandoraCustomType(propertyType) || !propertyType.IsClass) |
45 | | - { |
46 | | - continue; |
47 | | - } |
| 42 | + private static List<ConstantDefinition> WithinObject(Type input, List<Type> knownTypes) |
| 43 | + { |
| 44 | + if (!input.IsClass) |
| 45 | + { |
| 46 | + throw new NotSupportedException("expected a class"); |
| 47 | + } |
48 | 48 |
|
49 | | - var innerConstants = FromObject(propertyType); |
50 | | - constantDefinitions.AddRange(innerConstants); |
51 | | - } |
| 49 | + var found = new List<ConstantDefinition>(); |
| 50 | + var types = Model.FindTypesWithinType(input, knownTypes); |
| 51 | + var allTypes = new List<Type>(); |
| 52 | + allTypes.AddRange(knownTypes); |
| 53 | + allTypes.AddRange(types); |
52 | 54 |
|
53 | | - return constantDefinitions.Distinct(new ConstantComparer()).ToList(); |
| 55 | + foreach (var type in types) |
| 56 | + { |
| 57 | + var constantsWithinType = UsedByType(type); |
| 58 | + found.AddRange(constantsWithinType); |
54 | 59 | } |
55 | | - catch (Exception ex) |
| 60 | + |
| 61 | + return found.Distinct(new ConstantComparer()).ToList(); |
| 62 | + } |
| 63 | + |
| 64 | + private static List<ConstantDefinition> UsedByType(Type input) |
| 65 | + { |
| 66 | + var constants = new List<ConstantDefinition>(); |
| 67 | + |
| 68 | + foreach (var property in input.GetProperties()) |
56 | 69 | { |
57 | | - throw new Exception($"Mapping Constant FromObject {input.FullName}", ex); |
| 70 | + var actualType = property.PropertyType.GetActualType(true); |
| 71 | + if (actualType == null) |
| 72 | + { |
| 73 | + continue; |
| 74 | + } |
| 75 | + |
| 76 | + if (!actualType.IsEnum) |
| 77 | + { |
| 78 | + continue; |
| 79 | + } |
| 80 | + |
| 81 | + var constant = FromEnum(property.PropertyType); |
| 82 | + constants.Add(constant); |
58 | 83 | } |
| 84 | + |
| 85 | + return constants; |
59 | 86 | } |
60 | 87 |
|
61 | 88 | public static ConstantDefinition FromEnum(Type input) |
62 | 89 | { |
63 | 90 | try |
64 | 91 | { |
65 | | - if (!input.IsEnum) |
| 92 | + var actualType = input.GetActualType(true); |
| 93 | + if (actualType == null || !actualType.IsEnum) |
66 | 94 | { |
67 | 95 | throw new NotSupportedException("expected an enum"); |
68 | 96 | } |
69 | 97 |
|
70 | | - var name = input.Name.TrimSuffix("Constant"); |
71 | | - var caseInsensitive = IsCaseInsensitive(input); |
72 | | - var variableType = TypeForEnum(input); |
73 | | - var values = ValuesForEnum(input); |
| 98 | + var name = actualType.Name.TrimSuffix("Constant"); |
| 99 | + var caseInsensitive = IsCaseInsensitive(actualType); |
| 100 | + var variableType = TypeForEnum(actualType); |
| 101 | + var values = ValuesForEnum(actualType); |
74 | 102 |
|
75 | 103 | // this enum has to have a 'description' tag for each of the values |
76 | 104 | return new ConstantDefinition |
@@ -124,7 +152,9 @@ private static Dictionary<string, string> ValuesForEnum(Type input) |
124 | 152 | var values = input.GetEnumValues(); |
125 | 153 | foreach (var val in values) |
126 | 154 | { |
127 | | - var enumValue = input.GetMember(val.ToString()).First(); |
| 155 | + // Some Enum's define `Equals` as a value, however all objects implement Equals too which apparently conflicts here |
| 156 | + // so filter to the member on this specific Enum |
| 157 | + var enumValue = input.GetMember(val.ToString()).First(m => m.DeclaringType == input); |
128 | 158 | var description = enumValue.GetCustomAttribute<DescriptionAttribute>(); |
129 | 159 | if (description == null) |
130 | 160 | { |
|
0 commit comments