using System.Text; using Core; using Core.Helpers; using Core.Yaml; using MoreLinq; namespace Generator.DataSource.Yaml; public class YamlBuilder { private OpenApiYaml _file; private bool _isSubNode; private readonly string _configIdentifier; private readonly Dictionary _configs; private readonly OpenApiYamlExtractor _extractor; public YamlBuilder(string filePath, string configIdentifier) { _isSubNode = false; _configIdentifier = configIdentifier; _file = new OpenApiYaml(filePath); _configs = new Dictionary(); _extractor = new OpenApiYamlExtractor(); } /// /// Adds all raw references to the object to build /// public void AddReferences() { var scopedRefs = _extractor.ExtractScopedRefs(_file.Location.ToString()); var allRefs = _extractor.ExtractAllRefs(_file.Location.ToString()); _file.ScopedRefs = scopedRefs; _file.OutScopedRefs = allRefs; _file.OutScopedRefs.ExceptWith(scopedRefs); } /// /// Attributes the dedicated config file to the object to build /// public void SelectConfig() { if (_configs.ContainsKey(_file.Location.GetFileName())) { _file.Config = _configs[_file.Location.GetFileName()]; } else { throw new Exception($"{_file.Location} cannot be generated. You either made a typo " + $"or forgot to register file in {GetConfig(_file.Location)}"); } } /// /// Adds all built schemas to the object to build /// public void AddSchema() { using var enumerator = _file.ScopedRefs.GetEnumerator(); while (enumerator.MoveNext()) { var loc = new Location(enumerator.Current); var fileName = loc.GetFileName(); if(!_configs.ContainsKey(fileName)) continue; var schema = _isSubNode ? _extractor.ExtractNode(loc.ToString()) : CreateSubNode(loc.ToString()); schema.Config = _configs[fileName]; _file.ReferencedSchemas.Add(schema); } } /// /// Adds the models that will be ignored to the object to build /// public void AddIgnoredModels() { foreach (var reference in _file.Refs) { var loc = new Location(reference); var schema = _extractor.ExtractNode(loc.ToString()); _file.IgnoredModels.UnionWith(schema.Models); } } /// /// Simply output the object to build /// /// public OpenApiYaml Create() => _file; /// /// Loads the object to build /// public void LoadSpec() { _file = _extractor.ExtractNode(_file.Location.ToString()); _file.Openapi = _file.Openapi; if (_file.Info != null) _file.Info = new Dictionary(_file.Info); _file.Tags = _file.Tags == null ? new List() : [.._file.Tags]; } /// /// Load all the found config files into the builder /// public void LoadConfigs() { LoadConfig(_file.Location); foreach (var reference in _file.Refs) LoadConfig(new Location(reference)); } private void LoadConfig(Location path) { var configPath = GetConfig(path)?.ToString(); if (configPath == null || _configs.ContainsKey(path.GetFileName())) return; _extractor.LoadConfigs(configPath) .ForEach(c => _configs.TryAdd(c.Key, c.Value)); } private void SetForSubNode() => _isSubNode = true; private OpenApiYaml CreateSubNode(string path) { var yamlBuilder = new YamlBuilder(path, _configIdentifier); yamlBuilder.SetForSubNode(); yamlBuilder.LoadSpec(); yamlBuilder.AddReferences(); yamlBuilder.LoadConfigs(); yamlBuilder.AddSchema(); yamlBuilder.AddIgnoredModels(); return yamlBuilder.Create(); } private Location? GetConfig(Location loc) { var spec = loc.GetFolder(); var pathItems = loc.Path.Split(['/', '\\']); pathItems[^1] = spec + _configIdentifier; var builder = new StringBuilder(); builder.AppendJoin("/", pathItems); var configPath = builder.ToString(); try { PathHelper.CheckPathValidity(configPath); } catch (FileNotFoundException) { return null; } return new Location(configPath); } }