73 lines
2.7 KiB
C#
73 lines
2.7 KiB
C#
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();
|
|
}
|
|
} |