diff --git a/src/NJsonSchema.CodeGeneration.CSharp/CSharpGenerator.cs b/src/NJsonSchema.CodeGeneration.CSharp/CSharpGenerator.cs index 32b6d9fc3..d52e33aa2 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/CSharpGenerator.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/CSharpGenerator.cs @@ -59,7 +59,7 @@ public override string GenerateFile(string rootTypeNameHint) var model = new FileTemplateModel { Namespace = Settings.Namespace ?? string.Empty, - Classes = ConversionUtilities.TrimWhiteSpaces(_resolver.GenerateTypes().Concatenate()) + TypesCode = ConversionUtilities.TrimWhiteSpaces(_resolver.GenerateTypes().Concatenate()) }; var template = Settings.TemplateFactory.CreateTemplate("CSharp", "File", model); diff --git a/src/NJsonSchema.CodeGeneration.CSharp/CSharpTypeResolver.cs b/src/NJsonSchema.CodeGeneration.CSharp/CSharpTypeResolver.cs index e4cadba2a..e7dd917a2 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/CSharpTypeResolver.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/CSharpTypeResolver.cs @@ -9,7 +9,6 @@ using System.Collections.Generic; using System.Linq; using NJsonSchema.CodeGeneration.CSharp.Models; -using NJsonSchema.CodeGeneration.CSharp.Templates; namespace NJsonSchema.CodeGeneration.CSharp { @@ -93,7 +92,8 @@ public override CodeArtifactCollection GenerateTypes() Language = CodeArtifactLanguage.CSharp, TypeName = "JsonInheritanceConverter", - Code = new JsonInheritanceConverterTemplate(new JsonInheritanceConverterTemplateModel(Settings)).Render() + Code = Settings.TemplateFactory.CreateTemplate( + "CSharp", "JsonInheritanceConverter", new JsonInheritanceConverterTemplateModel(Settings)).Render() }); } @@ -105,7 +105,8 @@ public override CodeArtifactCollection GenerateTypes() Language = CodeArtifactLanguage.CSharp, TypeName = "DateFormatConverter", - Code = new DateFormatConverterTemplate(new DateFormatConverterTemplateModel(Settings)).Render() + Code = Settings.TemplateFactory.CreateTemplate( + "CSharp", "DateFormatConverter", new DateFormatConverterTemplateModel(Settings)).Render() }); } diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Models/ClassTemplateModel.cs b/src/NJsonSchema.CodeGeneration.CSharp/Models/ClassTemplateModel.cs index 301e0196b..13ddfeb82 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Models/ClassTemplateModel.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/Models/ClassTemplateModel.cs @@ -40,9 +40,6 @@ public ClassTemplateModel(string typeName, CSharpGeneratorSettings settings, .ToList(); } - /// Gets the NJsonSchema toolchain version. - public string ToolchainVersion => JsonSchema4.ToolchainVersion; - /// Gets or sets the class name. public override string ClassName { get; } @@ -95,9 +92,15 @@ public string InheritanceCode get { if (HasInheritance) - return ": " + BaseClassName + (_settings.ClassStyle == CSharpClassStyle.Inpc ? ", System.ComponentModel.INotifyPropertyChanged" : ""); + { + return ": " + BaseClassName + (_settings.ClassStyle == CSharpClassStyle.Inpc ? + ", System.ComponentModel.INotifyPropertyChanged" : ""); + } else - return _settings.ClassStyle == CSharpClassStyle.Inpc ? ": System.ComponentModel.INotifyPropertyChanged" : ""; + { + return _settings.ClassStyle == CSharpClassStyle.Inpc ? + ": System.ComponentModel.INotifyPropertyChanged" : ""; + } } } } diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Models/EnumTemplateModel.cs b/src/NJsonSchema.CodeGeneration.CSharp/Models/EnumTemplateModel.cs index 385bb4e28..77801df39 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Models/EnumTemplateModel.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/Models/EnumTemplateModel.cs @@ -15,7 +15,7 @@ namespace NJsonSchema.CodeGeneration.CSharp.Models // TODO: Add base class for CSharp.EnumTemplateModel and TypeScript.EnumTemplateModel /// The CSharp enum template model. - public class EnumTemplateModel + public class EnumTemplateModel : TemplateModelBase { private readonly JsonSchema4 _schema; private readonly CSharpGeneratorSettings _settings; @@ -52,7 +52,7 @@ public IEnumerable Enums get { var entries = new List(); - for (int i = 0; i < _schema.Enumeration.Count; i++) + for (var i = 0; i < _schema.Enumeration.Count; i++) { var value = _schema.Enumeration.ElementAt(i); if (value != null) @@ -69,6 +69,7 @@ public IEnumerable Enums }); } } + return entries; } } diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Models/FileTemplateModel.cs b/src/NJsonSchema.CodeGeneration.CSharp/Models/FileTemplateModel.cs index c0f60cb59..070dff80f 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Models/FileTemplateModel.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/Models/FileTemplateModel.cs @@ -14,7 +14,7 @@ public class FileTemplateModel /// Gets or sets the namespace. public string Namespace { get; set; } - /// Gets or sets the classes code. - public string Classes { get; set; } + /// Gets or sets the types code. + public string TypesCode { get; set; } } } \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.CSharp/NJsonSchema.CodeGeneration.CSharp.csproj b/src/NJsonSchema.CodeGeneration.CSharp/NJsonSchema.CodeGeneration.CSharp.csproj index 38661b816..a05507430 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/NJsonSchema.CodeGeneration.CSharp.csproj +++ b/src/NJsonSchema.CodeGeneration.CSharp/NJsonSchema.CodeGeneration.CSharp.csproj @@ -21,7 +21,23 @@ - + + + + + + + + + + + + + + + + + diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/DateFormatConverterTemplate.Extensions.cs b/src/NJsonSchema.CodeGeneration.CSharp/Templates/DateFormatConverterTemplate.Extensions.cs index 3eec35bc4..57e995ee4 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Templates/DateFormatConverterTemplate.Extensions.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/DateFormatConverterTemplate.Extensions.cs @@ -10,7 +10,7 @@ namespace NJsonSchema.CodeGeneration.CSharp.Templates { - internal partial class DateFormatConverterTemplate + internal partial class DateFormatConverterTemplate : ITemplate { public DateFormatConverterTemplate(DateFormatConverterTemplateModel model) { diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/FileTemplate.cs b/src/NJsonSchema.CodeGeneration.CSharp/Templates/FileTemplate.cs index 4943cf15e..595e6d26e 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Templates/FileTemplate.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/FileTemplate.cs @@ -44,7 +44,7 @@ public virtual string TransformText() this.Write("\r\n{\r\n #pragma warning disable // Disable all warnings\r\n\r\n "); #line 12 "C:\Data\Projects\NJsonSchema\src\NJsonSchema.CodeGeneration.CSharp\Templates\FileTemplate.tt" - this.Write(this.ToStringHelper.ToStringWithCulture(ConversionUtilities.Tab(Model.Classes, 1))); + this.Write(this.ToStringHelper.ToStringWithCulture(ConversionUtilities.Tab(Model.TypesCode, 1))); #line default #line hidden diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/FileTemplate.tt b/src/NJsonSchema.CodeGeneration.CSharp/Templates/FileTemplate.tt index 4671ccf16..4b02a02ad 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Templates/FileTemplate.tt +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/FileTemplate.tt @@ -9,5 +9,5 @@ namespace <#=Model.Namespace#> { #pragma warning disable // Disable all warnings - <#=ConversionUtilities.Tab(Model.Classes, 1)#> + <#=ConversionUtilities.Tab(Model.TypesCode, 1)#> } \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceConverterTemplate.Extensions.cs b/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceConverterTemplate.Extensions.cs index 2d5cdec59..7123d3fea 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceConverterTemplate.Extensions.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceConverterTemplate.Extensions.cs @@ -10,7 +10,7 @@ namespace NJsonSchema.CodeGeneration.CSharp.Templates { - internal partial class JsonInheritanceConverterTemplate + internal partial class JsonInheritanceConverterTemplate : ITemplate { public JsonInheritanceConverterTemplate(JsonInheritanceConverterTemplateModel model) { diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/Class.FromJson.liquid b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/Class.FromJson.liquid new file mode 100644 index 000000000..020640500 --- /dev/null +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/Class.FromJson.liquid @@ -0,0 +1,4 @@ +public static {{ ClassName }} FromJson(string data) +{ + return Newtonsoft.Json.JsonConvert.DeserializeObject<{{ ClassName }}>(data{{ JsonSerializerParameterCode }}); +} \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/Class.Inpc.liquid b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/Class.Inpc.liquid new file mode 100644 index 000000000..67b1d44a3 --- /dev/null +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/Class.Inpc.liquid @@ -0,0 +1,8 @@ +public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; + +protected virtual void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null) +{ + var handler = PropertyChanged; + if (handler != null) + handler(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); +} \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/Class.ToJson.liquid b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/Class.ToJson.liquid new file mode 100644 index 000000000..7505b8588 --- /dev/null +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/Class.ToJson.liquid @@ -0,0 +1,4 @@ +public string ToJson() +{ + return Newtonsoft.Json.JsonConvert.SerializeObject(this{{ JsonSerializerParameterCode }}); +} \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/Class.liquid b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/Class.liquid similarity index 81% rename from src/NJsonSchema.CodeGeneration.CSharp/Templates/Class.liquid rename to src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/Class.liquid index c8b4e64da..06236a112 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Templates/Class.liquid +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/Class.liquid @@ -67,26 +67,11 @@ } {%- endif -%} -{%- if RenderInpc -%} - public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; - -{%- endif -%} - public string ToJson() - { - return Newtonsoft.Json.JsonConvert.SerializeObject(this{{ JsonSerializerParameterCode }}); - } + {% template ToJson %} - public static {{ ClassName }} FromJson(string data) - { - return Newtonsoft.Json.JsonConvert.DeserializeObject<{{ ClassName }}>(data{{ JsonSerializerParameterCode }}); - } + {% template FromJson %} {%- if RenderInpc -%} - protected virtual void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null) - { - var handler = PropertyChanged; - if (handler != null) - handler(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); - } + {% template Inpc %} {%- endif -%} } \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/DateFormatConverter.liquid b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/DateFormatConverter.liquid new file mode 100644 index 000000000..612652bfc --- /dev/null +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/DateFormatConverter.liquid @@ -0,0 +1,10 @@ +{%- if GenerateDateFormatConverterClass -%} +[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "{{ ToolchainVersion }}")] +internal class DateFormatConverter : Newtonsoft.Json.Converters.IsoDateTimeConverter +{ + public DateFormatConverter() + { + DateTimeFormat = "yyyy-MM-dd"; + } +} +{%- endif -%} \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/Enum.liquid b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/Enum.liquid new file mode 100644 index 000000000..17c3f6866 --- /dev/null +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/Enum.liquid @@ -0,0 +1,14 @@ +{%- if HasDescription -%} +/// {{ Description | CSharpDocs }} +{%- endif -%} +[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "{{ ToolchainVersion }}")] +{{ TypeAccessModifier }} enum {{ Name }} +{ +{%- for enum in Enums -%} +{%- if IsStringEnum -%} + [System.Runtime.Serialization.EnumMember(Value = "{{ enum.Value }}")] +{%- endif -%} + {{ enum.Name }} = {{ enum.InternalValue }}, + +{%- endfor -%} +} \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/File.liquid b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/File.liquid new file mode 100644 index 000000000..770bf847a --- /dev/null +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/File.liquid @@ -0,0 +1,12 @@ +//---------------------- +// +// Generated using the NJsonSchema v{{ ToolchainVersion }} (http://NJsonSchema.org) +// +//---------------------- + +namespace {{ Namespace }} +{ + #pragma warning disable // Disable all warnings + + {{ TypesCode | tab: 1 }} +} \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/JsonInheritanceConverter.liquid b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/JsonInheritanceConverter.liquid new file mode 100644 index 000000000..80223b4f9 --- /dev/null +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/JsonInheritanceConverter.liquid @@ -0,0 +1,120 @@ +{%- if GenerateJsonInheritanceAttributeClass -%} +[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "{{ ToolchainVersion }}")] +[System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = true)] +internal class JsonInheritanceAttribute : System.Attribute +{ + public JsonInheritanceAttribute(string key, System.Type type) + { + Key = key; + Type = type; + } + + public string Key { get; } + + public System.Type Type { get; } +} + +{%- endif -%} +{%- if GenerateJsonInheritanceConverterClass -%} +[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "{{ ToolchainVersion }}")] +internal class JsonInheritanceConverter : Newtonsoft.Json.JsonConverter +{ + internal static readonly string DefaultDiscriminatorName = "discriminator"; + + private readonly string _discriminator; + + [System.ThreadStatic] + private static bool _isReading; + + [System.ThreadStatic] + private static bool _isWriting; + + public JsonInheritanceConverter() + { + _discriminator = DefaultDiscriminatorName; + } + + public JsonInheritanceConverter(string discriminator) + { + _discriminator = discriminator; + } + + public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) + { + try + { + _isWriting = true; + + var jObject = Newtonsoft.Json.Linq.JObject.FromObject(value, serializer); + jObject.AddFirst(new Newtonsoft.Json.Linq.JProperty(_discriminator, value.GetType().Name)); + writer.WriteToken(jObject.CreateReader()); + } + finally + { + _isWriting = false; + } + } + + public override bool CanWrite + { + get + { + if (_isWriting) + { + _isWriting = false; + return false; + } + return true; + } + } + + public override bool CanRead + { + get + { + if (_isReading) + { + _isReading = false; + return false; + } + return true; + } + } + + public override bool CanConvert(System.Type objectType) + { + return true; + } + + public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) + { + var jObject = serializer.Deserialize(reader); + if (jObject == null) + return null; + + var discriminator = Newtonsoft.Json.Linq.Extensions.Value(jObject.GetValue(_discriminator)); + var subtype = GetObjectSubtype(objectType, discriminator); + + try + { + _isReading = true; + return serializer.Deserialize(jObject.CreateReader(), subtype); + } + finally + { + _isReading = false; + } + } + + private System.Type GetObjectSubtype(System.Type objectType, string discriminator) + { + foreach (var type in System.Reflection.CustomAttributeExtensions.GetCustomAttributes(System.Reflection.IntrospectionExtensions.GetTypeInfo(objectType), false)) + { + if (type.Key == discriminator) + return type.Type; + } + + return objectType; + } +} +{%- endif -%} \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration/CodeGeneratorSettingsBase.cs b/src/NJsonSchema.CodeGeneration/CodeGeneratorSettingsBase.cs index 8c4329fed..d7eaa34d0 100644 --- a/src/NJsonSchema.CodeGeneration/CodeGeneratorSettingsBase.cs +++ b/src/NJsonSchema.CodeGeneration/CodeGeneratorSettingsBase.cs @@ -18,6 +18,10 @@ public CodeGeneratorSettingsBase() { GenerateDefaultValues = true; ExcludedTypeNames = new string[] { }; + +#if DEBUG + UseLiquidTemplates = true; +#endif } /// Gets or sets the schema type (default: JsonSchema). @@ -46,6 +50,9 @@ public CodeGeneratorSettingsBase() public ITemplateFactory TemplateFactory { get; set; } /// Gets or sets a value indicating whether to use DotLiquid templates (experimental). - public bool UseLiquidTemplates { get; set; } = true; + public bool UseLiquidTemplates { get; set; } + + /// Gets or sets the template directory path. + public string TemplateDirectory { get; set; } } } \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration/DefaultTemplateFactory.cs b/src/NJsonSchema.CodeGeneration/DefaultTemplateFactory.cs index 056c6f1ba..10e8ee5e0 100644 --- a/src/NJsonSchema.CodeGeneration/DefaultTemplateFactory.cs +++ b/src/NJsonSchema.CodeGeneration/DefaultTemplateFactory.cs @@ -26,46 +26,70 @@ public DefaultTemplateFactory(CodeGeneratorSettingsBase settings) /// Creates a template for the given language, template name and template model. /// Supports NJsonSchema and NSwag embedded templates. - /// The package name (i.e. language). + /// The language. /// The template name. /// The template model. /// The template. /// Could not load template.. - public virtual ITemplate CreateTemplate(string package, string template, object model) + public virtual ITemplate CreateTemplate(string language, string template, object model) { - if (_settings.UseLiquidTemplates) + var liquidTemplate = TryGetLiquidTemplate(language, template); + if (liquidTemplate != null) + return new LiquidTemplate(language, template, liquidTemplate, model, _settings); + else + return CreateT4Template(language, template, model); + } + + /// Tries to load a Liquid template from an embedded resource. + /// The language. + /// The template name. + /// The template. + protected virtual string TryLoadEmbeddedLiquidTemplate(string language, string template) + { + var assembly = Assembly.Load(new AssemblyName("NJsonSchema.CodeGeneration." + language)); + var resourceName = "NJsonSchema.CodeGeneration." + language + ".Templates.Liquid." + template + ".liquid"; + + var resource = assembly.GetManifestResourceStream(resourceName); + if (resource != null) { - var assembly = Assembly.Load(new AssemblyName("NJsonSchema.CodeGeneration." + package)); - var resourceName = "NJsonSchema.CodeGeneration." + package + ".Templates." + template + ".liquid"; + using (var reader = new StreamReader(resource)) + return reader.ReadToEnd(); + } - var resource = assembly.GetManifestResourceStream(resourceName); - if (resource != null) - { - using (var reader = new StreamReader(resource)) - return new LiquidTemplate(reader.ReadToEnd(), model); - } - else + return null; + } + + private string TryGetLiquidTemplate(string language, string template) + { + if (_settings.UseLiquidTemplates) + { + if (!template.EndsWith("!") && + !string.IsNullOrEmpty(_settings.TemplateDirectory) && + Directory.Exists(_settings.TemplateDirectory)) { - return CreateT4Template(package, template, model); + var templateFilePath = Path.Combine(_settings.TemplateDirectory, language, template + ".liquid"); + if (File.Exists(templateFilePath)) + return File.ReadAllText(templateFilePath); } + + return TryLoadEmbeddedLiquidTemplate(language, template.TrimEnd('!')); } - else - { - return CreateT4Template(package, template, model); - } + + return null; } - private ITemplate CreateT4Template(string package, string template, object model) + /// Could not load template.. + private ITemplate CreateT4Template(string language, string template, object model) { - var typeName = "NJsonSchema.CodeGeneration." + package + ".Templates." + template + "Template"; + var typeName = "NJsonSchema.CodeGeneration." + language + ".Templates." + template + "Template"; var type = Type.GetType(typeName); if (type == null) - type = Assembly.Load(new AssemblyName("NJsonSchema.CodeGeneration." + package))?.GetType(typeName); + type = Assembly.Load(new AssemblyName("NJsonSchema.CodeGeneration." + language))?.GetType(typeName); if (type != null) - return (ITemplate) Activator.CreateInstance(type, model); + return (ITemplate)Activator.CreateInstance(type, model); - throw new InvalidOperationException("Could not load template '" + template + "'."); + throw new InvalidOperationException("Could not load template '" + template + "' for language '" + language + "'."); } } } \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration/LiquidTemplate.cs b/src/NJsonSchema.CodeGeneration/LiquidTemplate.cs index a42f1c778..a534d6b84 100644 --- a/src/NJsonSchema.CodeGeneration/LiquidTemplate.cs +++ b/src/NJsonSchema.CodeGeneration/LiquidTemplate.cs @@ -6,31 +6,50 @@ // Rico Suter, mail@rsuter.com //----------------------------------------------------------------------- +using System.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; using DotLiquid; namespace NJsonSchema.CodeGeneration { internal class LiquidTemplate : ITemplate { + private readonly string _language; private readonly string _template; + private readonly string _data; private readonly object _model; + private readonly CodeGeneratorSettingsBase _settings; - public LiquidTemplate(string template, object model) + public LiquidTemplate(string language, string template, string data, object model, CodeGeneratorSettingsBase settings) { + _language = language; _template = template; + _data = data; _model = model; + _settings = settings; } public string Render() { - var tpl = Template.Parse(_template); - var hash = LiquidHash.FromObject(_model); - // TODO: Check models here - return tpl.Render(new RenderParameters + Template.RegisterTag("template"); + + var data = Regex.Replace(_data, "(\n(( )*?)\\{% template .*?) %}", m => + m.Groups[1].Value + " " + m.Groups[2].Value.Length / 4 + " %}", + RegexOptions.Singleline); + + var template = Template.Parse(data); + + var hash = _model is Hash ? (Hash)_model : LiquidHash.FromObject(_model); + hash[TemplateTag.LanguageKey] = _language; + hash[TemplateTag.TemplateKey] = _template; + hash[TemplateTag.SettingsKey] = _settings; + + return template.Render(new RenderParameters { LocalVariables = hash, Filters = new[] { typeof(LiquidFilters) } - }).Trim('\r', '\n', ' '); + }); } } @@ -38,8 +57,45 @@ internal static class LiquidFilters { public static string CSharpDocs(string input) { - // TODO: Check if this is really called! return ConversionUtilities.ConvertCSharpDocBreaks(input, 0); } + + public static string Tab(Context context, string input, int tabCount) + { + return ConversionUtilities.Tab(input, tabCount); + } + } + + internal class TemplateTag : Tag + { + public static string LanguageKey = "__language"; + public static string TemplateKey = "__template"; + public static string SettingsKey = "__settings"; + + private string _template; + private int _tab; + + public override void Initialize(string tagName, string markup, List tokens) + { + var parts = markup.Trim().Split(' '); + _template = parts[0]; + _tab = parts.Length == 2 ? int.Parse(parts[1]) : 0; + base.Initialize(tagName, markup, tokens); + } + + public override void Render(Context context, TextWriter result) + { + var hash = new Hash(); + foreach (var environment in context.Environments) + hash.Merge(environment); + + var settings = (CodeGeneratorSettingsBase)hash[SettingsKey]; + var template = settings.TemplateFactory.CreateTemplate( + (string)hash[LanguageKey], + !string.IsNullOrEmpty(_template) ? (string)hash[TemplateKey] + "." + _template : (string)hash[TemplateKey] + "!", + hash); + + result.Write(ConversionUtilities.Tab(template.Render(), _tab)); + } } } \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration/Models/ClassTemplateModelBase.cs b/src/NJsonSchema.CodeGeneration/Models/ClassTemplateModelBase.cs index a18d04750..6d3af3004 100644 --- a/src/NJsonSchema.CodeGeneration/Models/ClassTemplateModelBase.cs +++ b/src/NJsonSchema.CodeGeneration/Models/ClassTemplateModelBase.cs @@ -12,7 +12,7 @@ namespace NJsonSchema.CodeGeneration.Models { /// The class template base class. - public abstract class ClassTemplateModelBase + public abstract class ClassTemplateModelBase : TemplateModelBase { private readonly JsonSchema4 _schema; private readonly object _rootObject; diff --git a/src/NJsonSchema.CodeGeneration/Models/TemplateModelBase.cs b/src/NJsonSchema.CodeGeneration/Models/TemplateModelBase.cs new file mode 100644 index 000000000..6fce3deeb --- /dev/null +++ b/src/NJsonSchema.CodeGeneration/Models/TemplateModelBase.cs @@ -0,0 +1,17 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Rico Suter. All rights reserved. +// +// https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md +// Rico Suter, mail@rsuter.com +//----------------------------------------------------------------------- + +namespace NJsonSchema.CodeGeneration.Models +{ + /// The base template model. + public class TemplateModelBase + { + /// Gets the NJsonSchema toolchain version. + public string ToolchainVersion => JsonSchema4.ToolchainVersion; + } +}