Vibe Card Library Update
This commit is contained in:
@@ -0,0 +1,205 @@
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
var repoRoot = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", ".."));
|
||||
var docsDir = Path.Combine(repoRoot, "chrono.docs");
|
||||
var webWwwRoot = Path.Combine(repoRoot, "Chrono", "Web", "wwwroot");
|
||||
|
||||
Console.WriteLine($"Repo root: {repoRoot}");
|
||||
Console.WriteLine($"Docs dir: {docsDir}");
|
||||
Console.WriteLine($"Web wwwroot: {webWwwRoot}");
|
||||
|
||||
if (!Directory.Exists(docsDir))
|
||||
{
|
||||
Console.Error.WriteLine($"ERROR: docs dir not found: {docsDir}");
|
||||
return 1;
|
||||
}
|
||||
|
||||
var mdFiles = Directory.GetFiles(docsDir, "*.md");
|
||||
var cards = new List<CardData>();
|
||||
|
||||
foreach (var file in mdFiles)
|
||||
{
|
||||
var content = Encoding.UTF8.GetString(File.ReadAllBytes(file));
|
||||
if (!content.StartsWith("---"))
|
||||
continue;
|
||||
|
||||
var endIndex = content.IndexOf("---", 3, StringComparison.Ordinal);
|
||||
if (endIndex < 0)
|
||||
continue;
|
||||
|
||||
var frontmatter = content[3..endIndex].Trim();
|
||||
var yaml = ParseYaml(frontmatter);
|
||||
|
||||
var name = Path.GetFileNameWithoutExtension(file);
|
||||
var category = yaml.GetValueOrDefault("category");
|
||||
if (category == null) continue;
|
||||
|
||||
var card = new CardData
|
||||
{
|
||||
Name = name,
|
||||
Category = category,
|
||||
Cost = ParseInt(yaml, "cost"),
|
||||
Attack = ParseInt(yaml, "attack"),
|
||||
Health = ParseInt(yaml, "health"),
|
||||
Description = StripWikiLinks(yaml.GetValueOrDefault("description")),
|
||||
Faction = StripWikiLink(yaml.GetValueOrDefault("faction")),
|
||||
Set = StripWikiLink(yaml.GetValueOrDefault("set")),
|
||||
Speed = StripWikiLink(yaml.GetValueOrDefault("speed")),
|
||||
Archetypes = ParseList(yaml, "archetypes").Select(s => StripWikiLink(s) ?? "").Where(s => s != "").ToList(),
|
||||
ImmortalizeTo = yaml.ContainsKey("immortalizeTo") ? ParseListOrScalar(yaml, "immortalizeTo").Select(s => StripWikiLink(s) ?? "").Where(s => s != "").ToList() : null,
|
||||
ImmortalizeFrom = StripWikiLink(yaml.GetValueOrDefault("immortalizeFrom")),
|
||||
ImmortalizeWhen = NullIfNa(StripWikiLinks(yaml.GetValueOrDefault("immortalizeWhen"))),
|
||||
ImageFile = StripWikiLink(yaml.GetValueOrDefault("imageLink")),
|
||||
};
|
||||
|
||||
if (card.ImageFile != null && !card.ImageFile.EndsWith(".png"))
|
||||
card.ImageFile += ".png";
|
||||
|
||||
cards.Add(card);
|
||||
}
|
||||
|
||||
// Copy PNGs to wwwroot/cards
|
||||
var cardsDir = Path.Combine(webWwwRoot, "cards");
|
||||
Directory.CreateDirectory(cardsDir);
|
||||
foreach (var card in cards)
|
||||
{
|
||||
if (card.ImageFile == null) continue;
|
||||
var src = Path.Combine(docsDir, card.ImageFile);
|
||||
var dst = Path.Combine(cardsDir, card.ImageFile);
|
||||
if (File.Exists(src))
|
||||
File.Copy(src, dst, overwrite: true);
|
||||
}
|
||||
|
||||
// Write cards.json
|
||||
var output = new { cards };
|
||||
var json = JsonSerializer.Serialize(output, new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
||||
});
|
||||
var jsonPath = Path.Combine(webWwwRoot, "sample-data", "cards.json");
|
||||
File.WriteAllText(jsonPath, json);
|
||||
|
||||
Console.WriteLine($"Processed {cards.Count} cards");
|
||||
Console.WriteLine($"Written to {jsonPath}");
|
||||
return 0;
|
||||
|
||||
// --- Helpers ---
|
||||
|
||||
static int? ParseInt(Dictionary<string, string> yaml, string key)
|
||||
{
|
||||
if (!yaml.TryGetValue(key, out var val)) return null;
|
||||
if (int.TryParse(val, out var i)) return i;
|
||||
return null;
|
||||
}
|
||||
|
||||
static string? StripWikiLink(string? s)
|
||||
{
|
||||
if (s == null || s == "N/A") return null;
|
||||
return Regex.Replace(s, @"\[\[([^\]]*)\]\]", "$1").Trim('"');
|
||||
}
|
||||
|
||||
static string? NullIfNa(string? s) => s is "N/A" or null ? null : s.Trim('"');
|
||||
|
||||
static string? StripWikiLinks(string? s)
|
||||
{
|
||||
if (s == null || s == "N/A") return null;
|
||||
return Regex.Replace(s.Trim('"'), @"\[\[([^\]]*)\]\]", "$1").Trim();
|
||||
}
|
||||
|
||||
static List<string> ParseList(Dictionary<string, string> yaml, string key)
|
||||
{
|
||||
if (!yaml.TryGetValue(key, out var raw)) return [];
|
||||
var result = new List<string>();
|
||||
foreach (var item in raw.Split('\n', StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
var trimmed = item.TrimStart('-', ' ').Trim(' ', '"');
|
||||
if (trimmed.Length > 0) result.Add(trimmed);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static List<string> ParseListOrScalar(Dictionary<string, string> yaml, string key)
|
||||
{
|
||||
if (!yaml.TryGetValue(key, out var raw)) return [];
|
||||
raw = raw.Trim();
|
||||
if (!raw.StartsWith('-'))
|
||||
return [raw.Trim('"')];
|
||||
|
||||
var result = new List<string>();
|
||||
foreach (var item in raw.Split('\n', StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
var trimmed = item.TrimStart('-', ' ').Trim(' ', '"');
|
||||
if (trimmed.Length > 0) result.Add(trimmed);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static Dictionary<string, string> ParseYaml(string yaml)
|
||||
{
|
||||
var dict = new Dictionary<string, string>();
|
||||
var lines = yaml.Split('\n');
|
||||
string? currentKey = null;
|
||||
var listBuffer = new List<string>();
|
||||
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var trimmed = line.Trim();
|
||||
if (trimmed.Length == 0) continue;
|
||||
|
||||
if (trimmed.StartsWith("- "))
|
||||
{
|
||||
listBuffer.Add(trimmed);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (listBuffer.Count > 0 && currentKey != null)
|
||||
{
|
||||
dict[currentKey] = string.Join("\n", listBuffer);
|
||||
listBuffer.Clear();
|
||||
}
|
||||
|
||||
var colonIndex = trimmed.IndexOf(':');
|
||||
if (colonIndex < 0) continue;
|
||||
|
||||
currentKey = trimmed[..colonIndex].Trim();
|
||||
var value = trimmed[(colonIndex + 1)..].Trim();
|
||||
|
||||
if (value.Length == 0)
|
||||
{
|
||||
// Could be a list or multi-line value starting on next line
|
||||
continue;
|
||||
}
|
||||
|
||||
dict[currentKey] = value;
|
||||
}
|
||||
|
||||
if (listBuffer.Count > 0 && currentKey != null)
|
||||
dict[currentKey] = string.Join("\n", listBuffer);
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
record CardData
|
||||
{
|
||||
[JsonPropertyName("name")] public string Name { get; set; } = "";
|
||||
[JsonPropertyName("category")] public string Category { get; set; } = "";
|
||||
[JsonPropertyName("cost")] public int? Cost { get; set; }
|
||||
[JsonPropertyName("attack")] public int? Attack { get; set; }
|
||||
[JsonPropertyName("health")] public int? Health { get; set; }
|
||||
[JsonPropertyName("description")] public string? Description { get; set; }
|
||||
[JsonPropertyName("faction")] public string? Faction { get; set; }
|
||||
[JsonPropertyName("set")] public string? Set { get; set; }
|
||||
[JsonPropertyName("speed")] public string? Speed { get; set; }
|
||||
[JsonPropertyName("archetypes")] public List<string>? Archetypes { get; set; }
|
||||
[JsonPropertyName("immortalizeTo")] public List<string>? ImmortalizeTo { get; set; }
|
||||
[JsonPropertyName("immortalizeFrom")] public string? ImmortalizeFrom { get; set; }
|
||||
[JsonPropertyName("immortalizeWhen")] public string? ImmortalizeWhen { get; set; }
|
||||
[JsonPropertyName("imageFile")] public string? ImageFile { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user