using System.Text.RegularExpressions; using Core; using Core.Dto.Yaml; using Core.Exceptions; using Core.Helpers; using Core.Yaml; using Generator.Mappers; using Newtonsoft.Json; using YamlDotNet.Serialization; namespace Generator.DataSource.Yaml; public class OpenApiYamlExtractor { /// /// Retrieves an openapi-formatted yaml at a specific location /// /// file location /// public OpenApiYaml ExtractNode(string path) { var text = PathHelper.TextFrom(path); var deserializer = new DeserializerBuilder() .IgnoreUnmatchedProperties() .Build(); var dto = deserializer.Deserialize(text); return dto.ToModel(path); } /// /// Loads all configs that can be found in the config file located at the given path /// /// Given path /// /// When config file couldn't has been deserialize /// When the given path does not exists public Dictionary LoadConfigs(string configPath) { try { var json = PathHelper.TextFrom(configPath); var configDto = JsonConvert.DeserializeObject(json); return (configDto ?? throw new InvalidOperationException()).Map(); } catch (FileNotFoundException) { throw new ConfigException($"No config file found at {configPath}. Fix it or i'll never generate anything for you"); } } /// /// Extract all scoped references of a specification file. In other words, this will extracts all references /// between the given spec file and the closer reference-related schemas, including paths and params files /// /// Given file path /// public ISet ExtractScopedRefs(string filePath) => ExtractRefs(filePath, false, new HashSet()); /// /// Extract all possibles references from a given specification file /// /// Given file path /// public ISet ExtractAllRefs(string filePath) => ExtractRefs(filePath, true, new HashSet()); private ISet ExtractRefs(string filePath, bool deepSearch, ISet refs) { const string pattern = """(\$ref):\s{1}['|"](.+)['|"]"""; var text = PathHelper.TextFrom(filePath); var matches = Regex.Matches(text, pattern); foreach (Match m in matches) { var rawReference = m.Groups[2].Value; var absolutePath = AbsolutePathFromRef(filePath, rawReference); //If path references itself or circular dependency is detected if (absolutePath == string.Empty || refs.Contains(absolutePath)) continue; if (!deepSearch && IsSchema(absolutePath)) { refs.Add(absolutePath); continue; } var subRefs = ExtractRefs(absolutePath, deepSearch, refs); refs.UnionWith(subRefs); refs.Add(absolutePath); } return refs; } private string AbsolutePathFromRef(string relative, string reference) { var result = PathHelper.GetFolder(relative) + reference; var r = result.Split("#")[0]; return r[^1].Equals('/') ? string.Empty : PathHelper.AbsolutePath(r); } private bool IsSchema(string path) { var l = new Location(path); return l.LastElement().Contains("schemas"); } }