| 1 | using System.Reflection; |
| 2 | using System.Text.Json; |
| 3 | using System.Text.Json.Nodes; |
| 4 | using CascadeIDE.Services; |
| 5 | using Tomlyn; |
| 6 | using Tomlyn.Model; |
| 7 | |
| 8 | namespace CascadeIDE.Tests; |
| 9 | |
| 10 | internal static class IntentCatalogProfileSupport |
| 11 | { |
| 12 | internal static string RepoRoot => |
| 13 | Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "..")); |
| 14 | |
| 15 | internal static string SourceCatalogPath => |
| 16 | Path.Combine(RepoRoot, "IntentMelody", "intent-catalog.toml"); |
| 17 | |
| 18 | internal static string SchemaPath => |
| 19 | Path.Combine(RepoRoot, "docs", "schemas", "intent-catalog.schema.json"); |
| 20 | |
| 21 | internal static string ReadSourceCatalogText() => |
| 22 | File.ReadAllText(SourceCatalogPath); |
| 23 | |
| 24 | internal static JsonNode ToJsonNode(string tomlText) |
| 25 | { |
| 26 | var table = TomlSerializer.Deserialize<TomlTable>(tomlText) |
| 27 | ?? throw new InvalidOperationException("Empty TOML document."); |
| 28 | return TomlTableToJson.Convert(table); |
| 29 | } |
| 30 | |
| 31 | internal static bool TryGetIdeCommandSummary(string commandId, out string summary) |
| 32 | { |
| 33 | var docType = typeof(IdeCommands).Assembly.GetType("CascadeIDE.Services.IdeCommandsDoc", throwOnError: true)!; |
| 34 | var method = docType.GetMethod("TryGetSummary", BindingFlags.Public | BindingFlags.Static)!; |
| 35 | object?[] args = [commandId, null]; |
| 36 | var ok = (bool)method.Invoke(null, args)!; |
| 37 | summary = (string?)args[1] ?? ""; |
| 38 | return ok; |
| 39 | } |
| 40 | |
| 41 | internal static IReadOnlyCollection<string> CollectCommandIds(IntentMelodyCatalogSnapshot snapshot) |
| 42 | { |
| 43 | var ids = new HashSet<string>(StringComparer.OrdinalIgnoreCase); |
| 44 | foreach (var root in snapshot.Roots.Values) |
| 45 | { |
| 46 | if (!string.IsNullOrWhiteSpace(root.CommandId)) |
| 47 | ids.Add(root.CommandId.Trim()); |
| 48 | } |
| 49 | |
| 50 | foreach (var route in snapshot.SlashRoutes.Values) |
| 51 | { |
| 52 | if (!string.IsNullOrWhiteSpace(route.CommandId)) |
| 53 | ids.Add(route.CommandId.Trim()); |
| 54 | } |
| 55 | |
| 56 | return ids; |
| 57 | } |
| 58 | |
| 59 | private static class TomlTableToJson |
| 60 | { |
| 61 | internal static JsonObject Convert(TomlTable table) |
| 62 | { |
| 63 | var obj = new JsonObject(); |
| 64 | foreach (var (key, value) in table) |
| 65 | obj[key] = ConvertValue(value); |
| 66 | return obj; |
| 67 | } |
| 68 | |
| 69 | private static JsonArray ConvertTableArray(TomlTableArray array) |
| 70 | { |
| 71 | var arr = new JsonArray(); |
| 72 | foreach (var table in array) |
| 73 | arr.Add(Convert(table)); |
| 74 | return arr; |
| 75 | } |
| 76 | |
| 77 | private static JsonArray ConvertArray(TomlArray array) |
| 78 | { |
| 79 | var arr = new JsonArray(); |
| 80 | foreach (var item in array) |
| 81 | arr.Add(ConvertValue(item)); |
| 82 | return arr; |
| 83 | } |
| 84 | |
| 85 | private static JsonNode? ConvertValue(object? value) => |
| 86 | value switch |
| 87 | { |
| 88 | null => null, |
| 89 | TomlTable t => Convert(t), |
| 90 | TomlTableArray ta => ConvertTableArray(ta), |
| 91 | TomlArray a => ConvertArray(a), |
| 92 | string s => JsonValue.Create(s), |
| 93 | bool b => JsonValue.Create(b), |
| 94 | long l => JsonValue.Create(l), |
| 95 | int i => JsonValue.Create(i), |
| 96 | double d => JsonValue.Create(d), |
| 97 | float f => JsonValue.Create(f), |
| 98 | DateTimeOffset dto => JsonValue.Create(dto.ToString("O")), |
| 99 | DateTime dt => JsonValue.Create(dt.ToString("O")), |
| 100 | _ => JsonValue.Create(value.ToString()), |
| 101 | }; |
| 102 | } |
| 103 | } |
| 104 | |