Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/Microsoft.DotNet.Arcade.Sdk.Tests/GenerateResxSourceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,18 @@ public void GeneratesCSharp(bool emitFormatMethods, bool asConstants, bool omitG
_output.WriteLine(actualFileContents);
Assert.Equal(File.ReadAllText(expectedFile), actualFileContents, ignoreLineEndingDifferences: true);
}

[Theory]
[InlineData("a", "a")]
[InlineData("A", "A")]
[InlineData("_A", "_A")]
[InlineData(".A", "_A")]
[InlineData("4A", "_4A")]
[InlineData("4(.-)A", "_4____A")]
[InlineData("A\u0660\u2040\u0601\u0300\u0903", "A\u0660\u2040\u0601\u0300\u0903")]
public void GetIdentifierFromResourceName(string name, string expectedIdentifier)
{
Assert.Equal(expectedIdentifier, GenerateResxSource.GetIdentifierFromResourceName(name));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is failing to build: missing internals visible to?

}
}
}
90 changes: 62 additions & 28 deletions src/Microsoft.DotNet.Arcade.Sdk/src/GenerateResxSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,27 +70,6 @@ private enum Lang
CSharp,
VisualBasic,
}

private bool IsLetterChar(UnicodeCategory cat)
{
// letter-character:
// A Unicode character of classes Lu, Ll, Lt, Lm, Lo, or Nl
// A Unicode-escape-sequence representing a character of classes Lu, Ll, Lt, Lm, Lo, or Nl

switch (cat)
{
case UnicodeCategory.UppercaseLetter:
case UnicodeCategory.LowercaseLetter:
case UnicodeCategory.TitlecaseLetter:
case UnicodeCategory.ModifierLetter:
case UnicodeCategory.OtherLetter:
case UnicodeCategory.LetterNumber:
return true;
}

return false;
}

public override bool Execute()
{
string namespaceName;
Expand Down Expand Up @@ -151,7 +130,7 @@ public override bool Execute()

RenderDocComment(language, memberIndent, strings, docCommentString);

string identifier = IsLetterChar(CharUnicodeInfo.GetUnicodeCategory(name[0])) ? name : "_" + name;
string identifier = GetIdentifierFromResourceName(name);

string defaultValue = IncludeDefaultValues ? ", " + CreateStringLiteral(value, language) : string.Empty;

Expand All @@ -160,11 +139,11 @@ public override bool Execute()
case Lang.CSharp:
if (AsConstants)
{
strings.AppendLine($"{memberIndent}internal const string {name} = nameof({name});");
strings.AppendLine($"{memberIndent}internal const string @{identifier} = \"{name}\");");
Comment thread
safern marked this conversation as resolved.
}
else
{
strings.AppendLine($"{memberIndent}internal static string {identifier} => GetResourceString(\"{name}\"{defaultValue});");
strings.AppendLine($"{memberIndent}internal static string @{identifier} => GetResourceString(\"{name}\"{defaultValue});");
}

if (EmitFormatMethods)
Expand All @@ -182,11 +161,11 @@ public override bool Execute()
case Lang.VisualBasic:
if (AsConstants)
{
strings.AppendLine($"{memberIndent}Friend Const {name} As String = \"{name}\"");
strings.AppendLine($"{memberIndent}Friend Const [{identifier}] As String = \"{name}\"");
}
else
{
strings.AppendLine($"{memberIndent}Friend Shared ReadOnly Property {identifier} As String");
strings.AppendLine($"{memberIndent}Friend Shared ReadOnly Property [{identifier}] As String");
strings.AppendLine($"{memberIndent} Get");
strings.AppendLine($"{memberIndent} Return GetResourceString(\"{name}\"{defaultValue})");
strings.AppendLine($"{memberIndent} End Get");
Expand Down Expand Up @@ -215,8 +194,9 @@ public override bool Execute()
{
case Lang.CSharp:
getStringMethod = $@"{memberIndent}internal static global::System.Globalization.CultureInfo Culture {{ get; set; }}

#if !NET20
{memberIndent}[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
#endif
{memberIndent}internal static string GetResourceString(string resourceKey, string defaultValue = null) => ResourceManager.GetString(resourceKey, Culture);";
if (EmitFormatMethods)
{
Expand All @@ -240,8 +220,9 @@ public override bool Execute()

case Lang.VisualBasic:
getStringMethod = $@"{memberIndent}Friend Shared Property Culture As Global.System.Globalization.CultureInfo

#If Not NET20 Then
{memberIndent}<Global.System.Runtime.CompilerServices.MethodImpl(Global.System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)>
#End If
{memberIndent}Friend Shared Function GetResourceString(ByVal resourceKey As String, Optional ByVal defaultValue As String = Nothing) As String
{memberIndent} Return ResourceManager.GetString(resourceKey, Culture)
{memberIndent}End Function";
Expand Down Expand Up @@ -387,6 +368,59 @@ Imports System.Reflection
return true;
}

internal static string GetIdentifierFromResourceName(string name)
{
if (name.All(IsIdentifierPartCharacter))
{
return IsIdentifierStartCharacter(name[0]) ? name : "_" + name;
}

var builder = new StringBuilder(name.Length);

char f = name[0];
if (IsIdentifierPartCharacter(f) && !IsIdentifierStartCharacter(f))
{
builder.Append('_');
}

foreach (char c in name)
{
builder.Append(IsIdentifierPartCharacter(c) ? c : '_');
}

return builder.ToString();

static bool IsIdentifierStartCharacter(char ch)
=> ch == '_' || IsLetterChar(CharUnicodeInfo.GetUnicodeCategory(ch));

static bool IsIdentifierPartCharacter(char ch)
{
var cat = CharUnicodeInfo.GetUnicodeCategory(ch);
return IsLetterChar(cat)
|| cat == UnicodeCategory.DecimalDigitNumber
|| cat == UnicodeCategory.ConnectorPunctuation
|| cat == UnicodeCategory.Format
|| cat == UnicodeCategory.NonSpacingMark
|| cat == UnicodeCategory.SpacingCombiningMark;
}

static bool IsLetterChar(UnicodeCategory cat)
{
switch (cat)
{
case UnicodeCategory.UppercaseLetter:
case UnicodeCategory.LowercaseLetter:
case UnicodeCategory.TitlecaseLetter:
case UnicodeCategory.ModifierLetter:
case UnicodeCategory.OtherLetter:
case UnicodeCategory.LetterNumber:
return true;
}

return false;
}
}

private static void RenderDocComment(Lang language, string memberIndent, StringBuilder strings, string value)
{
string docCommentStart = language == Lang.CSharp
Expand Down