using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using Json.Schema; using Questionable.FatePaths; using Questionable.GatheringPaths; using Questionable.Model; using Questionable.QuestPaths; using Questionable.SeasonalDutyPaths; namespace Questionable.Validation; internal sealed class SchemaRegistrar { private const string BaseUri = "https://github.com/WigglyMuffin/Questionable/raw/refs/heads/main"; private static readonly IReadOnlyList<(string FileName, string Uri, Func Embedded)> Catalog = new global::_003C_003Ez__ReadOnlyArray<(string, string, Func)>(new(string, string, Func)[10] { ("common-aethernetshard.json", "https://github.com/WigglyMuffin/Questionable/raw/refs/heads/main/Questionable.Model/common-aethernetshard.json", () => AssemblyModelLoader.CommonAethernetShard), ("common-aetheryte.json", "https://github.com/WigglyMuffin/Questionable/raw/refs/heads/main/Questionable.Model/common-aetheryte.json", () => AssemblyModelLoader.CommonAetheryte), ("common-classjob.json", "https://github.com/WigglyMuffin/Questionable/raw/refs/heads/main/Questionable.Model/common-classjob.json", () => AssemblyModelLoader.CommonClassJob), ("common-completionflags.json", "https://github.com/WigglyMuffin/Questionable/raw/refs/heads/main/Questionable.Model/common-completionflags.json", () => AssemblyModelLoader.CommonCompletionFlags), ("common-requiredvariables.json", "https://github.com/WigglyMuffin/Questionable/raw/refs/heads/main/Questionable.Model/common-requiredvariables.json", () => AssemblyModelLoader.CommonRequiredVariables), ("common-vector3.json", "https://github.com/WigglyMuffin/Questionable/raw/refs/heads/main/Questionable.Model/common-vector3.json", () => AssemblyModelLoader.CommonVector3), ("quest-v1.json", "https://github.com/WigglyMuffin/Questionable/raw/refs/heads/main/QuestPaths/quest-v1.json", () => AssemblyQuestLoader.QuestSchema), ("fatedefinition-v1.json", "https://github.com/WigglyMuffin/Questionable/raw/refs/heads/main/FatePaths/fatedefinition-v1.json", () => AssemblyFateDefinitionLoader.FateDefinitionSchema), ("gatheringlocation-v1.json", "https://github.com/WigglyMuffin/Questionable/raw/refs/heads/main/GatheringPaths/gatheringlocation-v1.json", () => AssemblyGatheringLocationLoader.GatheringSchema), ("seasonaldutydefinition-v1.json", "https://github.com/WigglyMuffin/Questionable/raw/refs/heads/main/SeasonalDutyPaths/seasonaldutydefinition-v1.json", () => AssemblySeasonalDutyDefinitionLoader.SeasonalDutyDefinitionSchema) }); private readonly SchemaRegistry _registry = new SchemaRegistry(); private readonly Dictionary _schemas = new Dictionary(); private readonly object _lock = new object(); private bool _built; public void EnsureBuilt() { if (_built) { return; } lock (_lock) { if (_built) { return; } BuildOptions buildOptions = new BuildOptions { SchemaRegistry = _registry }; DirectoryInfo projectRoot = FindProjectRoot(); foreach (var (fileName, key, embedded) in Catalog) { _schemas[key] = Build(fileName, embedded, projectRoot, buildOptions); } _built = true; } } public JsonSchema Get(string uri) { EnsureBuilt(); if (!_schemas.TryGetValue(uri, out JsonSchema value)) { throw new InvalidOperationException("schema not registered: " + uri); } return value; } private static JsonSchema Build(string fileName, Func embedded, DirectoryInfo? projectRoot, BuildOptions buildOptions) { if (projectRoot != null) { try { string text = Directory.EnumerateFiles(projectRoot.FullName, fileName, SearchOption.AllDirectories).FirstOrDefault(); if (text != null) { return JsonSchema.FromText(File.ReadAllText(text), buildOptions); } } catch { } } using StreamReader streamReader = new StreamReader(embedded()); return JsonSchema.FromText(streamReader.ReadToEnd(), buildOptions); } private static DirectoryInfo? FindProjectRoot() { try { string location = Assembly.GetExecutingAssembly().Location; if (string.IsNullOrEmpty(location)) { return null; } for (DirectoryInfo directoryInfo = new DirectoryInfo(Path.GetDirectoryName(location) ?? location); directoryInfo != null; directoryInfo = directoryInfo.Parent) { if (directoryInfo.GetDirectories("QuestPaths", SearchOption.TopDirectoryOnly).Length != 0 || directoryInfo.GetDirectories("Questionable.Model", SearchOption.TopDirectoryOnly).Length != 0 || directoryInfo.GetDirectories("Questionable", SearchOption.TopDirectoryOnly).Length != 0) { return directoryInfo; } } } catch { } return null; } }