| | | 1 | | using System.Text.RegularExpressions; |
| | | 2 | | |
| | | 3 | | namespace NexusLabs.Needlr.Generators.Helpers; |
| | | 4 | | |
| | | 5 | | /// <summary> |
| | | 6 | | /// Helper methods for string manipulation and escaping. |
| | | 7 | | /// </summary> |
| | | 8 | | internal static class StringHelpers |
| | | 9 | | { |
| | | 10 | | /// <summary> |
| | | 11 | | /// Escapes a string for use in a regular C# string literal (quoted string). |
| | | 12 | | /// </summary> |
| | | 13 | | public static string EscapeStringLiteral(string value) |
| | | 14 | | { |
| | 0 | 15 | | return value.Replace("\\", "\\\\").Replace("\"", "\\\""); |
| | | 16 | | } |
| | | 17 | | |
| | | 18 | | /// <summary> |
| | | 19 | | /// Escapes a string for use in a C# verbatim string literal (@"..."). |
| | | 20 | | /// </summary> |
| | | 21 | | public static string EscapeVerbatimStringLiteral(string value) |
| | | 22 | | { |
| | | 23 | | // In verbatim strings, only quotes need escaping (doubled) |
| | 0 | 24 | | return value.Replace("\"", "\"\""); |
| | | 25 | | } |
| | | 26 | | |
| | | 27 | | /// <summary> |
| | | 28 | | /// Escapes content for use in XML documentation comments. |
| | | 29 | | /// </summary> |
| | | 30 | | public static string EscapeXmlContent(string content) |
| | | 31 | | { |
| | 0 | 32 | | return content |
| | 0 | 33 | | .Replace("&", "&") |
| | 0 | 34 | | .Replace("<", "<") |
| | 0 | 35 | | .Replace(">", ">"); |
| | | 36 | | } |
| | | 37 | | |
| | | 38 | | /// <summary> |
| | | 39 | | /// Gets the simple type name without namespace or generic markers. |
| | | 40 | | /// </summary> |
| | | 41 | | public static string GetSimpleTypeName(string fullyQualifiedName) |
| | | 42 | | { |
| | 0 | 43 | | var name = fullyQualifiedName.Replace("global::", ""); |
| | 0 | 44 | | var lastDot = name.LastIndexOf('.'); |
| | 0 | 45 | | var simpleName = lastDot >= 0 ? name.Substring(lastDot + 1) : name; |
| | | 46 | | |
| | | 47 | | // Remove generic suffix if present |
| | 0 | 48 | | var genericIndex = simpleName.IndexOf('<'); |
| | 0 | 49 | | return genericIndex >= 0 ? simpleName.Substring(0, genericIndex) : simpleName; |
| | | 50 | | } |
| | | 51 | | |
| | | 52 | | /// <summary> |
| | | 53 | | /// Converts a PascalCase name to camelCase. |
| | | 54 | | /// </summary> |
| | | 55 | | public static string ToCamelCase(string name) |
| | | 56 | | { |
| | 0 | 57 | | if (string.IsNullOrEmpty(name)) return name; |
| | 0 | 58 | | return char.ToLowerInvariant(name[0]) + name.Substring(1); |
| | | 59 | | } |
| | | 60 | | |
| | | 61 | | /// <summary> |
| | | 62 | | /// Removes the global:: prefix from a type name if present. |
| | | 63 | | /// </summary> |
| | | 64 | | public static string StripGlobalPrefix(string name) |
| | | 65 | | { |
| | 0 | 66 | | return name.StartsWith("global::") ? name.Substring(8) : name; |
| | | 67 | | } |
| | | 68 | | |
| | | 69 | | /// <summary> |
| | | 70 | | /// Extracts the generic type argument from a generic type name. |
| | | 71 | | /// E.g., "IHandler<Order>" returns "Order". |
| | | 72 | | /// </summary> |
| | | 73 | | public static string ExtractGenericTypeArgument(string genericTypeName) |
| | | 74 | | { |
| | 0 | 75 | | var start = genericTypeName.IndexOf('<'); |
| | 0 | 76 | | var end = genericTypeName.LastIndexOf('>'); |
| | 0 | 77 | | if (start < 0 || end < 0 || end <= start) |
| | 0 | 78 | | return genericTypeName; |
| | 0 | 79 | | return genericTypeName.Substring(start + 1, end - start - 1); |
| | | 80 | | } |
| | | 81 | | |
| | | 82 | | /// <summary> |
| | | 83 | | /// Gets the base name of a generic type (before the generic marker). |
| | | 84 | | /// E.g., "LoggingDecorator`1" returns "LoggingDecorator". |
| | | 85 | | /// </summary> |
| | | 86 | | public static string GetGenericBaseName(string typeName) |
| | | 87 | | { |
| | 0 | 88 | | var backtickIndex = typeName.IndexOf('`'); |
| | 0 | 89 | | if (backtickIndex > 0) |
| | 0 | 90 | | return typeName.Substring(0, backtickIndex); |
| | | 91 | | |
| | 0 | 92 | | var angleBracketIndex = typeName.IndexOf('<'); |
| | 0 | 93 | | if (angleBracketIndex > 0) |
| | 0 | 94 | | return typeName.Substring(0, angleBracketIndex); |
| | | 95 | | |
| | 0 | 96 | | return typeName; |
| | | 97 | | } |
| | | 98 | | |
| | | 99 | | /// <summary> |
| | | 100 | | /// Gets the proxy type name for an intercepted service. |
| | | 101 | | /// E.g., "global::MyApp.MyService" returns "MyService_InterceptorProxy". |
| | | 102 | | /// </summary> |
| | | 103 | | public static string GetProxyTypeName(string fullyQualifiedTypeName) |
| | | 104 | | { |
| | 0 | 105 | | return GetSimpleTypeName(fullyQualifiedTypeName) + "_InterceptorProxy"; |
| | | 106 | | } |
| | | 107 | | } |