tools/Elastic.CommonSchema.Generator/Schema/EcsSchemaParser.cs (106 lines of code) (raw):

using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; using CsQuery.ExtensionMethods; using Elastic.CommonSchema.Generator.Schema.DTO; using Newtonsoft.Json; using YamlDotNet.Serialization; namespace Elastic.CommonSchema.Generator.Schema { public class EcsSchemaParser { private readonly string _gitRef; public EcsSchemaParser(string gitRef) { _gitRef = gitRef; SpecificationFolder = Path.Combine(CodeConfiguration.SpecificationFolder, gitRef); EcsYamlFile = Path.Combine(SpecificationFolder, "Core", "ecs_nested.yml"); if (!File.Exists(EcsYamlFile)) throw new Exception($"Failed to locate {EcsYamlFile}"); } public string EcsYamlFile { get; } public string SpecificationFolder { get; } public EcsSchema Parse() { var contents = File.ReadAllText(EcsYamlFile); var deserializer = new Deserializer(); var yamlObject = deserializer.Deserialize(new StringReader(contents)); var asJson = yamlObject.ToJSON(); var jsonSerializer = JsonSerializer.Create(new JsonSerializerSettings { Converters = { new ExpectedConverter() } }); var spec = jsonSerializer.Deserialize<Dictionary<string, FieldSet>>(new JsonTextReader(new StringReader(asJson))); var warnings = SerializeParsedAndCompareWithOriginal(spec, asJson); var templates = ReadTemplates(); var components = ReadComponents(); var ecsVersion = new Regex("^.*\"ecs_version\":\\s?\"(.*?)\".*$", RegexOptions.Singleline) .Replace(templates["composable"], "$1"); return new EcsSchema(spec.Values.ToList(), warnings, templates, components, _gitRef, ecsVersion); } private Dictionary<string, string> ReadTemplates() { var templates = new Dictionary<string, string>(); var templateFiles = from directoryPath in Directory.GetDirectories(SpecificationFolder, "*", SearchOption.AllDirectories) let dir = new DirectoryInfo(directoryPath) from jsonFile in dir.EnumerateFileSystemInfos("*.json") select (dir, jsonFile); foreach (var (dir, jsonFile) in templateFiles) { if (dir.Name == "component") continue; templates.Add(dir.Name, File.ReadAllText(jsonFile.FullName)); } return templates; } private Dictionary<string, string> ReadComponents() { var templates = new Dictionary<string, string>(); var templateFiles = from directoryPath in Directory.GetDirectories(SpecificationFolder, "*", SearchOption.AllDirectories) let dir = new DirectoryInfo(directoryPath) from jsonFile in dir.EnumerateFileSystemInfos("*.json") select (dir, jsonFile); foreach (var (dir, jsonFile) in templateFiles) { if (dir.Name != "component") continue; templates.Add(jsonFile.Name.Replace(".json", ""), File.ReadAllText(jsonFile.FullName)); } return templates; } private List<string> SerializeParsedAndCompareWithOriginal(Dictionary<string, FieldSet> spec, string asJson) { var serialised = JsonConvert.SerializeObject(spec, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Converters = { new FormatAsTextConverter<int>(), new FormatAsTextConverter<int?>(), new FormatAsTextConverter<bool?>() } }); var differ = new JsonDiffPatchDotNet.JsonDiffPatch(); var diffs = differ.Diff(asJson, serialised); var warnings = new List<string>(); if (diffs != null) warnings.Add($"{EcsYamlFile}:{diffs}"); return warnings; } private sealed class FormatAsTextConverter<T> : JsonConverter { public override bool CanRead => false; public override bool CanWrite => true; public override bool CanConvert(Type type) => type == typeof(T); public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var cast = (T)value; writer.WriteValue(cast.ToString()!.ToLower()); } public override object ReadJson(JsonReader reader, Type type, object existingValue, JsonSerializer serializer) => throw new NotSupportedException(); } } }