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(); } }