Skip to content

Commit

Permalink
Check if the property name is a valid C# identifier, skip if not, and…
Browse files Browse the repository at this point in the history
… add a '@' before if a keyword
  • Loading branch information
volkanceylan committed Oct 5, 2024
1 parent e36a59e commit 40f7d10
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
namespace Serenity.CodeGeneration;

public static partial class CSharpSyntaxRules
{
private static readonly HashSet<string> Keywords = new(StringComparer.Ordinal)
{
"abstract",
"as",
"base",
"bool",
"breal",
"byte",
"case",
"catch",
"char",
"checked",
"class",
"const",
"continue",
"decimal",
"default",
"delegate",
"do",
"double",
"else",
"enum",
"event",
"explicit",
"extern",
"false",
"finally",
"fixed",
"float",
"for",
"foreach",
"goto",
"if",
"implicit",
"in",
"int",
"interface",
"internal",
"is",
"lock",
"long",
"namespace",
"new",
"null",
"object",
"operator",
"out",
"override",
"params",
"private",
"protected",
"public",
"readonly",
"ref",
"return",
"sbyte",
"sealed",
"short",
"sizeof",
"stackalloc",
"static",
"string",
"struct",
"switch",
"this",
"throw",
"true",
"try",
"typeof",
"uint",
"ulong",
"unchecked",
"unsafe",
"ushort",
"using",
"virtual",
"void",
"volatile",
"while"
};


#if ISSOURCEGENERATOR
const string formattingCharacter = @"\p{Cf}";
const string connectingCharacter = @"\p{Pc}";
const string decimalDigitCharacter = @"\p{Nd}";
const string combiningCharacter = @"\p{Mn}|\p{Mc}";
const string letterCharacter = @"\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}";
const string identifierPartCharacter = letterCharacter + "|" + decimalDigitCharacter + "|" +
connectingCharacter + "|" + combiningCharacter + "|" + formattingCharacter;
const string identifierPartCharacters = "(" + identifierPartCharacter + ")+";
const string identifierStartCharacter = "(" + letterCharacter + "|_)";
const string identifierOrKeyword = identifierStartCharacter + "(" + identifierPartCharacters + ")*";
static readonly Regex ValidIdentifierRegex = new("^" + identifierOrKeyword + "$", RegexOptions.Compiled);
#else
static readonly Regex ValidIdentifierRegex = ValidIdentifierRegexGen();

[GeneratedRegex(@"^(\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}|_)((\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}|\p{Nd}|\p{Pc}|\p{Mn}|\p{Mc}|\p{Cf})+)*$", RegexOptions.Compiled)]
private static partial Regex ValidIdentifierRegexGen();
#endif

public static bool IsKeyword(string identifier)
{
return Keywords.Contains(identifier);
}

public static bool IsValidIdentifier(string identifier, bool ignoreKeywords)
{
if (string.IsNullOrEmpty(identifier))
return false;

if (!ignoreKeywords && IsKeyword(identifier))
return false;

return ValidIdentifierRegex.IsMatch(identifier);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ public partial class ClientTypesGenerator : ImportGeneratorBase
{
private void GenerateBasicType(ExternalType type)
{
cw.IndentedLine("[System.CodeDom.Compiler.GeneratedCode(\"sergen\", null)]");
cw.Indented("public partial class ");
sb.AppendLine(type.Name);

Expand All @@ -24,12 +23,17 @@ private void GenerateBasicTypeMembers(ExternalType type, HashSet<string> skip)
skip.Contains(option.Name))
continue;

if (!CSharpSyntaxRules.IsValidIdentifier(option.Name, ignoreKeywords: true))
continue;

var typeName = GetMemberTypeName(option.Type);

sb.AppendLine();
cw.Indented("public ");
sb.Append(typeName);
sb.Append(' ');
if (CSharpSyntaxRules.IsKeyword(option.Name))
sb.Append('@');
sb.Append(option.Name);
sb.Append(" { get; set; }");
sb.AppendLine();
Expand Down Expand Up @@ -88,5 +92,4 @@ private void AddBasicTypeMembers(SortedDictionary<string, ExternalMember> dict,
dict[member.Name] = member;
}
}

}

0 comments on commit 40f7d10

Please sign in to comment.