RicoSuter / NSwag

The Swagger/OpenAPI toolchain for .NET, ASP.NET Core and TypeScript.
http://NSwag.org
MIT License
6.69k stars 1.24k forks source link

Consider using Razor template engine #2828

Open sergeyt opened 4 years ago

sergeyt commented 4 years ago

BTW now it is possible to use Razor as template engine. It is simple as:

using System;
using JetBrains.Annotations;
using NJsonSchema.CodeGeneration;
using NJsonSchema.CodeGeneration.TypeScript.Models;
using RazorEngineCore;

namespace NSwag.RazorTemplateExample
{
    internal class RazorTemplateFactory : ITemplateFactory
    {
        private readonly ITemplateFactory _baseFactory;
        private readonly RazorEngineCompiledTemplate _interface;

        public RazorTemplateFactory([NotNull] ITemplateFactory baseFactory)
        {
            _baseFactory = baseFactory ?? throw new ArgumentNullException(nameof(baseFactory));

            var templateStore = typeof(ApiToolsController).Assembly;

            var src = templateStore.ReadEmbeddedResource("Templates.Interface.cshtml");
            var razorEngine = new RazorEngine();
            _interface = razorEngine.Compile(src, builder =>
            {
                builder.AddAssemblyReference(typeof(ClassTemplateModel).Assembly);
            });
        }

        public ITemplate CreateTemplate(string language, string template, object model)
        {
            if (language == "TypeScript" && template == "Interface")
            {
                return new RazorTemplate(_interface, model);
            }

            return _baseFactory.CreateTemplate(language, template, model);
        }

        private class RazorTemplate : ITemplate
        {
            private readonly RazorEngineCompiledTemplate _source;
            private readonly object _model;

            public RazorTemplate(RazorEngineCompiledTemplate source, object model)
            {
                _source = source;
                _model = model;
            }

            public string Render() => _source.Run(_model);
        }
    }
}

Sample template:

@using NJsonSchema.CodeGeneration.TypeScript.Models
@model ClassTemplateModel
@{
    var export = Model.ExportTypes ? "export " : "";
    var keyword = Model.HasInheritance ? "interface " : "type ";
    var suffix = Model.HasInheritance ? " {" : " = {";
}
@if (Model.HasDescription)
{
    @:/** @Model.Description */
}
@export@keyword@Model.ClassName@Model.Inheritance@suffix
@foreach (var prop in Model.Properties)
{
    if (prop.HasDescription)
    {
        @:  /** @prop.Description */
    }
    var ro = prop.IsReadOnly ? "readonly " : "";
    var opt = prop.IsOptional ? "?" : "";
    @:  @ro@prop.InterfaceName@opt: @prop.Type@prop.TypePostfix;
}
@if (Model.HasIndexerProperty)
{
    @:  [key: string]: @Model.IndexerPropertyValueType;
}
};

Using Razor can improve performance and developer experience since Razor has fantastic support in Visual Studio. And so this might simplify template customization.

sergeyt commented 4 years ago

copied that from issue #51

TomSmith27 commented 4 years ago

I think this is a create idea, then you will get intellisense as your write the templates and compile time checking. Could you put a PR together for this i would like to see how it works?