Replace all raw string comparisons with StringKey, source generator that creates cache keys for all names for Gen7 plugin
All checks were successful
Build / Build (push) Successful in 2m21s
All checks were successful
Build / Build (push) Successful in 2m21s
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
using System.Text;
|
||||
using PkmnLib.Plugin.Gen7.SourceGen.Parsing;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.SourceGen.Emit;
|
||||
|
||||
/// <summary>
|
||||
/// Emits a constants class of <c>public static readonly StringKey</c> fields for a
|
||||
/// <see cref="ClassSpec"/>.
|
||||
/// </summary>
|
||||
public static class ConstantClassEmitter
|
||||
{
|
||||
public static string Emit(ClassSpec spec, List<ExtractionDiagnostic> diagnostics)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"// <auto-generated from Data/{spec.SourceFile} by PkmnLib.Plugin.Gen7.SourceGen />");
|
||||
sb.AppendLine("#nullable enable");
|
||||
sb.AppendLine("using PkmnLib.Static.Utils;");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("namespace PkmnLib.Plugin.Gen7.Common;");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine($"public static class {spec.ClassName}");
|
||||
sb.AppendLine("{");
|
||||
var seen = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||
foreach (var name in spec.Names)
|
||||
{
|
||||
var identifier = Sanitize(name);
|
||||
if (identifier.Length == 0)
|
||||
{
|
||||
diagnostics.Add(new ExtractionDiagnostic("PKMN7G002",
|
||||
$"Name '{name}' in {spec.ClassName} does not produce a usable identifier and was skipped."));
|
||||
continue;
|
||||
}
|
||||
if (seen.TryGetValue(identifier, out var existing))
|
||||
{
|
||||
diagnostics.Add(new ExtractionDiagnostic("PKMN7G001",
|
||||
$"Names '{existing}' and '{name}' in {spec.ClassName} both map to identifier '{identifier}'; '{name}' was skipped."));
|
||||
continue;
|
||||
}
|
||||
seen.Add(identifier, name);
|
||||
sb.AppendLine($" public static readonly StringKey {identifier} = \"{name}\";");
|
||||
}
|
||||
sb.AppendLine("}");
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a raw data name to a PascalCase identifier: segments split on <c>_</c>/<c>-</c>
|
||||
/// runs, non-alphanumeric characters stripped, and a leading <c>_</c> added when the result
|
||||
/// would start with a digit.
|
||||
/// </summary>
|
||||
public static string Sanitize(string raw)
|
||||
{
|
||||
var sb = new StringBuilder(raw.Length);
|
||||
var newSegment = true;
|
||||
foreach (var c in raw)
|
||||
{
|
||||
if (c is '_' or '-')
|
||||
{
|
||||
newSegment = true;
|
||||
continue;
|
||||
}
|
||||
if (!char.IsLetterOrDigit(c))
|
||||
continue;
|
||||
sb.Append(newSegment ? char.ToUpperInvariant(c) : c);
|
||||
newSegment = false;
|
||||
}
|
||||
if (sb.Length == 0)
|
||||
return string.Empty;
|
||||
if (char.IsDigit(sb[0]))
|
||||
sb.Insert(0, '_');
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user