using System.Text;
using PkmnLib.Plugin.Gen7.SourceGen.Parsing;
namespace PkmnLib.Plugin.Gen7.SourceGen.Emit;
///
/// Emits a constants class of public static readonly StringKey fields for a
/// .
///
public static class ConstantClassEmitter
{
public static string Emit(ClassSpec spec, List diagnostics)
{
var sb = new StringBuilder();
sb.AppendLine($"// ");
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(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();
}
///
/// Converts a raw data name to a PascalCase identifier: segments split on _/-
/// runs, non-alphanumeric characters stripped, and a leading _ added when the result
/// would start with a digit.
///
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();
}
}