using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Reflection; using UnityEngine; using UnityObject = UnityEngine.Object; namespace Unity.VisualScripting { public static class NameUtility { private static readonly Dictionary humanPrimitiveNames = new Dictionary { { typeof(byte), "Byte" }, { typeof(sbyte), "Signed Byte" }, { typeof(short), "Short" }, { typeof(ushort), "Unsigned Short" }, { typeof(int), "Integer" }, { typeof(uint), "Unsigned Integer" }, { typeof(long), "Long" }, { typeof(ulong), "Unsigned Long" }, { typeof(float), "Float" }, { typeof(double), "Double" }, { typeof(decimal), "Decimal" }, { typeof(string), "String" }, { typeof(char), "Character" }, { typeof(bool), "Boolean" }, { typeof(void), "Void" }, { typeof(object), "Object" }, }; public static readonly Dictionary humanOperatorNames = new Dictionary { { "op_Addition", "Add" }, { "op_Subtraction", "Subtract" }, { "op_Multiply", "Multiply" }, { "op_Division", "Divide" }, { "op_Modulus", "Modulo" }, { "op_ExclusiveOr", "Exclusive Or" }, { "op_BitwiseAnd", "Bitwise And" }, { "op_BitwiseOr", "Bitwise Or" }, { "op_LogicalAnd", "Logical And" }, { "op_LogicalOr", "Logical Or" }, { "op_Assign", "Assign" }, { "op_LeftShift", "Left Shift" }, { "op_RightShift", "Right Shift" }, { "op_Equality", "Equals" }, { "op_GreaterThan", "Greater Than" }, { "op_LessThan", "Less Than" }, { "op_Inequality", "Not Equals" }, { "op_GreaterThanOrEqual", "Greater Than Or Equals" }, { "op_LessThanOrEqual", "Less Than Or Equals" }, { "op_MultiplicationAssignment", "Multiplication Assignment" }, { "op_SubtractionAssignment", "Subtraction Assignment" }, { "op_ExclusiveOrAssignment", "Exclusive Or Assignment" }, { "op_LeftShiftAssignment", "Left Shift Assignment" }, { "op_ModulusAssignment", "Modulus Assignment" }, { "op_AdditionAssignment", "Addition Assignment" }, { "op_BitwiseAndAssignment", "Bitwise And Assignment" }, { "op_BitwiseOrAssignment", "Bitwise Or Assignment" }, { "op_Comma", "Comma" }, { "op_DivisionAssignment", "Division Assignment" }, { "op_Decrement", "Decrement" }, { "op_Increment", "Increment" }, { "op_UnaryNegation", "Negate" }, { "op_UnaryPlus", "Positive" }, { "op_OnesComplement", "One's Complement" }, }; private static readonly HashSet booleanVerbs = new HashSet { "Is", "Can", "Has", "Are", "Will", "Was", "Had", "Were" }; public static string SelectedName(this Type type, bool human, bool includeGenericParameters = true) { return human ? type.HumanName(includeGenericParameters) : type.CSharpName(includeGenericParameters); } public static string SelectedName(this MemberInfo member, bool human, ActionDirection direction = ActionDirection.Any, bool expectingBoolean = false) { return human ? member.HumanName(direction) : member.CSharpName(direction); } public static string SelectedName(this ParameterInfo parameter, bool human) { return human ? parameter.HumanName() : parameter.Name; } public static string SelectedName(this Exception exception, bool human) { return human ? exception.HumanName() : exception.GetType().CSharpName(false); } public static string SelectedName(this Enum @enum, bool human) { return human ? HumanName(@enum) : @enum.ToString(); } public static string SelectedName(this Namespace @namespace, bool human, bool full = true) { return human ? @namespace.HumanName(full) : @namespace.CSharpName(full); } public static string SelectedParameterString(this MethodBase methodBase, Type targetType, bool human) { return string.Join(", ", methodBase.GetInvocationParameters(targetType).Select(p => p.SelectedName(human)).ToArray()); } public static string DisplayName(this Type type, bool includeGenericParameters = true) { return SelectedName(type, BoltCore.Configuration.humanNaming, includeGenericParameters); } public static string DisplayName(this MemberInfo member, ActionDirection direction = ActionDirection.Any, bool expectingBoolean = false) { return SelectedName(member, BoltCore.Configuration.humanNaming, direction, expectingBoolean); } public static string DisplayName(this ParameterInfo parameter) { return SelectedName(parameter, BoltCore.Configuration.humanNaming); } public static string DisplayName(this Exception exception) { return SelectedName(exception, BoltCore.Configuration.humanNaming); } public static string DisplayName(this Enum @enum) { return SelectedName(@enum, BoltCore.Configuration.humanNaming); } public static string DisplayName(this Namespace @namespace, bool full = true) { return SelectedName(@namespace, BoltCore.Configuration.humanNaming, full); } public static string DisplayParameterString(this MethodBase methodBase, Type targetType) { return SelectedParameterString(methodBase, targetType, BoltCore.Configuration.humanNaming); } public static string HumanName(this Type type, bool includeGenericParameters = true) { if (type == typeof(UnityObject)) { return "Unity Object"; } if (humanPrimitiveNames.ContainsKey(type)) { return humanPrimitiveNames[type]; } else if (type.IsGenericParameter) { var genericParameterName = type.Name.Prettify(); if (genericParameterName == "T") { return "Generic"; } else if (genericParameterName.StartsWith("T ")) { return genericParameterName.Substring(2).Prettify() + " Generic"; } else { return genericParameterName.Prettify(); } } else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) { var nonNullable = Nullable.GetUnderlyingType(type); var underlyingName = nonNullable.HumanName(includeGenericParameters); return "Nullable " + underlyingName; } else { string name; if (Attribute.GetCustomAttribute(type, typeof(DisplayNameAttribute)) is DisplayNameAttribute displayNameAttribute) name = displayNameAttribute.DisplayName; else name = type.Name.Prettify(); if (type.IsInterface && name.StartsWith("I ")) { name = name.Substring(2) + " Interface"; } if (type.IsArray && name.Contains("[]")) { name = name.Replace("[]", " Array"); } if (type.IsGenericType && name.Contains('`')) { name = name.Substring(0, name.IndexOf('`')); } var genericArguments = (IEnumerable)type.GetGenericArguments(); if (type.IsNested) { name += " of " + type.DeclaringType.HumanName(includeGenericParameters); if (type.DeclaringType.IsGenericType) { genericArguments.Skip(type.DeclaringType.GetGenericArguments().Length); } } if (genericArguments.Any()) { if (type.ContainsGenericParameters) { name = "Generic " + name; var count = genericArguments.Count(); if (count > 1) { name += " (" + genericArguments.Count() + " parameters)"; } } else { name += " of "; name += string.Join(" and ", genericArguments.Select(t => t.HumanName(includeGenericParameters)).ToArray()); } } return name; } } public static string HumanName(this MemberInfo member, ActionDirection direction = ActionDirection.Any, bool expectingBoolean = false) { var words = member.Name.Prettify(); if (member is MethodInfo) { if (((MethodInfo)member).IsOperator()) { return humanOperatorNames[member.Name]; } else { return words; } } else if (member is FieldInfo || member is PropertyInfo) { if (direction == ActionDirection.Any) { return words; } var type = member is FieldInfo ? ((FieldInfo)member).FieldType : ((PropertyInfo)member).PropertyType; // Fix for Unity's object-to-boolean implicit null-check operators if (direction == ActionDirection.Get && typeof(UnityObject).IsAssignableFrom(type) && expectingBoolean) { return words + " Is Not Null"; } string verb; switch (direction) { case ActionDirection.Get: verb = "Get"; break; case ActionDirection.Set: verb = "Set"; break; default: throw new UnexpectedEnumValueException(direction); } if (type == typeof(bool)) { // Check for boolean verbs like IsReady, HasChildren, etc. if (words.Contains(' ') && booleanVerbs.Contains(words.Split(' ')[0])) { // Return them as-is for gets if (direction == ActionDirection.Get) { return words; } // Skip them for sets else if (direction == ActionDirection.Set) { return verb + " " + words.Substring(words.IndexOf(' ') + 1); } else { throw new UnexpectedEnumValueException(direction); } } else { return verb + " " + words; } } // Otherwise, add get/set the verb prefix else { return verb + " " + words; } } else if (member is ConstructorInfo) { return "Create " + member.DeclaringType.HumanName(); } else { throw new UnexpectedEnumValueException(direction); } } public static string HumanName(this ParameterInfo parameter) { return parameter.Name.Prettify(); } public static string HumanName(this Exception exception) { return exception.GetType().CSharpName(false).Prettify().Replace(" Exception", ""); } public static string HumanName(this Enum @enum) { return @enum.ToString().Prettify(); } public static string CSharpName(this Namespace @namespace, bool full = true) { return @namespace.IsGlobal ? "(global)" : (full ? @namespace.FullName : @namespace.Name); } public static string HumanName(this Namespace @namespace, bool full = true) { return @namespace.IsGlobal ? "(Global Namespace)" : (full ? @namespace.FullName.Replace(".", "/").Prettify() : @namespace.Name.Prettify()); } public static string ToSummaryString(this Exception ex) { return $"{ex.GetType().DisplayName()}: {ex.Message}"; } } }