diff --git a/src/NJsonSchema.CodeGeneration.CSharp/CSharpGenerator.cs b/src/NJsonSchema.CodeGeneration.CSharp/CSharpGenerator.cs index d52e33aa2..ceef5aa0c 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/CSharpGenerator.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/CSharpGenerator.cs @@ -13,35 +13,32 @@ namespace NJsonSchema.CodeGeneration.CSharp { /// The CSharp code generator. - public class CSharpGenerator : TypeGeneratorBase + public class CSharpGenerator : GeneratorBase { - private readonly JsonSchema4 _schema; private readonly CSharpTypeResolver _resolver; /// Initializes a new instance of the class. - /// The schema. - public CSharpGenerator(JsonSchema4 schema) - : this(schema, new CSharpGeneratorSettings()) + /// The root object to search for all JSON Schemas. + public CSharpGenerator(object rootObject) + : this(rootObject, new CSharpGeneratorSettings()) { } /// Initializes a new instance of the class. - /// The schema. + /// The root object to search for all JSON Schemas. /// The generator settings. - public CSharpGenerator(JsonSchema4 schema, CSharpGeneratorSettings settings) - : this(schema, settings, new CSharpTypeResolver(settings, schema), null) + public CSharpGenerator(object rootObject, CSharpGeneratorSettings settings) + : this(rootObject, settings, new CSharpTypeResolver(settings)) { } /// Initializes a new instance of the class. - /// The schema. + /// The root object to search for all JSON Schemas. /// The generator settings. /// The resolver. - /// The root object to search for all JSON Schemas. - public CSharpGenerator(JsonSchema4 schema, CSharpGeneratorSettings settings, CSharpTypeResolver resolver, object rootObject) - : base(schema, rootObject) + public CSharpGenerator(object rootObject, CSharpGeneratorSettings settings, CSharpTypeResolver resolver) + : base(rootObject, resolver, settings) { - _schema = schema; _resolver = resolver; Settings = settings; } @@ -49,17 +46,46 @@ public CSharpGenerator(JsonSchema4 schema, CSharpGeneratorSettings settings, CSh /// Gets the generator settings. public CSharpGeneratorSettings Settings { get; } - /// Generates the file. - /// The root type name hint. - /// The file contents. - public override string GenerateFile(string rootTypeNameHint) + /// + public override CodeArtifactCollection GenerateTypes() { - _resolver.Resolve(_schema, false, rootTypeNameHint); // register root type + var collection = base.GenerateTypes(); + var results = new List(); + + if (collection.Artifacts.Any(r => r.Code.Contains("JsonInheritanceConverter"))) + { + if (Settings.ExcludedTypeNames?.Contains("JsonInheritanceAttribute") != true) + { + var template = Settings.TemplateFactory.CreateTemplate("CSharp", "JsonInheritanceAttribute", null); + results.Add(new CodeArtifact("JsonInheritanceConverter", CodeArtifactType.Class, CodeArtifactLanguage.CSharp, template)); + } + + if (Settings.ExcludedTypeNames?.Contains("JsonInheritanceConverter") != true) + { + var template = Settings.TemplateFactory.CreateTemplate("CSharp", "JsonInheritanceConverter", null); + results.Add(new CodeArtifact("JsonInheritanceConverter", CodeArtifactType.Class, CodeArtifactLanguage.CSharp, template)); + } + } + + if (collection.Artifacts.Any(r => r.Code.Contains("DateFormatConverter"))) + { + if (Settings.ExcludedTypeNames?.Contains("DateFormatConverter") != true) + { + var template = Settings.TemplateFactory.CreateTemplate("CSharp", "DateFormatConverter", null); + results.Add(new CodeArtifact("DateFormatConverter", CodeArtifactType.Class, CodeArtifactLanguage.CSharp, template)); + } + } + + return new CodeArtifactCollection(collection.Artifacts.Concat(results), collection.ExtensionCode); + } + /// + protected override string GenerateFile(CodeArtifactCollection artifactCollection) + { var model = new FileTemplateModel { Namespace = Settings.Namespace ?? string.Empty, - TypesCode = ConversionUtilities.TrimWhiteSpaces(_resolver.GenerateTypes().Concatenate()) + TypesCode = artifactCollection.Concatenate() }; var template = Settings.TemplateFactory.CreateTemplate("CSharp", "File", model); @@ -67,35 +93,27 @@ public override string GenerateFile(string rootTypeNameHint) } /// Generates the type. + /// The schema. /// The type name hint. /// The code. - public override CodeArtifact GenerateType(string typeNameHint) + protected override CodeArtifact GenerateType(JsonSchema4 schema, string typeNameHint) { - var typeName = _resolver.GetOrGenerateTypeName(_schema, typeNameHint); + var typeName = _resolver.GetOrGenerateTypeName(schema, typeNameHint); - if (_schema.IsEnumeration) - return GenerateEnum(typeName); + if (schema.IsEnumeration) + return GenerateEnum(schema, typeName); else - return GenerateClass(typeName); + return GenerateClass(schema, typeName); } - private CodeArtifact GenerateClass(string typeName) + private CodeArtifact GenerateClass(JsonSchema4 schema, string typeName) { - var model = new ClassTemplateModel(typeName, Settings, _resolver, _schema, RootObject); + var model = new ClassTemplateModel(typeName, Settings, _resolver, schema, RootObject); RenamePropertyWithSameNameAsClass(typeName, model.Properties); var template = Settings.TemplateFactory.CreateTemplate("CSharp", "Class", model); - return new CodeArtifact - { - Type = CodeArtifactType.Class, - Language = CodeArtifactLanguage.CSharp, - - TypeName = typeName, - BaseTypeName = model.BaseClassName, - - Code = template.Render() - }; + return new CodeArtifact(typeName, model.BaseClassName, CodeArtifactType.Class, CodeArtifactLanguage.CSharp, template); } private void RenamePropertyWithSameNameAsClass(string typeName, IEnumerable properties) @@ -111,18 +129,11 @@ private void RenamePropertyWithSameNameAsClass(string typeName, IEnumerableGets or sets the .NET namespace of the generated types. diff --git a/src/NJsonSchema.CodeGeneration.CSharp/CSharpTypeResolver.cs b/src/NJsonSchema.CodeGeneration.CSharp/CSharpTypeResolver.cs index 35396a9f2..066908952 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/CSharpTypeResolver.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/CSharpTypeResolver.cs @@ -6,24 +6,18 @@ // Rico Suter, mail@rsuter.com //----------------------------------------------------------------------- -using System.Collections.Generic; using System.Linq; -using NJsonSchema.CodeGeneration.CSharp.Models; namespace NJsonSchema.CodeGeneration.CSharp { /// Manages the generated types and converts JSON types to CSharp types. - public class CSharpTypeResolver : TypeResolverBase + public class CSharpTypeResolver : TypeResolverBase { - private readonly object _rootObject; - /// Initializes a new instance of the class. /// The generator settings. - /// The root object to search for JSON Schemas. - public CSharpTypeResolver(CSharpGeneratorSettings settings, object rootObject) + public CSharpTypeResolver(CSharpGeneratorSettings settings) : base(settings) { - _rootObject = rootObject; Settings = settings; } @@ -74,76 +68,9 @@ public override string Resolve(JsonSchema4 schema, bool isNullable, string typeN return string.Format(Settings.DictionaryType + "", valueType); } - return AddGenerator(schema, typeNameHint); - } - - /// - public override CodeArtifactCollection GenerateTypes() - { - return GenerateTypes(null); - } - - /// Generates the code for all described types (e.g. interfaces, classes, enums, etc). - /// The code. - public override CodeArtifactCollection GenerateTypes(ExtensionCode extensionCode) - { - var collection = base.GenerateTypes(extensionCode); - var results = new List(); - - if (collection.Artifacts.Any(r => r.Code.Contains("JsonInheritanceConverter"))) - { - results.Add(new CodeArtifact - { - Type = CodeArtifactType.Class, - Language = CodeArtifactLanguage.CSharp, - - TypeName = "JsonInheritanceConverter", - Code = Settings.TemplateFactory.CreateTemplate( - "CSharp", "JsonInheritanceConverter", new JsonInheritanceConverterTemplateModel(Settings)).Render() - }); - } - - if (collection.Artifacts.Any(r => r.Code.Contains("DateFormatConverter"))) - { - results.Add(new CodeArtifact - { - Type = CodeArtifactType.Class, - Language = CodeArtifactLanguage.CSharp, - - TypeName = "DateFormatConverter", - Code = Settings.TemplateFactory.CreateTemplate( - "CSharp", "DateFormatConverter", new DateFormatConverterTemplateModel(Settings)).Render() - }); - } - - return new CodeArtifactCollection(collection.Artifacts.Concat(results)); + return GetOrGenerateTypeName(schema, typeNameHint); } - - /// Adds a generator for the given schema if necessary. - /// The schema. - /// The type name hint. - /// The type name of the created generator. - protected override string AddGenerator(JsonSchema4 schema, string typeNameHint) - { - if (schema.IsEnumeration && schema.Type == JsonObjectType.Integer) - { - // Regenerate generator because it is be better than the current one (defined enum values) - var typeName = GetOrGenerateTypeName(schema, typeNameHint); - var generator = CreateTypeGenerator(schema); - AddOrReplaceTypeGenerator(typeName, generator); - } - - return base.AddGenerator(schema, typeNameHint); - } - - /// Creates a type generator. - /// The schema. - /// The generator. - protected override CSharpGenerator CreateTypeGenerator(JsonSchema4 schema) - { - return new CSharpGenerator(schema, Settings, this, _rootObject); - } - + private string ResolveString(JsonSchema4 schema, bool isNullable, string typeNameHint) { if (schema.Format == JsonFormatStrings.Date) @@ -169,7 +96,7 @@ private string ResolveString(JsonSchema4 schema, bool isNullable, string typeNam #pragma warning restore 618 if (schema.IsEnumeration) - return AddGenerator(schema, typeNameHint) + (isNullable ? "?" : string.Empty); + return GetOrGenerateTypeName(schema, typeNameHint) + (isNullable ? "?" : string.Empty); return "string"; } @@ -182,7 +109,7 @@ private static string ResolveBoolean(bool isNullable) private string ResolveInteger(JsonSchema4 schema, bool isNullable, string typeNameHint) { if (schema.IsEnumeration) - return AddGenerator(schema, typeNameHint) + (isNullable ? "?" : string.Empty); + return GetOrGenerateTypeName(schema, typeNameHint) + (isNullable ? "?" : string.Empty); if (schema.Format == JsonFormatStrings.Byte) return isNullable ? "byte?" : "byte"; diff --git a/src/NJsonSchema.CodeGeneration.CSharp/CSharpValueGenerator.cs b/src/NJsonSchema.CodeGeneration.CSharp/CSharpValueGenerator.cs index 13dbd3604..04737b104 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/CSharpValueGenerator.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/CSharpValueGenerator.cs @@ -19,7 +19,7 @@ public class CSharpValueGenerator : ValueGeneratorBase /// Initializes a new instance of the class. /// The type resolver. /// The settings. - public CSharpValueGenerator(ITypeResolver typeResolver, CSharpGeneratorSettings settings) + public CSharpValueGenerator(TypeResolverBase typeResolver, CSharpGeneratorSettings settings) : base(typeResolver, settings.EnumNameGenerator) { _settings = settings; diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Models/JsonInheritanceConverterTemplateModel.cs b/src/NJsonSchema.CodeGeneration.CSharp/Models/JsonInheritanceConverterTemplateModel.cs deleted file mode 100644 index 5c8140125..000000000 --- a/src/NJsonSchema.CodeGeneration.CSharp/Models/JsonInheritanceConverterTemplateModel.cs +++ /dev/null @@ -1,30 +0,0 @@ -//----------------------------------------------------------------------- -// -// Copyright (c) Rico Suter. All rights reserved. -// -// https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md -// Rico Suter, mail@rsuter.com -//----------------------------------------------------------------------- - -using System.Linq; - -namespace NJsonSchema.CodeGeneration.CSharp.Models -{ - /// The JsonInheritanceConverterTemplateModel. - public class JsonInheritanceConverterTemplateModel - { - private readonly CSharpGeneratorSettings _settings; - - /// The JsonInheritanceConverterTemplateModel. - public JsonInheritanceConverterTemplateModel(CSharpGeneratorSettings settings) - { - _settings = settings; - } - - /// Gets or sets a value indicating whether to generate the JsonInheritanceAttribute class. - public bool GenerateJsonInheritanceAttributeClass => _settings.ExcludedTypeNames?.Contains("JsonInheritanceAttribute") != true; - - /// Gets or sets a value indicating whether to generate the GenerateJsonInheritanceConverterClass class. - public bool GenerateJsonInheritanceConverterClass => _settings.ExcludedTypeNames?.Contains("JsonInheritanceConverter") != true; - } -} diff --git a/src/NJsonSchema.CodeGeneration.CSharp/NJsonSchema.CodeGeneration.CSharp.csproj b/src/NJsonSchema.CodeGeneration.CSharp/NJsonSchema.CodeGeneration.CSharp.csproj index 01000bff2..1180f9b20 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/NJsonSchema.CodeGeneration.CSharp.csproj +++ b/src/NJsonSchema.CodeGeneration.CSharp/NJsonSchema.CodeGeneration.CSharp.csproj @@ -2,7 +2,7 @@ netstandard1.3;net451 JSON Schema draft v4 reader, generator and validator for .NET - 9.8.3 + 9.9.0 json schema validation generator .net Copyright © Rico Suter, 2017 https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md @@ -31,15 +31,39 @@ - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -65,6 +89,10 @@ TextTemplatingFilePreprocessor FileTemplate.cs + + JsonInheritanceAttributeTemplate.cs + TextTemplatingFilePreprocessor + TextTemplatingFilePreprocessor JsonInheritanceConverterTemplate.cs @@ -94,6 +122,11 @@ True FileTemplate.tt + + True + True + JsonInheritanceAttributeTemplate.tt + True True diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/DateFormatConverterTemplate.cs b/src/NJsonSchema.CodeGeneration.CSharp/Templates/DateFormatConverterTemplate.cs index ddc6944e8..8f5f79c60 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Templates/DateFormatConverterTemplate.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/DateFormatConverterTemplate.cs @@ -25,28 +25,16 @@ internal partial class DateFormatConverterTemplate : DateFormatConverterTemplate /// public virtual string TransformText() { - - #line 2 "C:\Data\Projects\NJsonSchema\src\NJsonSchema.CodeGeneration.CSharp\Templates\DateFormatConverterTemplate.tt" -if(Model.GenerateDateFormatConverterClass){ - - #line default - #line hidden this.Write("[System.CodeDom.Compiler.GeneratedCode(\"NJsonSchema\", \""); - #line 3 "C:\Data\Projects\NJsonSchema\src\NJsonSchema.CodeGeneration.CSharp\Templates\DateFormatConverterTemplate.tt" + #line 2 "C:\Data\Projects\NJsonSchema\src\NJsonSchema.CodeGeneration.CSharp\Templates\DateFormatConverterTemplate.tt" this.Write(this.ToStringHelper.ToStringWithCulture(JsonSchema4.ToolchainVersion)); #line default #line hidden this.Write("\")]\r\ninternal class DateFormatConverter : Newtonsoft.Json.Converters.IsoDateTimeC" + "onverter\r\n{\r\n public DateFormatConverter()\r\n {\r\n DateTimeFormat = \"" + - "yyyy-MM-dd\";\r\n }\r\n}\r\n"); - - #line 11 "C:\Data\Projects\NJsonSchema\src\NJsonSchema.CodeGeneration.CSharp\Templates\DateFormatConverterTemplate.tt" -} - - #line default - #line hidden + "yyyy-MM-dd\";\r\n }\r\n}"); return this.GenerationEnvironment.ToString(); } } diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/DateFormatConverterTemplate.tt b/src/NJsonSchema.CodeGeneration.CSharp/Templates/DateFormatConverterTemplate.tt index 030177866..59d0a3e43 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Templates/DateFormatConverterTemplate.tt +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/DateFormatConverterTemplate.tt @@ -1,5 +1,4 @@ <#@ template visibility="internal" #> -<#if(Model.GenerateDateFormatConverterClass){#> [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "<#=JsonSchema4.ToolchainVersion#>")] internal class DateFormatConverter : Newtonsoft.Json.Converters.IsoDateTimeConverter { @@ -7,5 +6,4 @@ internal class DateFormatConverter : Newtonsoft.Json.Converters.IsoDateTimeConve { DateTimeFormat = "yyyy-MM-dd"; } -} -<#}#> \ No newline at end of file +} \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceAttributeTemplate.Extensions.cs b/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceAttributeTemplate.Extensions.cs new file mode 100644 index 000000000..f7ab2b9e0 --- /dev/null +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceAttributeTemplate.Extensions.cs @@ -0,0 +1,25 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Rico Suter. All rights reserved. +// +// https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md +// Rico Suter, mail@rsuter.com +//----------------------------------------------------------------------- + +namespace NJsonSchema.CodeGeneration.CSharp.Templates +{ + internal partial class JsonInheritanceAttributeTemplate : ITemplate + { + public JsonInheritanceAttributeTemplate(object model) + { + Model = model; + } + + public object Model { get; } + + public string Render() + { + return ConversionUtilities.TrimWhiteSpaces(TransformText()); + } + } +} diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceAttributeTemplate.cs b/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceAttributeTemplate.cs new file mode 100644 index 000000000..99175e146 --- /dev/null +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceAttributeTemplate.cs @@ -0,0 +1,327 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version: 15.0.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ +namespace NJsonSchema.CodeGeneration.CSharp.Templates +{ + using System; + + /// + /// Class to produce the template output + /// + + #line 1 "C:\Data\Projects\NJsonSchema\src\NJsonSchema.CodeGeneration.CSharp\Templates\JsonInheritanceAttributeTemplate.tt" + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "15.0.0.0")] + internal partial class JsonInheritanceAttributeTemplate : JsonInheritanceAttributeTemplateBase + { +#line hidden + /// + /// Create the template output + /// + public virtual string TransformText() + { + this.Write("[System.CodeDom.Compiler.GeneratedCode(\"NJsonSchema\", \""); + + #line 2 "C:\Data\Projects\NJsonSchema\src\NJsonSchema.CodeGeneration.CSharp\Templates\JsonInheritanceAttributeTemplate.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(JsonSchema4.ToolchainVersion)); + + #line default + #line hidden + this.Write(@""")] +[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; } +}"); + return this.GenerationEnvironment.ToString(); + } + } + + #line default + #line hidden + #region Base class + /// + /// Base class for this transformation + /// + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "15.0.0.0")] + internal class JsonInheritanceAttributeTemplateBase + { + #region Fields + private global::System.Text.StringBuilder generationEnvironmentField; + private global::System.CodeDom.Compiler.CompilerErrorCollection errorsField; + private global::System.Collections.Generic.List indentLengthsField; + private string currentIndentField = ""; + private bool endsWithNewline; + private global::System.Collections.Generic.IDictionary sessionField; + #endregion + #region Properties + /// + /// The string builder that generation-time code is using to assemble generated output + /// + protected System.Text.StringBuilder GenerationEnvironment + { + get + { + if ((this.generationEnvironmentField == null)) + { + this.generationEnvironmentField = new global::System.Text.StringBuilder(); + } + return this.generationEnvironmentField; + } + set + { + this.generationEnvironmentField = value; + } + } + /// + /// The error collection for the generation process + /// + public System.CodeDom.Compiler.CompilerErrorCollection Errors + { + get + { + if ((this.errorsField == null)) + { + this.errorsField = new global::System.CodeDom.Compiler.CompilerErrorCollection(); + } + return this.errorsField; + } + } + /// + /// A list of the lengths of each indent that was added with PushIndent + /// + private System.Collections.Generic.List indentLengths + { + get + { + if ((this.indentLengthsField == null)) + { + this.indentLengthsField = new global::System.Collections.Generic.List(); + } + return this.indentLengthsField; + } + } + /// + /// Gets the current indent we use when adding lines to the output + /// + public string CurrentIndent + { + get + { + return this.currentIndentField; + } + } + /// + /// Current transformation session + /// + public virtual global::System.Collections.Generic.IDictionary Session + { + get + { + return this.sessionField; + } + set + { + this.sessionField = value; + } + } + #endregion + #region Transform-time helpers + /// + /// Write text directly into the generated output + /// + public void Write(string textToAppend) + { + if (string.IsNullOrEmpty(textToAppend)) + { + return; + } + // If we're starting off, or if the previous text ended with a newline, + // we have to append the current indent first. + if (((this.GenerationEnvironment.Length == 0) + || this.endsWithNewline)) + { + this.GenerationEnvironment.Append(this.currentIndentField); + this.endsWithNewline = false; + } + // Check if the current text ends with a newline + if (textToAppend.EndsWith(global::System.Environment.NewLine, global::System.StringComparison.CurrentCulture)) + { + this.endsWithNewline = true; + } + // This is an optimization. If the current indent is "", then we don't have to do any + // of the more complex stuff further down. + if ((this.currentIndentField.Length == 0)) + { + this.GenerationEnvironment.Append(textToAppend); + return; + } + // Everywhere there is a newline in the text, add an indent after it + textToAppend = textToAppend.Replace(global::System.Environment.NewLine, (global::System.Environment.NewLine + this.currentIndentField)); + // If the text ends with a newline, then we should strip off the indent added at the very end + // because the appropriate indent will be added when the next time Write() is called + if (this.endsWithNewline) + { + this.GenerationEnvironment.Append(textToAppend, 0, (textToAppend.Length - this.currentIndentField.Length)); + } + else + { + this.GenerationEnvironment.Append(textToAppend); + } + } + /// + /// Write text directly into the generated output + /// + public void WriteLine(string textToAppend) + { + this.Write(textToAppend); + this.GenerationEnvironment.AppendLine(); + this.endsWithNewline = true; + } + /// + /// Write formatted text directly into the generated output + /// + public void Write(string format, params object[] args) + { + this.Write(string.Format(global::System.Globalization.CultureInfo.CurrentCulture, format, args)); + } + /// + /// Write formatted text directly into the generated output + /// + public void WriteLine(string format, params object[] args) + { + this.WriteLine(string.Format(global::System.Globalization.CultureInfo.CurrentCulture, format, args)); + } + /// + /// Raise an error + /// + public void Error(string message) + { + System.CodeDom.Compiler.CompilerError error = new global::System.CodeDom.Compiler.CompilerError(); + error.ErrorText = message; + this.Errors.Add(error); + } + /// + /// Raise a warning + /// + public void Warning(string message) + { + System.CodeDom.Compiler.CompilerError error = new global::System.CodeDom.Compiler.CompilerError(); + error.ErrorText = message; + error.IsWarning = true; + this.Errors.Add(error); + } + /// + /// Increase the indent + /// + public void PushIndent(string indent) + { + if ((indent == null)) + { + throw new global::System.ArgumentNullException("indent"); + } + this.currentIndentField = (this.currentIndentField + indent); + this.indentLengths.Add(indent.Length); + } + /// + /// Remove the last indent that was added with PushIndent + /// + public string PopIndent() + { + string returnValue = ""; + if ((this.indentLengths.Count > 0)) + { + int indentLength = this.indentLengths[(this.indentLengths.Count - 1)]; + this.indentLengths.RemoveAt((this.indentLengths.Count - 1)); + if ((indentLength > 0)) + { + returnValue = this.currentIndentField.Substring((this.currentIndentField.Length - indentLength)); + this.currentIndentField = this.currentIndentField.Remove((this.currentIndentField.Length - indentLength)); + } + } + return returnValue; + } + /// + /// Remove any indentation + /// + public void ClearIndent() + { + this.indentLengths.Clear(); + this.currentIndentField = ""; + } + #endregion + #region ToString Helpers + /// + /// Utility class to produce culture-oriented representation of an object as a string. + /// + public class ToStringInstanceHelper + { + private System.IFormatProvider formatProviderField = global::System.Globalization.CultureInfo.InvariantCulture; + /// + /// Gets or sets format provider to be used by ToStringWithCulture method. + /// + public System.IFormatProvider FormatProvider + { + get + { + return this.formatProviderField ; + } + set + { + if ((value != null)) + { + this.formatProviderField = value; + } + } + } + /// + /// This is called from the compile/run appdomain to convert objects within an expression block to a string + /// + public string ToStringWithCulture(object objectToConvert) + { + if ((objectToConvert == null)) + { + throw new global::System.ArgumentNullException("objectToConvert"); + } + System.Type t = objectToConvert.GetType(); + System.Reflection.MethodInfo method = t.GetMethod("ToString", new System.Type[] { + typeof(System.IFormatProvider)}); + if ((method == null)) + { + return objectToConvert.ToString(); + } + else + { + return ((string)(method.Invoke(objectToConvert, new object[] { + this.formatProviderField }))); + } + } + } + private ToStringInstanceHelper toStringHelperField = new ToStringInstanceHelper(); + /// + /// Helper to produce culture-oriented representation of an object as a string + /// + public ToStringInstanceHelper ToStringHelper + { + get + { + return this.toStringHelperField; + } + } + #endregion + } + #endregion +} diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceAttributeTemplate.tt b/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceAttributeTemplate.tt new file mode 100644 index 000000000..604d0e2e2 --- /dev/null +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceAttributeTemplate.tt @@ -0,0 +1,15 @@ +<#@ template visibility="internal" #> +[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "<#=JsonSchema4.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; } +} \ 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 7123d3fea..0b4ae0363 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceConverterTemplate.Extensions.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceConverterTemplate.Extensions.cs @@ -6,18 +6,16 @@ // Rico Suter, mail@rsuter.com //----------------------------------------------------------------------- -using NJsonSchema.CodeGeneration.CSharp.Models; - namespace NJsonSchema.CodeGeneration.CSharp.Templates { internal partial class JsonInheritanceConverterTemplate : ITemplate { - public JsonInheritanceConverterTemplate(JsonInheritanceConverterTemplateModel model) + public JsonInheritanceConverterTemplate(object model) { Model = model; } - public JsonInheritanceConverterTemplateModel Model { get; } + public object Model { get; } public string Render() { diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceConverterTemplate.cs b/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceConverterTemplate.cs index 6a59ced52..6ce2597a9 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceConverterTemplate.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceConverterTemplate.cs @@ -25,50 +25,9 @@ internal partial class JsonInheritanceConverterTemplate : JsonInheritanceConvert /// public virtual string TransformText() { - - #line 2 "C:\Data\Projects\NJsonSchema\src\NJsonSchema.CodeGeneration.CSharp\Templates\JsonInheritanceConverterTemplate.tt" -if(Model.GenerateJsonInheritanceAttributeClass){ - - #line default - #line hidden - this.Write("[System.CodeDom.Compiler.GeneratedCode(\"NJsonSchema\", \""); - - #line 3 "C:\Data\Projects\NJsonSchema\src\NJsonSchema.CodeGeneration.CSharp\Templates\JsonInheritanceConverterTemplate.tt" - this.Write(this.ToStringHelper.ToStringWithCulture(JsonSchema4.ToolchainVersion)); - - #line default - #line hidden - this.Write(@""")] -[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; } -} - -"); - - #line 18 "C:\Data\Projects\NJsonSchema\src\NJsonSchema.CodeGeneration.CSharp\Templates\JsonInheritanceConverterTemplate.tt" -} - - #line default - #line hidden - - #line 19 "C:\Data\Projects\NJsonSchema\src\NJsonSchema.CodeGeneration.CSharp\Templates\JsonInheritanceConverterTemplate.tt" -if(Model.GenerateJsonInheritanceConverterClass){ - - #line default - #line hidden this.Write("[System.CodeDom.Compiler.GeneratedCode(\"NJsonSchema\", \""); - #line 20 "C:\Data\Projects\NJsonSchema\src\NJsonSchema.CodeGeneration.CSharp\Templates\JsonInheritanceConverterTemplate.tt" + #line 2 "C:\Data\Projects\NJsonSchema\src\NJsonSchema.CodeGeneration.CSharp\Templates\JsonInheritanceConverterTemplate.tt" this.Write(this.ToStringHelper.ToStringWithCulture(JsonSchema4.ToolchainVersion)); #line default @@ -108,13 +67,7 @@ public JsonInheritanceAttribute(string key, System.Type type) "tCustomAttributes(System.Reflection.IntrospectionExten" + "sions.GetTypeInfo(objectType), false))\r\n {\r\n if (type.Key == d" + "iscriminator)\r\n return type.Type;\r\n }\r\n\r\n return ob" + - "jectType;\r\n }\r\n}\r\n"); - - #line 121 "C:\Data\Projects\NJsonSchema\src\NJsonSchema.CodeGeneration.CSharp\Templates\JsonInheritanceConverterTemplate.tt" -} - - #line default - #line hidden + "jectType;\r\n }\r\n}"); return this.GenerationEnvironment.ToString(); } } diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceConverterTemplate.tt b/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceConverterTemplate.tt index ec7b51fb7..94ca75521 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceConverterTemplate.tt +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/JsonInheritanceConverterTemplate.tt @@ -1,22 +1,4 @@ <#@ template visibility="internal" #> -<#if(Model.GenerateJsonInheritanceAttributeClass){#> -[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "<#=JsonSchema4.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; } -} - -<#}#> -<#if(Model.GenerateJsonInheritanceConverterClass){#> [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "<#=JsonSchema4.ToolchainVersion#>")] internal class JsonInheritanceConverter : Newtonsoft.Json.JsonConverter { @@ -117,5 +99,4 @@ internal class JsonInheritanceConverter : Newtonsoft.Json.JsonConverter return objectType; } -} -<#}#> \ No newline at end of file +} \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/Class.Property.Annotations.liquid b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/Class.Property.Annotations.liquid new file mode 100644 index 000000000..5f282702b --- /dev/null +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/Class.Property.Annotations.liquid @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/Class.liquid b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/Class.liquid index 816152c32..9c9317226 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/Class.liquid +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/Class.liquid @@ -8,7 +8,7 @@ {%- endfor -%} {%- endif -%} [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "{{ToolchainVersion}}")] -{% template Annotations -%} +{% template Annotations %} {{ TypeAccessModifier }} partial class {{ClassName}} {{InheritanceCode}} { {%- if RenderInpc -%} @@ -40,6 +40,7 @@ {%- if(property.IsDate -%} [Newtonsoft.Json.JsonConverter(typeof(DateFormatConverter))] {%- endif -%} + {% template Property.Annotations %} public {{ property.Type }} {{ property.PropertyName }}{% if RenderInpc == false %} { get; {% if property.HasSetter %}set; {% endif %}}{% if property.HasDefaultValue %} = {{ property.DefaultValue }};{% endif %}{% else %} { get { return {{ property.FieldName }}; } diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/DateFormatConverter.liquid b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/DateFormatConverter.liquid index 612652bfc..0186ad4fe 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/DateFormatConverter.liquid +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/DateFormatConverter.liquid @@ -1,10 +1,8 @@ -{%- if GenerateDateFormatConverterClass -%} -[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "{{ ToolchainVersion }}")] +[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 +} \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/JsonInheritanceAttribute.liquid b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/JsonInheritanceAttribute.liquid new file mode 100644 index 000000000..09a6e67a1 --- /dev/null +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/JsonInheritanceAttribute.liquid @@ -0,0 +1,14 @@ +[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; } +} \ 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 index 80223b4f9..91ed977ac 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/JsonInheritanceConverter.liquid +++ b/src/NJsonSchema.CodeGeneration.CSharp/Templates/Liquid/JsonInheritanceConverter.liquid @@ -1,22 +1,4 @@ -{%- 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 }}")] +[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "{{ ToolchainVersion }}")] internal class JsonInheritanceConverter : Newtonsoft.Json.JsonConverter { internal static readonly string DefaultDiscriminatorName = "discriminator"; @@ -116,5 +98,4 @@ internal class JsonInheritanceConverter : Newtonsoft.Json.JsonConverter return objectType; } -} -{%- endif -%} \ No newline at end of file +} \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.Tests/DefaultValueGeneratorTests.cs b/src/NJsonSchema.CodeGeneration.Tests/DefaultValueGeneratorTests.cs index e85132cea..6c4cfa240 100644 --- a/src/NJsonSchema.CodeGeneration.Tests/DefaultValueGeneratorTests.cs +++ b/src/NJsonSchema.CodeGeneration.Tests/DefaultValueGeneratorTests.cs @@ -14,10 +14,10 @@ public class DefaultValueGeneratorTests public void Init() { var csharpSettings = new CSharpGeneratorSettings(); - _csharpGenerator = new CSharpValueGenerator(new CSharpTypeResolver(csharpSettings, new object()), csharpSettings); + _csharpGenerator = new CSharpValueGenerator(new CSharpTypeResolver(csharpSettings), csharpSettings); var typescriptSettings = new TypeScriptGeneratorSettings(); - _typescriptGenerator = new TypeScriptValueGenerator(new TypeScriptTypeResolver(typescriptSettings, new object()), typescriptSettings); + _typescriptGenerator = new TypeScriptValueGenerator(new TypeScriptTypeResolver(typescriptSettings), typescriptSettings); } [TestMethod] @@ -128,10 +128,10 @@ public void When_schema_has_default_value_of_enum_it_is_generated_in_CSharp_and_ { //// Arrange var csharpSettings = new CSharpGeneratorSettings { EnumNameGenerator = new MyEnumNameGenerator(), Namespace = "Ns" }; - var csharpGenerator = new CSharpValueGenerator(new CSharpTypeResolver(csharpSettings, new object()), csharpSettings); + var csharpGenerator = new CSharpValueGenerator(new CSharpTypeResolver(csharpSettings), csharpSettings); var typescriptSettings = new TypeScriptGeneratorSettings { EnumNameGenerator = new MyEnumNameGenerator() }; - var typescriptGenerator = new TypeScriptValueGenerator(new TypeScriptTypeResolver(typescriptSettings, new object()), typescriptSettings); + var typescriptGenerator = new TypeScriptValueGenerator(new TypeScriptTypeResolver(typescriptSettings), typescriptSettings); //// Act var schema = new JsonSchema4() diff --git a/src/NJsonSchema.CodeGeneration.Tests/TypeScript/ClassOrderTests.cs b/src/NJsonSchema.CodeGeneration.Tests/TypeScript/ClassOrderTests.cs index ff4f92ca5..1a6a2f569 100644 --- a/src/NJsonSchema.CodeGeneration.Tests/TypeScript/ClassOrderTests.cs +++ b/src/NJsonSchema.CodeGeneration.Tests/TypeScript/ClassOrderTests.cs @@ -13,33 +13,12 @@ public void When_class_order_is_wrong_then_classes_are_correctly_reordered() //// Arrange var classes = new List { - new CodeArtifact - { - TypeName = "Car" - }, - new CodeArtifact - { - TypeName = "Apple", - BaseTypeName = "Fruit" - }, - new CodeArtifact - { - TypeName = "Professor", - BaseTypeName = "Teacher" - }, - new CodeArtifact - { - TypeName = "Teacher", - BaseTypeName = "Person" - }, - new CodeArtifact - { - TypeName = "Fruit" - }, - new CodeArtifact - { - TypeName = "Person" - } + new CodeArtifact("Car", CodeArtifactType.Class, CodeArtifactLanguage.CSharp), + new CodeArtifact("Apple", "Fruit", CodeArtifactType.Class, CodeArtifactLanguage.CSharp), + new CodeArtifact("Professor", "Teacher", CodeArtifactType.Class, CodeArtifactLanguage.CSharp), + new CodeArtifact("Teacher", "Person", CodeArtifactType.Class, CodeArtifactLanguage.CSharp), + new CodeArtifact("Fruit", CodeArtifactType.Class, CodeArtifactLanguage.CSharp), + new CodeArtifact("Person", CodeArtifactType.Class, CodeArtifactLanguage.CSharp) }; //// Act diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/Models/ClassTemplateModel.cs b/src/NJsonSchema.CodeGeneration.TypeScript/Models/ClassTemplateModel.cs index 46bdc8298..9fc494899 100644 --- a/src/NJsonSchema.CodeGeneration.TypeScript/Models/ClassTemplateModel.cs +++ b/src/NJsonSchema.CodeGeneration.TypeScript/Models/ClassTemplateModel.cs @@ -60,9 +60,6 @@ public ClassTemplateModel(string typeName, string discriminatorName, /// Gets the description. public string Description => ConversionUtilities.RemoveLineBreaks(_schema.Description); - /// Gets the inherited schema. - public JsonSchema4 InheritedSchema => _schema.InheritedSchema?.ActualSchema; - /// Gets a value indicating whether this class has a parent class. public bool HasInheritance => InheritedSchema != null && !InheritedSchema.IsDictionary; @@ -124,5 +121,8 @@ public string IndexerPropertyValueType public List Properties => _schema.ActualProperties.Values .Where(v => v.IsInheritanceDiscriminator == false) .Select(property => new PropertyModel(this, property, ClassName, _resolver, _settings)).ToList(); + + /// Gets the inherited schema. + private JsonSchema4 InheritedSchema => _schema.InheritedSchema?.ActualSchema; } } \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/NJsonSchema.CodeGeneration.TypeScript.csproj b/src/NJsonSchema.CodeGeneration.TypeScript/NJsonSchema.CodeGeneration.TypeScript.csproj index 1c2037367..dab9334d2 100644 --- a/src/NJsonSchema.CodeGeneration.TypeScript/NJsonSchema.CodeGeneration.TypeScript.csproj +++ b/src/NJsonSchema.CodeGeneration.TypeScript/NJsonSchema.CodeGeneration.TypeScript.csproj @@ -2,7 +2,7 @@ netstandard1.3;net451 JSON Schema draft v4 reader, generator and validator for .NET - 9.8.3 + 9.9.0 json schema validation generator .net Copyright © Rico Suter, 2017 https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md @@ -21,6 +21,20 @@ true + + + + + + + + + + + + + + diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/Templates/Liquid/Class.liquid b/src/NJsonSchema.CodeGeneration.TypeScript/Templates/Liquid/Class.liquid new file mode 100644 index 000000000..c630297db --- /dev/null +++ b/src/NJsonSchema.CodeGeneration.TypeScript/Templates/Liquid/Class.liquid @@ -0,0 +1,155 @@ +{%- if HasDescription -%} +/** {{ Description }} */ +{%- endif -%} +export class {{ ClassName }}{{ Inheritance }} { +{%- for property in Properties -%} +{%- if property.HasDescription -%} + /** {{ property.Description }} */ +{%- endif -%} + {% if property.IsReadOnly %}readonly {% endif %}{{ property.PropertyName }}{% if property.IsOptional %}?{% endif %}: {{ property.Type }}{{ property.TypePostfix }}{% if property.HasDefaultValue %} = {{ property.DefaultValue }}{% endif %}; +{%- endfor -%} +{%- if HasIndexerProperty -%} + + [key: string]: {{ IndexerPropertyValueType }}; +{%- endif -%} +{%- if HasDiscriminator -%} + + protected _discriminator: string; +{%- endif -%} + +{%- if GenerateConstructorInterface or Model.HasBaseDiscriminator -%} + constructor({% if GenerateConstructorInterface %}data?: I{{ ClassName }}{% endif %}) { +{%- if HasInheritance -%} + super({% if GenerateConstructorInterface %}data{% endif %}); +{%- elseif GenerateConstructorInterface -%} + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } +{%- if ConvertConstructorInterfaceData -%} +{%- for property in Properties -%} +{%- if property.SupportsConstructorConversion -%} +{%- if property.IsArray -%} + if (data.{{ property.PropertyName }}) { + this.{{ property.PropertyName }} = []; + for (let i = 0; i < data.{{ property.PropertyName }}.length; i++) { + let item = data.{{ property.PropertyName }}[i]; + this.{{ property.PropertyName }}[i] = item && !(item).toJSON ? new {{ property.ArrayItemType }}(item) : <{{ property.ArrayItemType }}>item; + } + } +{%- elseif property.IsDictionary -%} + if (data.{{ property.PropertyName }}) { + this.{{ property.PropertyName }} = {}; + for (let key in data.{{ property.PropertyName }}) { + if (data.{{ property.PropertyName }}.hasOwnProperty(key)) { + let item = data.{{ property.PropertyName }}[key]; + this.{{ property.PropertyName }}[key] = item && !(item).toJSON ? new {{ property.DictionaryItemType }}(item) : <{{ property.DictionaryItemType }}>item; + } + } + } +{%- else -%} + this.{{ property.PropertyName }} = data.{{ property.PropertyName }} && !(data.{{ property.PropertyName }}).toJSON ? new {{ property.Type }}(data.{{ property.PropertyName }}) : <{{ property.Type }}>this.{{ property.PropertyName }}; +{%- endif -%} +{%- endif -%} +{%- endfor -%} +{%- endif -%} + } +{%- endif -%} +{%- if HasBaseDiscriminator -%} + this._discriminator = "{{ DiscriminatorName }}"; +{%- endif -%} + } +{%- endif -%} + + init(data?: any{% if HandleReferences %}, _mappings?: any{% endif %}) { +{%- if HasInheritance -%} + super.init(data); +{%- endif -%} + if (data) { +{%- if HasIndexerProperty -%} + for (var property in data) { + if (data.hasOwnProperty(property)) + this[property] = data[property]; + } +{%- endif -%} +{%- for property in Properties -%} + {{ property.ConvertToClassCode | tab: 3 }} +{%- endfor -%} + } + } + + static fromJS(data: any{% if HandleReferences %}, _mappings?: any{% endif %}): {{ ClassName }} { +{%- if HandleReferences -%} +{%- if HasBaseDiscriminator -%} +{%- for derivedClass in DerivedClasses -%} + if (data["{{ BaseDiscriminator }}"] === "{{ derivedClass.Key }}") + return createInstance<{{ derivedClass.Value }}>(data, _mappings, {{ derivedClass.Value }}); +{%- endfor -%} + return createInstance<{{ ClassName }}>(data, _mappings, {{ ClassName }}); +{%- else -%} + return createInstance<{{ ClassName }}>(data, _mappings, {{ ClassName }}); +{%- endif -%} +{%- else -%} +{%- if HasBaseDiscriminator -%} +{%- for derivedClass in DerivedClasses -%} + if (data["{{ BaseDiscriminator }}"] === "{{ derivedClass.Key }}") { + let result = new {{ derivedClass.Value }}(); + result.init(data); + return result; + } +{%- endfor -%} +{%- endif -%} + let result = new {{ ClassName }}(); + result.init(data); + return result; +{%- endif -%} + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; +{%- if HasIndexerProperty -%} + for (var property in this) { + if (this.hasOwnProperty(property)) + data[property] = this[property]; + } +{%- endif -%} +{%- if HasDiscriminator -%} + data["{{ BaseDiscriminator }}"] = this._discriminator; +{%- endif -%} +{%- for property in Properties -%} + {{ property.ConvertToJavaScriptCode | tab: 2 }} +{%- endfor -%} +{%- if HasInheritance -%} + super.toJSON(data); +{%- endif -%} + return data; + } +{%- if GenerateCloneMethod -%} + + clone() { + const json = this.toJSON(); + let result = new {{ ClassName }}(); + result.init(json); + return result; + } +{%- endif -%} +} +{%- if GenerateConstructorInterface -%} + +{%- if HasDescription -%} +/** {{ Description }} */ +{%- endif -%} +export interface I{{ ClassName }}{{ InterfaceInheritance }} { +{%- for property in Properties -%} +{%- if property.HasDescription -%} + /** {{ property.Description }} */ +{%- endif -%} + {{ property.PropertyName }}{% if property.IsOptional %}?{% endif %}: {{ property.ConstructorInterfaceType }}{{ property.TypePostfix }}; +{%- endfor -%} +{%- if HasIndexerProperty -%} + + [key: string]: {{ IndexerPropertyValueType }}; +{%- endif -%} +} +{%- endif -%} \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/Templates/Liquid/ConvertToClass.Liquid b/src/NJsonSchema.CodeGeneration.TypeScript/Templates/Liquid/ConvertToClass.Liquid new file mode 100644 index 000000000..b271ef78b --- /dev/null +++ b/src/NJsonSchema.CodeGeneration.TypeScript/Templates/Liquid/ConvertToClass.Liquid @@ -0,0 +1,47 @@ +{%- if IsNewableObject -%} +{{ Variable }} = {{ Value }} ? {{ Type }}.fromJS({{ Value }}{% if HandleReferences -%}, _mappings{% endif %}) : {% if HasDefaultValue %}{{ DefaultValue }}{% else %}{{ NullValue }}{% endif %}; +{%- elseif IsArray -%} +if ({{ Value }} && {{ Value }}.constructor === Array) { + {{ Variable }} = []; + for (let item of {{ Value }}) +{%- if IsArrayItemNewableObject -%} + {{ Variable }}.push({{ ArrayItemType }}.fromJS(item{% if HandleReferences %}, _mappings{% endif %})); +{%- else -%} +{%- if IsArrayItemDate or IsArrayItemDateTime -%} + {{ Variable }}.push({{ StringToDateCode }}(item)); +{%- else -%} + {{ Variable }}.push(item); +{%- endif -%} +{%- endif -%} +} +{%- elseif IsDictionary -%} +if ({{ Value }}) { + {{ Variable }} = {}; + for (let key in {{ Value }}) { + if ({{ Value }}.hasOwnProperty(key)) +{%- if IsDictionaryValueNewableObject -%} + {{ Variable }}[key] = {{ Value }}[key] ? {{ DictionaryValueType }}.fromJS({{ Value }}[key]{% if HandleReferences %}, _mappings{% endif %}) : {% if HasDictionaryValueDefaultValue %}{{ DictionaryValueDefaultValue }}{% else %}{{ NullValue }}{% endif %}; +{%- elseif IsDictionaryValueNewableArray -%} + {{ Variable }}[key] = {{ Value }}[key] ? {{ Value }}[key].map((i: any) => {{ DictionaryValueArrayItemType }}.fromJS(i{% if HandleReferences %}, _mappings{% endif %})) : {% if HasDictionaryValueDefaultValue %}{{ DictionaryValueDefaultValue }}{% else %}{{ NullValue }}{% endif %}; +{%- elseif IsDictionaryValueDate or Model.IsDictionaryValueDateTime -%} + {{ Variable }}[key] = {{ Value }}[key] ? {{ StringToDateCode }}({{ Value }}[key].toString()) : {% if HasDictionaryValueDefaultValue %}{{ DictionaryValueDefaultValue }}{% else %}{{ NullValue }}{% endif %}; +{%- else -%} +{%- if(Model.HasDictionaryValueDefaultValue || Model.NullValue != "undefined"){ -%} + {{ Variable }}[key] = {{ Value }}[key] !== undefined ? {{ Value }}[key] : {% if HasDictionaryValueDefaultValue %}{{ DictionaryValueDefaultValue }}{% else %}{{ NullValue }}{% endif %}; +{%- else -%} + {{ Variable }}[key] = {{ Value }}[key]; +{%- endif -%} +{%- endif -%} + } +} +{%- else -%} + {%- if IsDate or IsDateTime -%} +{{ Variable }} = {{ Value }} ? {{ StringToDateCode }}({{ Value }}.toString()) : {% if HasDefaultValue %}{{ StringToDateCode }}({{ DefaultValue }}){% else %}{{ NullValue }}{% endif %}; + {%- else -%} +{%- if HasDefaultValue or NullValue != "undefined" -%} +{{ Variable }} = {{ Value }} !== undefined ? {{ Value }} : {% if HasDefaultValue %}{{ DefaultValue }}{% else %}{{ NullValue }}{% endif %}; +{%- else -%} +{{ Variable }} = {{ Value }}; +{%- endif -%} + {%- endif -%} +{%- endif -%} \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/Templates/Liquid/ConvertToJavaScriptTemplate.liquid b/src/NJsonSchema.CodeGeneration.TypeScript/Templates/Liquid/ConvertToJavaScriptTemplate.liquid new file mode 100644 index 000000000..22fd4c51a --- /dev/null +++ b/src/NJsonSchema.CodeGeneration.TypeScript/Templates/Liquid/ConvertToJavaScriptTemplate.liquid @@ -0,0 +1,45 @@ +{%- if IsNewableObject -%} +{{ Variable }} = {{ Value }} ? {{ Value }}.toJSON() : {{ NullValue }}; +{%- elseif IsArray -%} +if ({{ Value }} && {{ Value }}.constructor === Array) { + {{ Variable }} = []; + for (let item of {{ Value }}) +{%- if IsArrayItemNewableObject -%} + {{ Variable }}.push(item.toJSON()); +{%- elseif IsArrayItemDate -%} + {{ Variable }}.push(item.{{ DateToStringCode }}); +{%- elseif IsArrayItemDateTime -%} + {{ Variable }}.push(item.{{ DateTimeToStringCode }}); +{%- else -%} + {{ Variable }}.push(item); +{%- endif -%} +} +{%- elseif IsDictionary -%} +if ({{ Value }}) { + {{ Variable }} = {}; + for (let key in {{ Value }}) { + if ({{ Value }}.hasOwnProperty(key)) +{%- if IsDictionaryValueNewableObjec -%} + {{ Variable }}[key] = {{ Value }}[key] ? {{ Value }}[key].toJSON() : {{ NullValue }}; +{%- elseif IsDictionaryValueDate -%} + {{ Variable }}[key] = {{ Value }}[key] ? {{ Value }}[key].{{ DateToStringCode }} : {{ NullValue }}; +{%- elseif IsDictionaryValueDateTime -%} + {{ Variable }}[key] = {{ Value }}[key] ? {{ Value }}[key].{{ DateTimeToStringCode }} : {{ NullValue }}; +{%- else -%} +{%- if NullValue != "undefined" -%} + {{ Variable }}[key] = {{ Value }}[key] !== undefined ? {{ Value }}[key] : {{ NullValue }}; +{%- else -%} + {{ Variable }}[key] = {{ Value }}[key]; +{%- endif -%} +{%- endif -%} + } +} +{%- elseif IsDate -%} +{{ Variable }} = {{ Value }} ? {{ Value }}.{{ DateToStringCode }} : {% if HasDefaultValue -%}{{ DefaultValue }}{% else %}{{ NullValue }}{% endif %}; +{%- elseif IsDateTime -%} +{{ Variable }} = {{ Value }} ? {{ Value }}.{{ DateTimeToStringCode }} : {% if HasDefaultValue %}{{ DefaultValue }}{% else %}{{ NullValue }}{% endif %}; +{%- elseif NullValue != "undefined" -%} +{{ Variable }} = {{ Value }} !== undefined ? {{ Value }} : {{ NullValue }}; +{%- else -%} +{{ Variable }} = {{ Value }}; +{%- endif -%} \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/Templates/Liquid/Enum.liquid b/src/NJsonSchema.CodeGeneration.TypeScript/Templates/Liquid/Enum.liquid new file mode 100644 index 000000000..991db6374 --- /dev/null +++ b/src/NJsonSchema.CodeGeneration.TypeScript/Templates/Liquid/Enum.liquid @@ -0,0 +1,8 @@ +{%- if HasDescription -%} +/** {{ Description }} */ +{%- endif -%} +export enum {{ Name }} { +{%- for enumeration in Enums -%} + {{ enumeration.Name }} = {{ enumeration.Value }}, +{%- endfor -%} +} \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptGenerator.cs b/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptGenerator.cs index d2208ec18..c2e6e0f3a 100644 --- a/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptGenerator.cs +++ b/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptGenerator.cs @@ -6,14 +6,14 @@ // Rico Suter, mail@rsuter.com //----------------------------------------------------------------------- +using System; using NJsonSchema.CodeGeneration.TypeScript.Models; namespace NJsonSchema.CodeGeneration.TypeScript { /// The TypeScript interface and enum code generator. - public class TypeScriptGenerator : TypeGeneratorBase + public class TypeScriptGenerator : GeneratorBase { - private readonly JsonSchema4 _schema; private readonly TypeScriptTypeResolver _resolver; /// Initializes a new instance of the class. @@ -24,22 +24,20 @@ public TypeScriptGenerator(JsonSchema4 schema) } /// Initializes a new instance of the class. + /// The root object to search for all JSON Schemas. /// The generator settings. - /// The schema. - public TypeScriptGenerator(JsonSchema4 schema, TypeScriptGeneratorSettings settings) - : this(schema, settings, new TypeScriptTypeResolver(settings, schema), null) + public TypeScriptGenerator(object rootObject, TypeScriptGeneratorSettings settings) + : this(rootObject, settings, new TypeScriptTypeResolver(settings)) { } /// Initializes a new instance of the class. - /// The schema. + /// The root object to search for all JSON Schemas. /// The generator settings. /// The resolver. - /// The root object to search for all JSON Schemas. - public TypeScriptGenerator(JsonSchema4 schema, TypeScriptGeneratorSettings settings, TypeScriptTypeResolver resolver, object rootObject) - : base(schema, rootObject) + public TypeScriptGenerator(object rootObject, TypeScriptGeneratorSettings settings, TypeScriptTypeResolver resolver) + : base(rootObject, resolver, settings) { - _schema = schema; _resolver = resolver; Settings = settings; } @@ -47,18 +45,49 @@ public TypeScriptGenerator(JsonSchema4 schema, TypeScriptGeneratorSettings setti /// Gets the generator settings. public TypeScriptGeneratorSettings Settings { get; } + /// Generates all types from the resolver with extension code from the settings. + /// The code. + public override CodeArtifactCollection GenerateTypes() + { + return GenerateTypes(new TypeScriptExtensionCode(Settings.ExtensionCode, Settings.ExtendedClasses)); + } + + /// Generates all types from the resolver with the given extension code. + /// The code. + public CodeArtifactCollection GenerateTypes(ExtensionCode extensionCode) + { + var collection = base.GenerateTypes(); + + foreach (var artifact in collection.Artifacts) + { + if (extensionCode?.ExtensionClasses.ContainsKey(artifact.TypeName) == true) + { + var classCode = artifact.Code; + + var index = classCode.IndexOf("constructor(", StringComparison.Ordinal); + if (index != -1) + artifact.Code = classCode.Insert(index, extensionCode.GetExtensionClassBody(artifact.TypeName).Trim() + "\n\n "); + else + { + index = classCode.IndexOf("class", StringComparison.Ordinal); + index = classCode.IndexOf("{", index, StringComparison.Ordinal) + 1; + + artifact.Code = classCode.Insert(index, "\n " + extensionCode.GetExtensionClassBody(artifact.TypeName).Trim() + "\n"); + } + } + } + + return new CodeArtifactCollection(collection.Artifacts, extensionCode); + } + /// Generates the file. - /// The root type name hint. /// The file contents. - public override string GenerateFile(string rootTypeNameHint) + protected override string GenerateFile(CodeArtifactCollection artifactCollection) { - _resolver.Resolve(_schema, false, rootTypeNameHint); // register root type - - var extensionCode = new TypeScriptExtensionCode(Settings.ExtensionCode, Settings.ExtendedClasses); var model = new FileTemplateModel(Settings) { - Types = ConversionUtilities.TrimWhiteSpaces(_resolver.GenerateTypes().Concatenate()), - ExtensionCode = extensionCode + Types = artifactCollection.Concatenate(), + ExtensionCode = (TypeScriptExtensionCode)artifactCollection.ExtensionCode }; var template = Settings.TemplateFactory.CreateTemplate("TypeScript", "File", model); @@ -66,40 +95,29 @@ public override string GenerateFile(string rootTypeNameHint) } /// Generates the type. + /// The schema. /// The fallback type name. /// The code. - public override CodeArtifact GenerateType(string typeNameHint) + protected override CodeArtifact GenerateType(JsonSchema4 schema, string typeNameHint) { - var typeName = _resolver.GetOrGenerateTypeName(_schema, typeNameHint); + var typeName = _resolver.GetOrGenerateTypeName(schema, typeNameHint); - if (_schema.IsEnumeration) + if (schema.IsEnumeration) { - var model = new EnumTemplateModel(typeName, _schema, Settings); + var model = new EnumTemplateModel(typeName, schema, Settings); var template = Settings.TemplateFactory.CreateTemplate("TypeScript", "Enum", model); - return new CodeArtifact - { - Type = CodeArtifactType.Enum, - Language = CodeArtifactLanguage.TypeScript, - - TypeName = typeName, - Code = template.Render() - }; + return new CodeArtifact(typeName, CodeArtifactType.Enum, CodeArtifactLanguage.TypeScript, template); } else { - var model = new ClassTemplateModel(typeName, typeNameHint, Settings, _resolver, _schema, RootObject); + var model = new ClassTemplateModel(typeName, typeNameHint, Settings, _resolver, schema, RootObject); var template = Settings.CreateTemplate(typeName, model); - return new CodeArtifact - { - Type = Settings.TypeStyle == TypeScriptTypeStyle.Interface ? - CodeArtifactType.Interface : CodeArtifactType.Class, - Language = CodeArtifactLanguage.TypeScript, - TypeName = typeName, - BaseTypeName = model.BaseClass, + var type = Settings.TypeStyle == TypeScriptTypeStyle.Interface + ? CodeArtifactType.Interface + : CodeArtifactType.Class; - Code = template.Render() - }; + return new CodeArtifact(typeName, model.BaseClass, type, CodeArtifactLanguage.TypeScript, template); } } } diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptTypeResolver.cs b/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptTypeResolver.cs index a33a0b873..a59b8bfa8 100644 --- a/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptTypeResolver.cs +++ b/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptTypeResolver.cs @@ -12,22 +12,18 @@ namespace NJsonSchema.CodeGeneration.TypeScript { /// Manages the generated types and converts JSON types to TypeScript types. - public class TypeScriptTypeResolver : TypeResolverBase + public class TypeScriptTypeResolver : TypeResolverBase { - private readonly object _rootObject; - /// Initializes a new instance of the class. /// The settings. - /// The root object to search for JSON Schemas. - public TypeScriptTypeResolver(TypeScriptGeneratorSettings settings, object rootObject) + public TypeScriptTypeResolver(TypeScriptGeneratorSettings settings) : base(settings) { - _rootObject = rootObject; Settings = settings; } /// Gets the generator settings. - public TypeScriptGeneratorSettings Settings { get; private set; } + public TypeScriptGeneratorSettings Settings { get; } /// Gets or sets the namespace of the generated classes. public string Namespace { get; set; } @@ -54,47 +50,6 @@ public override string Resolve(JsonSchema4 schema, bool isNullable, string typeN return Resolve(schema, typeNameHint, false); } - /// Creates a type generator. - /// The schema. - /// The generator. - protected override TypeScriptGenerator CreateTypeGenerator(JsonSchema4 schema) - { - return new TypeScriptGenerator(schema, Settings, this, _rootObject); - } - - /// - public override CodeArtifactCollection GenerateTypes() - { - var extensionCode = new TypeScriptExtensionCode(Settings.ExtensionCode, Settings.ExtendedClasses); - return GenerateTypes(extensionCode); - } - - /// - public override CodeArtifactCollection GenerateTypes(ExtensionCode extensionCode) - { - var collection = base.GenerateTypes(extensionCode); - foreach (var artifact in collection.Artifacts) - { - if (extensionCode.ExtensionClasses.ContainsKey(artifact.TypeName) == true) - { - var classCode = artifact.Code; - - var index = classCode.IndexOf("constructor(", StringComparison.Ordinal); - if (index != -1) - artifact.Code = classCode.Insert(index, extensionCode.GetExtensionClassBody(artifact.TypeName).Trim() + "\n\n "); - else - { - index = classCode.IndexOf("class", StringComparison.Ordinal); - index = classCode.IndexOf("{", index, StringComparison.Ordinal) + 1; - - artifact.Code = classCode.Insert(index, "\n " + extensionCode.GetExtensionClassBody(artifact.TypeName).Trim() + "\n"); - } - } - } - - return collection; - } - private string Resolve(JsonSchema4 schema, string typeNameHint, bool addInterfacePrefix) { if (schema == null) @@ -138,7 +93,7 @@ private string Resolve(JsonSchema4 schema, string typeNameHint, bool addInterfac return $"{{ [key: string] : {valueType}; }}"; } - return (addInterfacePrefix ? "I" : "") + AddGenerator(schema, typeNameHint); + return (addInterfacePrefix ? "I" : "") + GetOrGenerateTypeName(schema, typeNameHint); } private string ResolveString(JsonSchema4 schema, string typeNameHint) @@ -174,7 +129,7 @@ private string ResolveString(JsonSchema4 schema, string typeNameHint) } if (schema.IsEnumeration) - return AddGenerator(schema, typeNameHint); + return GetOrGenerateTypeName(schema, typeNameHint); return "string"; } @@ -182,7 +137,7 @@ private string ResolveString(JsonSchema4 schema, string typeNameHint) private string ResolveInteger(JsonSchema4 schema, string typeNameHint) { if (schema.IsEnumeration) - return AddGenerator(schema, typeNameHint); + return GetOrGenerateTypeName(schema, typeNameHint); return "number"; } diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptValueGenerator.cs b/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptValueGenerator.cs index 0804d616c..35f943fe6 100644 --- a/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptValueGenerator.cs +++ b/src/NJsonSchema.CodeGeneration.TypeScript/TypeScriptValueGenerator.cs @@ -16,7 +16,7 @@ public class TypeScriptValueGenerator : ValueGeneratorBase /// Initializes a new instance of the class. /// The type resolver. /// The settings - public TypeScriptValueGenerator(ITypeResolver typeResolver, TypeScriptGeneratorSettings settings) + public TypeScriptValueGenerator(TypeResolverBase typeResolver, TypeScriptGeneratorSettings settings) : base(typeResolver, settings.EnumNameGenerator) { } diff --git a/src/NJsonSchema.CodeGeneration/CodeArtifact.cs b/src/NJsonSchema.CodeGeneration/CodeArtifact.cs index e81eb2fbb..2e7d3dc07 100644 --- a/src/NJsonSchema.CodeGeneration/CodeArtifact.cs +++ b/src/NJsonSchema.CodeGeneration/CodeArtifact.cs @@ -11,19 +11,66 @@ namespace NJsonSchema.CodeGeneration /// The type generator result. public class CodeArtifact { - /// Gets or sets the type name. - public string TypeName { get; set; } + /// Initializes a new instance of the class. + /// The type name. + /// The artifact type. + /// The artifact language. + public CodeArtifact(string typeName, CodeArtifactType type, CodeArtifactLanguage language) + : this(typeName, null, type, language, null) + { + } - /// Gets or sets the name of the base type (i.e. the name of the inherited class). - public string BaseTypeName { get; set; } + /// Initializes a new instance of the class. + /// The type name. + /// The base type name (e.g. base class). + /// The artifact type. + /// The artifact language. + public CodeArtifact(string typeName, string baseTypeName, CodeArtifactType type, CodeArtifactLanguage language) + : this(typeName, baseTypeName, type, language, null) + { + BaseTypeName = baseTypeName; + } - /// Gets or sets the generated code. - public string Code { get; set; } + /// Initializes a new instance of the class. + /// The type name. + /// The artifact type. + /// The artifact language. + /// The template to render the code. + public CodeArtifact(string typeName, CodeArtifactType type, CodeArtifactLanguage language, ITemplate template) + : this(typeName, null, type, language, template) + { + } + + /// Initializes a new instance of the class. + /// The type name. + /// The base type name (e.g. base class). + /// The artifact type. + /// The artifact language. + /// The template to render the code. + public CodeArtifact(string typeName, string baseTypeName, CodeArtifactType type, CodeArtifactLanguage language, ITemplate template) + { + TypeName = typeName; + BaseTypeName = baseTypeName; + + Type = type; + Language = language; + + Code = template?.Render(); + } - /// Gets or sets the artifact type. - public CodeArtifactType Type { get; set; } + /// Gets the type name. + public string TypeName { get; } - /// Get or sets the artifact language. - public CodeArtifactLanguage Language { get; set; } + /// Gets the name of the base type (i.e. the name of the inherited class). + public string BaseTypeName { get; } + + /// Gets the artifact type. + public CodeArtifactType Type { get; } + + /// Get the artifact language. + public CodeArtifactLanguage Language { get; } + + /// Gets or sets the generated code. + public string Code { get; set; } } } \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration/CodeArtifactCollection.cs b/src/NJsonSchema.CodeGeneration/CodeArtifactCollection.cs index f7422cd89..f6e83bd1e 100644 --- a/src/NJsonSchema.CodeGeneration/CodeArtifactCollection.cs +++ b/src/NJsonSchema.CodeGeneration/CodeArtifactCollection.cs @@ -14,21 +14,26 @@ namespace NJsonSchema.CodeGeneration /// public class CodeArtifactCollection { - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// The artifacts. - public CodeArtifactCollection(IEnumerable artifacts) + /// The extension code. + public CodeArtifactCollection(IEnumerable artifacts, ExtensionCode extensionCode) { Artifacts = OrderByBaseDependency(artifacts); + ExtensionCode = extensionCode; } - + /// Gets the artifacts. public IEnumerable Artifacts { get; } - + + /// Gets the extension code. + public ExtensionCode ExtensionCode { get; } + /// Concatenates the results. /// The result. public string Concatenate() { - return string.Join("\n\n", Artifacts.Select(p => p.Code)); + return ConversionUtilities.TrimWhiteSpaces(string.Join("\n\n", Artifacts.Select(p => p.Code))); } /// Reorders the results so that base classes are always before child classes. diff --git a/src/NJsonSchema.CodeGeneration/CodeArtifactLanguage.cs b/src/NJsonSchema.CodeGeneration/CodeArtifactLanguage.cs index d5c0e1755..5db5b884c 100644 --- a/src/NJsonSchema.CodeGeneration/CodeArtifactLanguage.cs +++ b/src/NJsonSchema.CodeGeneration/CodeArtifactLanguage.cs @@ -14,10 +14,13 @@ public enum CodeArtifactLanguage /// Undefined. Undefined, - /// A class. + /// C#. CSharp, - /// A class. - TypeScript + /// TypeScript. + TypeScript, + + /// Html. + Html } } \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration/DefaultTemplateFactory.cs b/src/NJsonSchema.CodeGeneration/DefaultTemplateFactory.cs index 10e8ee5e0..d3fd7f948 100644 --- a/src/NJsonSchema.CodeGeneration/DefaultTemplateFactory.cs +++ b/src/NJsonSchema.CodeGeneration/DefaultTemplateFactory.cs @@ -40,26 +40,11 @@ public virtual ITemplate CreateTemplate(string language, string template, object return CreateT4Template(language, template, model); } - /// Tries to load a Liquid template from an embedded resource. + /// Tries to load a Liquid template. /// 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) - { - using (var reader = new StreamReader(resource)) - return reader.ReadToEnd(); - } - - return null; - } - - private string TryGetLiquidTemplate(string language, string template) + protected virtual string TryGetLiquidTemplate(string language, string template) { if (_settings.UseLiquidTemplates) { @@ -67,7 +52,7 @@ private string TryGetLiquidTemplate(string language, string template) !string.IsNullOrEmpty(_settings.TemplateDirectory) && Directory.Exists(_settings.TemplateDirectory)) { - var templateFilePath = Path.Combine(_settings.TemplateDirectory, language, template + ".liquid"); + var templateFilePath = Path.Combine(_settings.TemplateDirectory, template + ".liquid"); if (File.Exists(templateFilePath)) return File.ReadAllText(templateFilePath); } @@ -77,6 +62,21 @@ private string TryGetLiquidTemplate(string language, string template) return null; } + + private 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) + { + using (var reader = new StreamReader(resource)) + return reader.ReadToEnd(); + } + + return null; + } /// Could not load template.. private ITemplate CreateT4Template(string language, string template, object model) diff --git a/src/NJsonSchema.CodeGeneration/GeneratorBase.cs b/src/NJsonSchema.CodeGeneration/GeneratorBase.cs index 917cdd58d..8130555a7 100644 --- a/src/NJsonSchema.CodeGeneration/GeneratorBase.cs +++ b/src/NJsonSchema.CodeGeneration/GeneratorBase.cs @@ -6,6 +6,8 @@ // Rico Suter, mail@rsuter.com //----------------------------------------------------------------------- +using System.Collections.Generic; +using System.Linq; using System.Text.RegularExpressions; namespace NJsonSchema.CodeGeneration @@ -13,25 +15,87 @@ namespace NJsonSchema.CodeGeneration /// The base class of the code generators public abstract class GeneratorBase { - private readonly JsonSchema4 _schema; + private readonly TypeResolverBase _resolver; + private readonly CodeGeneratorSettingsBase _settings; /// Initializes a new instance of the class. - /// The schema. - protected GeneratorBase(JsonSchema4 schema) + /// The root object. + /// The type resolver. + /// The settings. + protected GeneratorBase(object rootObject, TypeResolverBase typeResolver, CodeGeneratorSettingsBase settings) { - _schema = schema; + RootObject = rootObject; + _resolver = typeResolver; + _settings = settings; + } + + /// Gets the root object. + protected object RootObject { get; } + + /// Generates the the whole file containing all needed types. + /// The code + public string GenerateFile(string typeNameHint) + { + var schema = (JsonSchema4)RootObject; + return GenerateFile(schema, typeNameHint); } /// Generates the the whole file containing all needed types. /// The code public string GenerateFile() { - return GenerateFile(_schema.Title != null && Regex.IsMatch(_schema.Title, "^[a-zA-Z0-9_]*$") ? _schema.Title : null); + var schema = (JsonSchema4)RootObject; + return GenerateFile(schema, schema.Title != null && Regex.IsMatch(schema.Title, "^[a-zA-Z0-9_]*$") ? schema.Title : null); + } + + /// Generates the type from the schema and all types from the resolver. + /// The schema + /// The type name hint. + /// The code. + public CodeArtifactCollection GenerateTypes(JsonSchema4 schema, string typeNameHint) + { + _resolver.Resolve(schema, false, typeNameHint); // register root type + return GenerateTypes(); + } + + /// Generates the the whole file containing all needed types. + /// The code + public string GenerateFile(JsonSchema4 schema, string typeNameHint) + { + var collection = GenerateTypes(schema, typeNameHint); + return GenerateFile(collection); + } + + /// Generates all types from the resolver. + /// The code. + public virtual CodeArtifactCollection GenerateTypes() + { + var processedTypes = new List(); + var types = new Dictionary(); + while (_resolver.Types.Any(t => !processedTypes.Contains(t.Value))) + { + foreach (var pair in _resolver.Types.ToList()) + { + processedTypes.Add(pair.Value); + var result = GenerateType(pair.Key, pair.Value); + types[result.TypeName] = result; + } + } + + var artifacts = types.Values.Where(p => + !_settings.ExcludedTypeNames.Contains(p.TypeName)); + + return new CodeArtifactCollection(artifacts, null); } /// Generates the the whole file containing all needed types. - /// The root type name hint. /// The code - public abstract string GenerateFile(string rootTypeNameHint); + protected abstract string GenerateFile(CodeArtifactCollection artifactCollection); + + /// Generates the type. + /// The schema. + /// The type name hint. + /// The code. + protected abstract CodeArtifact GenerateType(JsonSchema4 schema, string typeNameHint); } } \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration/ITypeResolver.cs b/src/NJsonSchema.CodeGeneration/ITypeResolver.cs deleted file mode 100644 index da1350b41..000000000 --- a/src/NJsonSchema.CodeGeneration/ITypeResolver.cs +++ /dev/null @@ -1,27 +0,0 @@ -//----------------------------------------------------------------------- -// -// Copyright (c) Rico Suter. All rights reserved. -// -// https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md -// Rico Suter, mail@rsuter.com -//----------------------------------------------------------------------- - -namespace NJsonSchema.CodeGeneration -{ - /// The type resolver interface. - public interface ITypeResolver - { - /// Gets or generates the type name for the given schema. - /// The schema. - /// The type name hint. - /// The type name. - string GetOrGenerateTypeName(JsonSchema4 schema, string typeNameHint); - - /// Resolves and possibly generates the specified schema. - /// The schema. - /// Specifies whether the given type usage is nullable. - /// The type name hint to use when generating the type and the type name is missing. - /// The type name. - string Resolve(JsonSchema4 schema, bool isNullable, string typeNameHint); - } -} \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration/JsonSchemaGraphUtilities.cs b/src/NJsonSchema.CodeGeneration/JsonSchemaGraphUtilities.cs index a7c0a1ebf..6c166b84f 100644 --- a/src/NJsonSchema.CodeGeneration/JsonSchemaGraphUtilities.cs +++ b/src/NJsonSchema.CodeGeneration/JsonSchemaGraphUtilities.cs @@ -6,10 +6,9 @@ // Rico Suter, mail@rsuter.com //----------------------------------------------------------------------- -using System.Collections; using System.Collections.Generic; -using System.Linq; -using NJsonSchema.Infrastructure; +using System.Threading.Tasks; +using NJsonSchema.Visitors; namespace NJsonSchema.CodeGeneration { @@ -19,63 +18,33 @@ public static class JsonSchemaGraphUtilities /// Gets the derived schemas. /// The schema. /// The root object. - /// The type resolver. /// - public static IDictionary GetDerivedSchemas(this JsonSchema4 schema, object rootObject, ITypeResolver typeResolver) + public static IDictionary GetDerivedSchemas(this JsonSchema4 schema, object rootObject) { - return FindAllSchemas(rootObject, typeResolver) - .Where(p => p.Value.Inherits(schema)) - .ToDictionary(p => p.Key, p => p.Value); + var visitor = new DerivedSchemaVisitor(schema); + visitor.VisitAsync(rootObject).GetAwaiter().GetResult(); + return visitor.DerivedSchemas; } - /// Finds all schema object in the given object. - /// The root object. - /// The type resolver. - /// The schemas. - public static IDictionary FindAllSchemas(object root, ITypeResolver typeResolver) + private class DerivedSchemaVisitor : JsonSchemaVisitorBase { - var schemas = new Dictionary(); - FindAllSchemas(root, new HashSet(), schemas, typeResolver, null); - return schemas; - } + private readonly JsonSchema4 _baseSchema; - private static void FindAllSchemas(object obj, HashSet checkedObjects, Dictionary schemas, ITypeResolver typeResolver, string typeNameHint) - { - if (obj == null || obj is string || checkedObjects.Contains(obj)) - return; + public Dictionary DerivedSchemas { get; } = new Dictionary(); - var schema = obj as JsonSchema4; - if (schema != null) + public DerivedSchemaVisitor(JsonSchema4 baseSchema) { - schema = schema.ActualSchema; - - if (schema.Type.HasFlag(JsonObjectType.Object) && schemas.Values.All(s => s != schema)) - { - var typeName = typeResolver.GetOrGenerateTypeName(schema, typeNameHint); - schemas.Add(typeName, schema); - } + _baseSchema = baseSchema; } - checkedObjects.Add(obj); - - if (obj is IDictionary) +#pragma warning disable 1998 + protected override async Task VisitSchemaAsync(JsonSchema4 schema, string path, string typeNameHint) +#pragma warning restore 1998 { - foreach (var key in ((IDictionary)obj).Keys) - FindAllSchemas(((IDictionary)obj)[key], checkedObjects, schemas, typeResolver, key as string); - } - else if (obj is IEnumerable) - { - foreach (var item in (IEnumerable)obj) - FindAllSchemas(item, checkedObjects, schemas, typeResolver, null); - } - else - { - foreach (var member in ReflectionCache.GetPropertiesAndFields(obj.GetType()).Where(p => p.CustomAttributes.JsonIgnoreAttribute == null)) - { - var value = member.GetValue(obj); - if (value != null) - FindAllSchemas(value, checkedObjects, schemas, typeResolver, member.MemberInfo.Name); - } + if (schema.Inherits(_baseSchema) && _baseSchema != schema) + DerivedSchemas.Add(schema, typeNameHint); + + return schema; } } } diff --git a/src/NJsonSchema.CodeGeneration/LiquidHash.cs b/src/NJsonSchema.CodeGeneration/LiquidHash.cs index a4161e1a4..923097ae0 100644 --- a/src/NJsonSchema.CodeGeneration/LiquidHash.cs +++ b/src/NJsonSchema.CodeGeneration/LiquidHash.cs @@ -18,7 +18,7 @@ internal class LiquidHash { public static Hash FromObject(object obj) { - return FromObject(obj, new Dictionary()); + return obj != null ? FromObject(obj, new Dictionary()) : new Hash(); } private static Hash FromObject(object obj, Dictionary cache) @@ -30,7 +30,7 @@ private static Hash FromObject(object obj, Dictionary cache) return cache[obj]; var hash = new Hash(); - foreach (var property in obj.GetType().GetRuntimeProperties().Where(p => p.CanRead)) + foreach (var property in obj.GetType().GetRuntimeProperties().Where(p => p.CanRead && p.GetMethod.IsPublic)) { var value = property.GetValue(obj, null); if (value is IEnumerable && !(value is string)) diff --git a/src/NJsonSchema.CodeGeneration/LiquidTemplate.cs b/src/NJsonSchema.CodeGeneration/LiquidTemplate.cs index 93264530d..68e649ac6 100644 --- a/src/NJsonSchema.CodeGeneration/LiquidTemplate.cs +++ b/src/NJsonSchema.CodeGeneration/LiquidTemplate.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text.RegularExpressions; using DotLiquid; @@ -35,8 +36,8 @@ public string Render() { Template.RegisterTag("template"); - var data = Regex.Replace(_data, "(\n(( )*?)\\{% template .*?) %}", m => - m.Groups[1].Value + " " + m.Groups[2].Value.Length / 4 + " %}", + var data = Regex.Replace(_data, "(\n( )*?)\\{% (template .*?) %}", m => + "\n{%- " + m.Groups[3].Value + " " + m.Groups[1].Value.Length / 4 + " -%}", RegexOptions.Singleline); var template = Template.Parse(data); @@ -46,6 +47,9 @@ public string Render() hash[TemplateTag.TemplateKey] = _template; hash[TemplateTag.SettingsKey] = _settings; + if (!hash.ContainsKey("ToolchainVersion")) + hash["ToolchainVersion"] = JsonSchema4.ToolchainVersion; + return template.Render(new RenderParameters { LocalVariables = hash, @@ -74,13 +78,13 @@ internal class TemplateTag : Tag public static string SettingsKey = "__settings"; private string _template; - private int _tab; + private int _tabCount; 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; + _tabCount = parts.Length >= 2 ? int.Parse(parts[1]) : 0; base.Initialize(tagName, markup, tokens); } @@ -98,7 +102,15 @@ public override void Render(Context context, TextWriter result) !string.IsNullOrEmpty(_template) ? (string)hash[TemplateKey] + "." + _template : (string)hash[TemplateKey] + "!", hash); - result.Write(ConversionUtilities.Tab(template.Render(), _tab)); + var output = template.Render(); + + if (string.IsNullOrEmpty(output)) + result.Write(""); + else + { + result.Write(string.Join("", Enumerable.Repeat(" ", _tabCount)) + + ConversionUtilities.Tab(output, _tabCount) + "\r\n"); + } } catch (InvalidOperationException) { diff --git a/src/NJsonSchema.CodeGeneration/Models/ClassTemplateModelBase.cs b/src/NJsonSchema.CodeGeneration/Models/ClassTemplateModelBase.cs index 6d3af3004..45f4282b6 100644 --- a/src/NJsonSchema.CodeGeneration/Models/ClassTemplateModelBase.cs +++ b/src/NJsonSchema.CodeGeneration/Models/ClassTemplateModelBase.cs @@ -16,13 +16,13 @@ public abstract class ClassTemplateModelBase : TemplateModelBase { private readonly JsonSchema4 _schema; private readonly object _rootObject; - private readonly ITypeResolver _resolver; + private readonly TypeResolverBase _resolver; /// Initializes a new instance of the class. /// The resolver. /// The schema. /// The root object. - protected ClassTemplateModelBase(ITypeResolver resolver, JsonSchema4 schema, object rootObject) + protected ClassTemplateModelBase(TypeResolverBase resolver, JsonSchema4 schema, object rootObject) { _schema = schema; _rootObject = rootObject; @@ -33,8 +33,9 @@ protected ClassTemplateModelBase(ITypeResolver resolver, JsonSchema4 schema, obj public abstract string ClassName { get; } /// Gets the derived class names (discriminator key/type name). - public IDictionary DerivedClasses => _schema.GetDerivedSchemas(_rootObject, _resolver) - .Where(s => s.Value.Inherits(_schema)) - .ToDictionary(s => s.Key, s => _resolver.GetOrGenerateTypeName(s.Value, s.Key)); + public IDictionary DerivedClasses => _schema + .GetDerivedSchemas(_rootObject) + .Select(p => new { Discriminator = p.Value, ClassName = _resolver.GetOrGenerateTypeName(p.Key, p.Value), Schema = p.Value }) + .ToDictionary(s => !string.IsNullOrEmpty(s.Discriminator) ? s.Discriminator : s.ClassName, s => s.ClassName); } } \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration/NJsonSchema.CodeGeneration.csproj b/src/NJsonSchema.CodeGeneration/NJsonSchema.CodeGeneration.csproj index e6e6b6952..73390738d 100644 --- a/src/NJsonSchema.CodeGeneration/NJsonSchema.CodeGeneration.csproj +++ b/src/NJsonSchema.CodeGeneration/NJsonSchema.CodeGeneration.csproj @@ -2,7 +2,7 @@ netstandard1.3;net451 JSON Schema draft v4 reader, generator and validator for .NET - 9.8.3 + 9.9.0 json schema validation generator .net Copyright © Rico Suter, 2017 https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md diff --git a/src/NJsonSchema.CodeGeneration/TypeGeneratorBase.cs b/src/NJsonSchema.CodeGeneration/TypeGeneratorBase.cs deleted file mode 100644 index 093023ea3..000000000 --- a/src/NJsonSchema.CodeGeneration/TypeGeneratorBase.cs +++ /dev/null @@ -1,30 +0,0 @@ -//----------------------------------------------------------------------- -// -// Copyright (c) Rico Suter. All rights reserved. -// -// https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md -// Rico Suter, mail@rsuter.com -//----------------------------------------------------------------------- - -namespace NJsonSchema.CodeGeneration -{ - /// Generates code for a type. - public abstract class TypeGeneratorBase : GeneratorBase - { - /// Generates the type. - /// The type name hint. - /// The code. - public abstract CodeArtifact GenerateType(string typeNameHint); - - /// Initializes a new instance of the class. - /// The schema. - /// The root object. - protected TypeGeneratorBase(JsonSchema4 schema, object rootObject) : base(schema) - { - RootObject = rootObject ?? schema; - } - - /// Gets the root object. - protected object RootObject { get; } - } -} \ No newline at end of file diff --git a/src/NJsonSchema.CodeGeneration/TypeResolverBase.cs b/src/NJsonSchema.CodeGeneration/TypeResolverBase.cs index aec29d060..a472a107a 100644 --- a/src/NJsonSchema.CodeGeneration/TypeResolverBase.cs +++ b/src/NJsonSchema.CodeGeneration/TypeResolverBase.cs @@ -12,20 +12,21 @@ namespace NJsonSchema.CodeGeneration { /// The type resolver base. - public abstract class TypeResolverBase : ITypeResolver - where TGenerator : TypeGeneratorBase + public abstract class TypeResolverBase { private readonly CodeGeneratorSettingsBase _settings; - private readonly Dictionary _types = new Dictionary(); private readonly Dictionary _generatedTypeNames = new Dictionary(); - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// The settings. protected TypeResolverBase(CodeGeneratorSettingsBase settings) { _settings = settings; } + /// Gets the registered schemas and with their type names. + public IDictionary Types => _generatedTypeNames.ToDictionary(p => p.Key, p => p.Value); + /// Tries to resolve the schema and returns null if there was a problem. /// The schema. /// The type name hint. @@ -35,32 +36,6 @@ public string TryResolve(JsonSchema4 schema, string typeNameHint) return schema != null ? Resolve(schema, false, typeNameHint) : null; } - /// Generates the code for all described types (e.g. interfaces, classes, enums, etc). - /// The code. - public abstract CodeArtifactCollection GenerateTypes(); - - /// Generates the code for all described types (e.g. interfaces, classes, enums, etc). - /// The code. - public virtual CodeArtifactCollection GenerateTypes(ExtensionCode extensionCode) - { - var processedTypes = new List(); - var types = new Dictionary(); - while (_types.Any(t => !processedTypes.Contains(t.Key))) - { - foreach (var pair in _types.ToList()) - { - processedTypes.Add(pair.Key); - var result = pair.Value.GenerateType(pair.Key); - types[result.TypeName] = result; - } - } - - var artifacts = types.Values.Where(p => - !_settings.ExcludedTypeNames.Contains(p.TypeName)); - - return new CodeArtifactCollection(artifacts); - } - /// Resolves and possibly generates the specified schema. /// The schema. /// Specifies whether the given type usage is nullable. @@ -68,24 +43,6 @@ public virtual CodeArtifactCollection GenerateTypes(ExtensionCode extensionCode) /// The type name. public abstract string Resolve(JsonSchema4 schema, bool isNullable, string typeNameHint); - /// Adds all schemas to the resolver. - /// The schema definitions. - public void AddGenerators(IDictionary definitions) - { - if (definitions != null) - { - foreach (var pair in definitions) - { - var schema = pair.Value.ActualSchema; - var isCodeGeneratingSchema = !schema.IsDictionary && !schema.IsAnyType && - (schema.IsEnumeration || schema.Type == JsonObjectType.None || schema.Type.HasFlag(JsonObjectType.Object)); - - if (isCodeGeneratingSchema) - AddGenerator(schema, pair.Key); - } - } - } - /// Gets or generates the type name for the given schema. /// The schema. /// The type name hint. @@ -93,6 +50,7 @@ public void AddGenerators(IDictionary definitions) public virtual string GetOrGenerateTypeName(JsonSchema4 schema, string typeNameHint) { schema = schema.ActualSchema; + RegisterSchemaDefinitions(schema.Definitions); if (!_generatedTypeNames.ContainsKey(schema)) { @@ -103,42 +61,22 @@ public virtual string GetOrGenerateTypeName(JsonSchema4 schema, string typeNameH return _generatedTypeNames[schema]; } - /// Determines whether the generator for a given type name is registered. - /// Name of the type. - /// - public bool HasTypeGenerator(string typeName) - { - return _types.ContainsKey(typeName); - } - - /// Creates a type generator. - /// The schema. - /// The generator. - protected abstract TGenerator CreateTypeGenerator(JsonSchema4 schema); - - /// Adds the type generator for a given type name. - /// Name of the type. - /// The generator. - protected void AddOrReplaceTypeGenerator(string typeName, TGenerator generator) - { - _types[typeName] = generator; - } - - /// Adds a generator for the given schema if necessary. - /// The schema. - /// The type name hint. - /// The type name of the created generator. - protected virtual string AddGenerator(JsonSchema4 schema, string typeNameHint) + /// Adds all schemas to the resolver. + /// The schema definitions. + public void RegisterSchemaDefinitions(IDictionary definitions) { - var typeName = GetOrGenerateTypeName(schema, typeNameHint); - if (!HasTypeGenerator(typeName)) + if (definitions != null) { - AddGenerators(schema.Definitions); + foreach (var pair in definitions) + { + var schema = pair.Value.ActualSchema; + var isCodeGeneratingSchema = !schema.IsDictionary && !schema.IsAnyType && + (schema.IsEnumeration || schema.Type == JsonObjectType.None || schema.Type.HasFlag(JsonObjectType.Object)); - var generator = CreateTypeGenerator(schema); - AddOrReplaceTypeGenerator(typeName, generator); + if (isCodeGeneratingSchema) + GetOrGenerateTypeName(schema, pair.Key); + } } - return typeName; } /// Resolves the type of the dictionary value of the given schema (must be a dictionary schema). diff --git a/src/NJsonSchema.CodeGeneration/ValueGeneratorBase.cs b/src/NJsonSchema.CodeGeneration/ValueGeneratorBase.cs index b4479350c..09d7e1d9a 100644 --- a/src/NJsonSchema.CodeGeneration/ValueGeneratorBase.cs +++ b/src/NJsonSchema.CodeGeneration/ValueGeneratorBase.cs @@ -13,13 +13,13 @@ namespace NJsonSchema.CodeGeneration /// Converts the default value to a language specific identifier. public abstract class ValueGeneratorBase { - private readonly ITypeResolver _typeResolver; + private readonly TypeResolverBase _typeResolver; private readonly IEnumNameGenerator _enumNameGenerator; /// Initializes a new instance of the class. /// The type typeResolver. /// The enum name generator. - protected ValueGeneratorBase(ITypeResolver typeResolver, IEnumNameGenerator enumNameGenerator) + protected ValueGeneratorBase(TypeResolverBase typeResolver, IEnumNameGenerator enumNameGenerator) { _typeResolver = typeResolver; _enumNameGenerator = enumNameGenerator; diff --git a/src/NJsonSchema/JsonSchemaReferenceUtilities.cs b/src/NJsonSchema/JsonSchemaReferenceUtilities.cs index 38dd130f7..bff0fd83b 100644 --- a/src/NJsonSchema/JsonSchemaReferenceUtilities.cs +++ b/src/NJsonSchema/JsonSchemaReferenceUtilities.cs @@ -11,6 +11,7 @@ using System.Linq; using System.Threading.Tasks; using NJsonSchema.References; +using NJsonSchema.Visitors; namespace NJsonSchema { @@ -69,7 +70,7 @@ public static void UpdateSchemaReferencePaths(object rootObject, bool removeExte p.Key.ReferencePath = result[p.Value]; } - private class JsonReferenceUpdater : JsonSchemaVisitor + private class JsonReferenceUpdater : JsonReferenceVisitorBase { private readonly object _rootObject; private readonly JsonReferenceResolver _referenceResolver; @@ -116,7 +117,7 @@ protected override async Task VisitJsonReferenceAsync(IJsonRefer } } - private class JsonReferencePathUpdater : JsonSchemaVisitor + private class JsonReferencePathUpdater : JsonReferenceVisitorBase { private readonly object _rootObject; private readonly Dictionary _schemaReferences; diff --git a/src/NJsonSchema/NJsonSchema.csproj b/src/NJsonSchema/NJsonSchema.csproj index d838161ef..377ec44f9 100644 --- a/src/NJsonSchema/NJsonSchema.csproj +++ b/src/NJsonSchema/NJsonSchema.csproj @@ -3,7 +3,7 @@ netstandard1.0;net40;net45 JON Schema draft v4 reader, generator and validator for .NET - 9.8.3 + 9.9.0 json schema validation generator .net Copyright © Rico Suter, 2017 https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md diff --git a/src/NJsonSchema/JsonSchemaVisitor.cs b/src/NJsonSchema/Visitors/JsonReferenceVisitorBase.cs similarity index 86% rename from src/NJsonSchema/JsonSchemaVisitor.cs rename to src/NJsonSchema/Visitors/JsonReferenceVisitorBase.cs index 1c4cdb048..6399b8b5f 100644 --- a/src/NJsonSchema/JsonSchemaVisitor.cs +++ b/src/NJsonSchema/Visitors/JsonReferenceVisitorBase.cs @@ -1,5 +1,5 @@ //----------------------------------------------------------------------- -// +// // Copyright (c) Rico Suter. All rights reserved. // // https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md @@ -17,10 +17,10 @@ using NJsonSchema.Infrastructure; using NJsonSchema.References; -namespace NJsonSchema +namespace NJsonSchema.Visitors { /// Visitor to transform an object with objects. - public abstract class JsonSchemaVisitor + public abstract class JsonReferenceVisitorBase { private readonly string[] _jsonSchemaProperties = typeof(JsonSchema4).GetRuntimeProperties().Select(p => p.Name).ToArray(); @@ -45,18 +45,18 @@ protected virtual async Task VisitAsync(object obj, string path, string typeName return; checkedObjects.Add(obj); - if (obj is JsonSchema4 schema) + if (obj is IJsonReference reference) { - var newSchema = await VisitSchemaAsync(schema, path, typeNameHint); - if (newSchema != schema) + var newReference = await VisitJsonReferenceAsync(reference, path, typeNameHint); + if (newReference != reference) { - replacer(newSchema); - schema = newSchema; - } - - if (schema == null) + replacer(newReference); return; + } + } + if (obj is JsonSchema4 schema) + { if (schema.Reference != null) await VisitAsync(schema.Reference, path, null, checkedObjects, o => schema.Reference = (JsonSchema4)o); @@ -160,31 +160,6 @@ p.MemberInfo is PropertyInfo && } } } - - if (obj is IJsonReference reference) - { - var newReference = await VisitJsonReferenceAsync(reference, path, typeNameHint); - if (newReference != reference) - { - replacer(newReference); - obj = newReference; - } - - if (obj == null) - return; - } - } - - /// Called when a is visited. - /// The visited schema. - /// The path. - /// The type name hint. - /// The task. -#pragma warning disable 1998 - protected virtual async Task VisitSchemaAsync(JsonSchema4 schema, string path, string typeNameHint) -#pragma warning restore 1998 - { - return schema; } /// Called when a is visited. @@ -192,12 +167,7 @@ protected virtual async Task VisitSchemaAsync(JsonSchema4 schema, s /// The path. /// The type name hint. /// The task. -#pragma warning disable 1998 - protected virtual async Task VisitJsonReferenceAsync(IJsonReference reference, string path, string typeNameHint) -#pragma warning restore 1998 - { - return reference; - } + protected abstract Task VisitJsonReferenceAsync(IJsonReference reference, string path, string typeNameHint); private void ReplaceOrDelete(ICollection collection, int index, T obj) { diff --git a/src/NJsonSchema/Visitors/JsonSchemaVisitorBase.cs b/src/NJsonSchema/Visitors/JsonSchemaVisitorBase.cs new file mode 100644 index 000000000..73d8c4824 --- /dev/null +++ b/src/NJsonSchema/Visitors/JsonSchemaVisitorBase.cs @@ -0,0 +1,37 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Rico Suter. All rights reserved. +// +// https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md +// Rico Suter, mail@rsuter.com +//----------------------------------------------------------------------- + +using System.Threading.Tasks; +using NJsonSchema.References; + +namespace NJsonSchema.Visitors +{ + /// Visitor to transform an object with objects. + public abstract class JsonSchemaVisitorBase : JsonReferenceVisitorBase + { + /// Called when a is visited. + /// The visited schema. + /// The path. + /// The type name hint. + /// The task. + protected abstract Task VisitSchemaAsync(JsonSchema4 schema, string path, string typeNameHint); + + /// Called when a is visited. + /// The visited schema. + /// The path. + /// The type name hint. + /// The task. + protected override async Task VisitJsonReferenceAsync(IJsonReference reference, string path, string typeNameHint) + { + if (reference is JsonSchema4 schema) + return await VisitSchemaAsync(schema, path, typeNameHint); + + return reference; + } + } +} \ No newline at end of file