Import from internal git
This commit is contained in:
109
Generator/DataSource/Yaml/OpenApiYamlExtractor.cs
Normal file
109
Generator/DataSource/Yaml/OpenApiYamlExtractor.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves an openapi-formatted yaml at a specific location
|
||||
/// </summary>
|
||||
/// <param name="path">file location</param>
|
||||
/// <returns></returns>
|
||||
public OpenApiYaml ExtractNode(string path)
|
||||
{
|
||||
var text = PathHelper.TextFrom(path);
|
||||
var deserializer = new DeserializerBuilder()
|
||||
.IgnoreUnmatchedProperties()
|
||||
.Build();
|
||||
|
||||
var dto = deserializer.Deserialize<OpenApiYamlDto>(text);
|
||||
return dto.ToModel(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads all configs that can be found in the config file located at the given path
|
||||
/// </summary>
|
||||
/// <param name="configPath">Given path</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InvalidOperationException">When config file couldn't has been deserialize</exception>
|
||||
/// <exception cref="ConfigException">When the given path does not exists</exception>
|
||||
public Dictionary<string, YamlConfig> LoadConfigs(string configPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = PathHelper.TextFrom(configPath);
|
||||
var configDto = JsonConvert.DeserializeObject<SpecConfigDto>(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");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
/// <param name="filePath">Given file path</param>
|
||||
/// <returns></returns>
|
||||
public ISet<string> ExtractScopedRefs(string filePath) => ExtractRefs(filePath, false, new HashSet<string>());
|
||||
|
||||
/// <summary>
|
||||
/// Extract all possibles references from a given specification file
|
||||
/// </summary>
|
||||
/// <param name="filePath">Given file path</param>
|
||||
/// <returns></returns>
|
||||
public ISet<string> ExtractAllRefs(string filePath) => ExtractRefs(filePath, true, new HashSet<string>());
|
||||
|
||||
|
||||
private ISet<string> ExtractRefs(string filePath, bool deepSearch, ISet<string> 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");
|
||||
}
|
||||
|
||||
}
|
||||
164
Generator/DataSource/Yaml/YamlBuilder.cs
Normal file
164
Generator/DataSource/Yaml/YamlBuilder.cs
Normal file
@@ -0,0 +1,164 @@
|
||||
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<string, YamlConfig> _configs;
|
||||
private readonly OpenApiYamlExtractor _extractor;
|
||||
|
||||
public YamlBuilder(string filePath, string configIdentifier)
|
||||
{
|
||||
_isSubNode = false;
|
||||
_configIdentifier = configIdentifier;
|
||||
_file = new OpenApiYaml(filePath);
|
||||
_configs = new Dictionary<string, YamlConfig>();
|
||||
_extractor = new OpenApiYamlExtractor();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds all raw references to the object to build
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attributes the dedicated config file to the object to build
|
||||
/// </summary>
|
||||
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)}");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds all built schemas to the object to build
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the models that will be ignored to the object to build
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simply output the object to build
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public OpenApiYaml Create() => _file;
|
||||
|
||||
/// <summary>
|
||||
/// Loads the object to build
|
||||
/// </summary>
|
||||
public void LoadSpec()
|
||||
{
|
||||
_file = _extractor.ExtractNode(_file.Location.ToString());
|
||||
_file.Openapi = _file.Openapi;
|
||||
if (_file.Info != null) _file.Info = new Dictionary<string, object>(_file.Info);
|
||||
_file.Tags = _file.Tags == null ? new List<object>() : [.._file.Tags];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load all the found config files into the builder
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
36
Generator/DataSource/Yaml/YamlDirector.cs
Normal file
36
Generator/DataSource/Yaml/YamlDirector.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using Core;
|
||||
using Core.Yaml;
|
||||
using Generator.Daos;
|
||||
|
||||
namespace Generator.DataSource.Yaml;
|
||||
|
||||
public class YamlDirector
|
||||
{
|
||||
|
||||
private readonly OpenApiDao _openApiDao;
|
||||
|
||||
public YamlDirector(OpenApiDao openApiDao)
|
||||
{
|
||||
_openApiDao = openApiDao;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build a yaml object lmao what do you want me to say ? All the information's are in the method signature
|
||||
/// </summary>
|
||||
/// <param name="specPath"></param>
|
||||
/// <returns></returns>
|
||||
public OpenApiYaml BuildYaml(string specPath)
|
||||
{
|
||||
var openApiConfig = _openApiDao.GetOpenApi(true, specPath);
|
||||
var yamlBuilder = new YamlBuilder(openApiConfig.SpecFile.ToString(), openApiConfig.ConfigIdentifier);
|
||||
|
||||
yamlBuilder.LoadSpec();
|
||||
yamlBuilder.AddReferences();
|
||||
yamlBuilder.LoadConfigs();
|
||||
yamlBuilder.SelectConfig();
|
||||
yamlBuilder.AddSchema();
|
||||
yamlBuilder.AddIgnoredModels();
|
||||
|
||||
return yamlBuilder.Create();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user