Code Monkey home page Code Monkey logo

ntypewriter's Introduction

NTypewriter

ci Visual Studio Marketplace Version Nuget Nuget

NTypewriter LivePreview

Scriban templates + Roslyn C# code model => generated files

design/compile/run time == any time

For those who do not know Typewriter:

NTypewriter is files generator from text templates populated with meta-data about your C# code. It is like a specialized and more convenient T4 design-time template.

With NTypewriter you can:

  • auto-generate documentation for your C# code
  • create a typed TypeScript API client for your ASP.net web API

NTypewriter comes in many flavours, that can be used according to your needs:

  • NTypewriter editor for Visual Studio - extension for Visual Studio that adds support for editing *.nt templates, with syntax highlighting, code completion, live preview, design time rendering, available on vs marketplace
  • NTypewriter.SourceGenerator - nuget, Roslyn source generator that renders *.nt templates during compilation, since it is a compiler extension, it can be used with any IDE or CI/pipeline that supports source generators
  • NTypewriter.Online - blazor client side, online demo of NTypewriter capabilities
  • NTypewriter - nuget, library that enables you to create run time solution which will be able to render *.nt templates, for example: your own CLI
  • NTypewriter.CodeModel.Roslyn - nuget, library that exposes C# code model from an instance of Microsoft.CodeAnalysis.Compilation, useful if you would like to use a different template engine

more about NTypewriter architecture and all extension points that can be used, you will find here

For those who know Typewriter:

NTypewriter is a younger and more immature brother of beloved Typewriter. They share the same ideas but with a completely different implementation. NTypwriter uses Scriban as a template engine, thus template files are completely not interchangeable. While code model API is about 95% compatible between them, there are some differences. NTypewriter code model is 100% pure, without any amenities that help generate TS files. All things that help generate TypeScript from ASP.NET are located in built-in functions: Action, Type.

Oh, did I forget to mention that NTypewriter also solves most of the awaited issues of the Typewriter that were promised for 2.0 version:

  • support for attribute properties/values, statics, indexers, default parameters, nullable, records, constructors
  • output multiple types to a single file
  • include types in CodeModel from referenced assemblies/nugets
  • save generated file only when file content has changed
  • sharable custom functions between templates
  • full control over whitespaces
  • compile-time rendering, without any IDE needed
  • built-in support for getting all types used in type declaration (Type.AllReferencedTypes)
  • you can debug custom functions

Index

Typewriter vs NTypewriter

ย  Typewriter NTypewriter
Template file extension *.tst *.nt
Syntax typewriter syntax scriban scripting language
Lambda filters present yes
Can be used from CLI no yes
Can be used in pipeline no yes
Full control over whitespaces nope yup
Mapping one input always produces one output file you can generate as many files as you want
Live preview no yes
Code model
Unit of work file there is no concept of a file in NTypewriter, you work on compiled symbols
Access modifiers code model contains only public types code model contains all types
Partial classes treated as separate units all parts of the class are treated as a whole unit
Automation
Auto-render template on save yes (opt-out is possible) yes (opt-in is possible)
Auto-render when C# file changes yes (opt-out is possible) no
Auto-render on build no yes (opt-in is possible)
Custom functions
Placement inside template file (.tst) in separate file (*.nt.cs)
Can be shared separate for every template shared between templates inside a project
Can be debug no yes
Can be unit tested no yes
VS Integration
Supported versions of Visual Studio 2015, 2017, 2019 2019 (min ver 16.11.x), 2022
Add generated files to VS project yes (opt-out is possible) yes (opt-out is possible)
Sync deleted or renamed C# types with generated files there is a part of the code that should do that but it does not work anymore yes (only when the above option is enabled)

Typewriter template:

module App { $Classes(*Model)[
    export class $Name { $Properties[
        public $name: $Type;]
    }]
}

equivalent NTypewriter template will be: (open in NTypewriter.Online)

{{- for class in data.Classes | Symbols.WhereNameEndsWith "Model"
        capture output -}}
module App {
    export class {{ class.Name }} {
            {{- for property in class.Properties | Symbols.ThatArePublic }}
        public {{ property.Name | String.ToCamelCase }}: {{ property.Type | Type.ToTypeScriptType }};
            {{- end }}
    }
}
    {{- end 
        filePath =  class.BareName | String.Append ".ts"
        Save output filePath
    end }}

yes, it is more verbose, but maintaining it over time will be much easier. Both templates generate exactly the same output:

module App {
    export class CustomerModel {
        public id: number;
        public name: string;
        public orders: OrderModel[];
    }
}

Examples

All Typewriter examples are available as .nt templates on github and also on NTypewriter.Online website.

Note nt. templates produce exactly the same output as .tst templates, even bad output formatting was preserved, to make them easier to compare.

example NTypewriter Typewriter Online
CreateYourFirstTemplate CreateYourFirstTemplate.nt CreateYourFirstTemplate.tst open
Extensions Extensions.nt Extensions.tst open
ModelInterfaces ModelInterfaces.nt ModelInterfaces.tst open
KnockoutModels KnockoutModels.nt KnockoutModels.tst open
AngularWebAPIService AngularWebAPIService.nt AngularWebAPIService.tst open

Known issues

NTypewriter does not have own a lexer/parser as Typewriter has, and uses Scriban instead to do heavy work. Scriban works very well with fully correct templates, but with incomplete templates during editing not so much. It is the source of the most glitches in the Editor. Scriban language is also typeless, thus doing code completion is challenging.

ntypewriter's People

Contributors

amdavie avatar christophdebaene avatar curtiskeller avatar etchelon avatar gregveres avatar nevespl avatar rudeysh avatar tanguy-c avatar wolfulus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

ntypewriter's Issues

Are you open to some negative Symbol filters?

I am still perfecting my Services generation template and I just realized that I have some Webhook Controllers that are being converted into Typescript Services because they are getting caught up in my data.Classes | Types.ThatInheritFrom query.

I notice that all of your SymbolFunctions are positive and none are negative. I could use a Symbols.WhereNameSpaceDoesNobBeginWith query for instance, to filter out my Webhooks.

I am willing to do a PR for some negative SymbolFunctions if you would like them as part of NTypewriter.

I don't explicitly need it right now because I ended up doing an if with a continue in my loop.

If I had the negative query, I would have done something like this:

{{for controller in data.Classes | Types.ThatInheritFrom "OurBaseApiController" | Symbols.WhereNamespaceDoesNotStartsWith "path"}}

local configuration is not working

only global configs are working correctly.
below .nt file

{{ config.ProjectsToBeSearched = ["ClassLibrary1"] }}

     {{- capture output
       for class in data.Classes 
           class.Name | String.Append "\r\n"
      end
   end
   Save output "index.txt"
   }}

is generating:
Program
Class1

while Class1 exists inside the ClassLibrary1 project while the Program class in another project

Select classes with a specific attribute?

Hi,

I just stumbled upon your project. It looks really interesting. I have been a Typewriter user for 5 years.

I have a code base that uses an attribute called ExportToTypescript to indicate in my c# code which classes and enums should be converted to TS through Typewriter.

I have been looking through your unit tests and that has helped me understand Scriban a bit. I have also been reading the Scriban github docs to understand the language.

But I am confused on the very highest level structure of the .nt file. I can see how I can just start writing output and then do substitution within that output using snippets of scriban. But what I want as output is one file per enum and one file per class that are tagged with the attribute. This is where I get confused on the strucutre of the scriban file.

I think I need to first filter the list with something like this:

for class in data.Enums | Symbols.ThatHaveAttribute "ExportToTypescript"

But do I put this in {{ }} and then use String.Append for all of my output? Something like this:

{{  
  for enum in data.Enums | Symbols.ThatHaveAttribute "ExportToTypescript" 
    capture output
      "export const enum " | String.Append enum.Name | String.Append " {\r\n"
      ...
   end
   Save output (enum.BareName | String.Append ".ts")

or is there away to have the text just appear in my output without having to use String.Append?

Thanks

ERROR: Class NTConfig does not implement IEditorConfig interface, using default configuration instead

I don't know when this started happening. It could have been back in early august - I haven't done much since then.

I have an NTCconfig.cs file in my project beside my .nt files.
I have Version 0.1.11 of the extension installed
The project with the NTConfig.cs file references the NuGet package NTypewriter.Editor.Config version 0.1.10-alpha. That seems to be the latest version.

My NTConfig.cs file is:

using System.Collections.Generic;
using NTypewriter.Editor.Config;

namespace SkyCourt.UI.ui.src.api
{
    [NTEditorFile]
    public class NTConfig : EditorConfig
    {
        public override bool AddGeneratedFilesToVSProject { get => false; }
        public override IEnumerable<string> ProjectsToBeSearched
        {
            get
            {
                yield return "SkyCourt";
                yield return "SkyCourt.App.Api";
                yield return "SkyCourt.App.Models";
                yield return "SkyCourt.App.Utilities";
                yield return "SkyCourt.App.ViewModels";
            }
        }
    }
}

Any thoughts? Is there suppposed to be a verson 1.11 of the NuGet package?

execute NTypewriter as a dotnet tool

I am not sure if its possible, if it is - that would help a lot in CI/CD automation.
Also, I can run it as a vscode command rather than depending on visual studio.

Questions

Hello!
First of all I want to say thanks for the effort you've put into this! It's not a small feat and it is tremendously helpful!

I've used TypeWriter some time ago, and I had assembled a nice set of scripts that allowed me to create TS interfaces from cs classes/enums and place them in various npm packages in the company ecosystem, and I am looking to translate those scripts into .nt scripts!
I used Attributes heavily in order to achieve that, so I'm trying to figure out how to do a few things:

  1. Is there a way to use type hints in functions? I'm writing a lot of helpers like
func TsPropertyName(prop)
  ret prop.Name
end

but prop has no intellisense, and since I'm learning the tool it would ease the learning 10x

  1. How can I log to the NTypewriter output? Would help a lot for debugging!
  2. How can I throw exceptions?

Thanks!

IType.Namespace throws an exception when using string[]

When using a model with a string[] property:

public class ClassModel
{
    public string[] Foo { get; set; }
}

And using a template that uses {{ property.Type.Namespace }}:

module App {
    export class {{ class.Name }} {
            {{- for property in class.Properties | Symbols.ThatArePublic }}
        public {{ property.Name | String.ToCamelCase }}: {{ property.Type | Type.ToTypeScriptType }}; //{{ property.Type.Namespace }}
            {{- end }}
    }
}
    {{- end
        filePath =  class.BareName | String.Append ".ts"
        Save output filePath
    end }}

I get the following exception:

INFO: Rendering template
ERROR: (6,108) Unexpected exception while accessing target expression: Exception has been thrown by the target of an invocation.
ERROR: System.Exception: Rendering template failed
at NTypewriter.EditorForVisualStudio.CoreDomain.TemplateRenderer.d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at NTypewriter.EditorForVisualStudio.CoreDomain.TemplateRenderer.d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
at NTypewriter.EditorForVisualStudio.NTypewriterEditorForVisualStudioPackage.<RenderTemplateCommand_OnExecuted>d__11.MoveNext()

config issue: error CS0115: 'NTConfig.GetProjectsToBeSearched()': no suitable method found to override

My csharp configuration seems to be broken with the latest version. It was working just fine with the previous version.

I have an NTConfig.cs file:

using NTypewriter.Editor.Config;
using System.Collections.Generic;

namespace SkyCourt.UI.ui.src.api
{
    [NTEditorFile]
    public class NTConfig : EditorConfig
    {
        public override IEnumerable<string> GetProjectsToBeSearched()
        {
            yield return "SkyCourt";
            yield return "SkyCourt.App.Api";
            yield return "SkyCourt.App.Models";
            yield return "SkyCourt.App.Utilities";
            yield return "SkyCourt.App.ViewModels";
        }
    }
}

that was being picked up just fine. But with this latest version I am getting this as an error message:

08:12:08.584 INFO: 
  _   _ _____                               _ _            
 | \ | |_   _|   _ _ __   _____      ___ __(_) |_ ___ _ __ 
 |  \| | | || | | | '_ \ / _ \ \ /\ / / '__| | __/ _ \ '__|
 | |\  | | || |_| | |_) |  __/\ V  V /| |  | | ||  __/ |   
 |_| \_| |_| \__, | .__/ \___| \_/\_/ |_|  |_|\__\___|_|   
             |___/|_|
17:42:54.552 INFO: ------------------------------------------------------
17:42:54.558 INFO: Loading configuration
17:42:54.599 ERROR: Failed to compile configuration
17:42:54.601 ERROR: C:\Users\Greg\source\repos\SquashSpider\SquashSpider\SkyCourt.UI\ui\src\api\NTConfig.cs(9,45): error CS0115: 'NTConfig.GetProjectsToBeSearched()': no suitable method found to override

Documentation should include examples

I'd like to explore migrating from Typewriter to NTypewriter but while this documentation is very complete, I'd like some simple/complex examples for how to migrate my classes to corresponding typescript interfaces.

FR: Symbols.ThatDerivesFrom filter

Hi,

Now that I have all the Enums and Interfaces being generated, the next step is to generate my services from my controllers. All of my controllers are derived from a single base class. It would be great if there was a Symbols filter that selected classes that were derived from a base class rather than having to find all the controllers.

This is especially important for me because I am still on ASP.Net MVC (haven't had time to re-write for .Net Core), so all of my API Controllers and my MVC Controllers end with the word Controller. So using a name filter doesn't really work. I am hoping I can capture just the right set of controllers through the namespace, but the best would be to filter by a derived class.

Thanks!

TypeScriptDefault for GUID

I am using the KnockoutModel Template for a C# file that has a GUID Attribute. This generates the following typescript code:

public someguid: KnockoutObservable<string> = ko.observable<string>(00000000-0000-0000-0000-000000000000)

I receive two errors:
TS1121: (TS) Octal literals are not allowed in strict mode.
TS1085: (TS) Octal literals are not available when targeting ECMAScript 5 and higher. Use the syntax '0o0'.

I would suspect that changing the return value for GUID of the ToTypeScriptDefault method from "00000000-0000-0000-0000-000000000000" to "\"00000000-0000-0000-0000-000000000000\"" solves the problem.

Rendering failed: Sequence contains no elements

Thanks for creating NTypewriter! I'm currently attempting to replace Typewriter with something else, this project looks very promising.

Currently, NTypewriter appears to be working for me (it generates files), but after rendering the example template from the readme in my project, Visual Studio's status bar says "Rendering failed" and the following exception/stacktrace is logged:

ERROR: System.InvalidOperationException: Sequence contains no elements
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
at NTypewriter.EditorForVisualStudio.Editor.SolutionItemsManager.GetAssociatedProjectItems(String projectFilePath, String id)
at NTypewriter.EditorForVisualStudio.Editor.SolutionItemsManager..ctor(DTE2 dte, String templateFilePath, String projectFilePath)
at NTypewriter.EditorForVisualStudio.NTypewriterEditorForVisualStudioPackage.<>c__DisplayClass11_0.<RenderTemplateCommand_OnExecuted>b__2()
at System.Threading.Tasks.Task.InnerInvoke()
at System.Threading.Tasks.Task.Execute()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
at NTypewriter.EditorForVisualStudio.NTypewriterEditorForVisualStudioPackage.<RenderTemplateCommand_OnExecuted>d__11.MoveNext()

Suggestion: push people to supply GetProjectsToBeSearched config option: 15 second run time down to 1/2 second

HI

After spending a week of tweaking and working with you on issues, I stumbled upon debugging the data.Classes list and realized that it was huge. This led me to looking around for how to specify just the projects to search when building data.Classes.

I admit you have nicely laid out the configuration section of the docs, but i skipped over it as "something to come back to later". But I really should of addressed the configuration head on first. The reason: speed.

My solution has 27 projects in it, 12 of them are Unit test projects and 5 of them are webjob related projects. So only 5 projects needed to be searched.

Adding in a very simple config file that only provides GetProjectsToBeSearched changed the run time from 15 seconds down to 1/2 a second.

I thought it was going to be the resource file because there are so many resource string objects. But it turns out that the real time killer was all the unit tests projects. I started adding them in 1 at a time and each one takes about 2 seconds to process. I suspect it is because of the large number of methods on the test classes. I have 11,500 c# unit tests.

So focusing on just the projects that will have the classes to process, I was able to speed things up tremendously. So I was thinking that it would probably be a good idea to direct people to creating a config file early on in their learning of the tool. I wasn't happy with the 15-20 second run time but I was willing to tough it out to see if I could get the result I wanted and when I got the result, I figured I would live with the run time. But now that the run time is 1/2 a second, it's a no brainer.

Just something to think about. I am now a big fan of NTypewriter. Thank you for writing it!

Ability to configure ToTypeScriptType to handle nullable types differently.

Currently, NTypewriter appends " | null" to nullable types:

I would like to be able to use any of following TypeScript notations in my templates:

myProperty: string | null;
myProperty: string | undefined;
myProperty: string | null | undefined;
myProperty?: string;

I could attempt to write my own implementation of ToTypeScriptType, but I'd rather not copy-paste 100+ lines to change a single detail. I'd like to help out if possible, but I'm not sure where to start - I'm not sure what the best approach is here. Is there already an example of something similar to this in the code base, e.g. a configuration option that affects the behavior of a static function such as ToTypeScriptType?

The 'NTypewriterEditorForVisualStudioPackage' package did not load correctly.

I'm getting the following error when starting Visual Studio:

The 'NTypewriterEditorForVisualStudioPackage' package did not load correctly.

The problem may have been caused by a configuration change or by the installation of another extension. You can get more information by examining the file 'C:\Users\RudeySH\AppData\Roaming\Microsoft\VisualStudio\16.0_9d235251\ActivityLog.xml'.

Restarting Visual Studio could help resolve this issue.

I have the latest version of the extension installed (0.0.11).

The ActivityLog.xml contains the following entries near the bottom:

  <entry>
    <record>2847</record>
    <time>2021/04/28 13:11:23.026</time>
    <type>Information</type>
    <source>VisualStudio</source>
    <description>Begin package load [NTypewriterEditorForVisualStudioPackage]</description>
    <guid>{7CB32B43-C9AA-44F8-BCED-9BAA9A76B4FD}</guid>
  </entry>
  <entry>
    <record>2848</record>
    <time>2021/04/28 13:11:23.039</time>
    <type>Error</type>
    <source>VisualStudio</source>
    <description>SetSite failed for package [NTypewriterEditorForVisualStudioPackage]Source: &apos;NTypewriter.EditorForVisualStudio&apos; Description: Could not load file or assembly &apos;Microsoft.VisualStudio.Threading, Version=16.9.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a&apos; or one of its dependencies. The system cannot find the file specified.&#x000D;&#x000A;System.IO.FileNotFoundException: Could not load file or assembly &apos;Microsoft.VisualStudio.Threading, Version=16.9.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a&apos; or one of its dependencies. The system cannot find the file specified.&#x000D;&#x000A;File name: &apos;Microsoft.VisualStudio.Threading, Version=16.9.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a&apos;&#x000D;&#x000A;   at NTypewriter.EditorForVisualStudio.NTypewriterEditorForVisualStudioPackage.InitializeAsync(CancellationToken cancellationToken, IProgress`1 progress)&#x000D;&#x000A;   at Microsoft.VisualStudio.Shell.AsyncPackage.&lt;&gt;c__DisplayClass20_0.&lt;&lt;Microsoft-VisualStudio-Shell-Interop-IAsyncLoadablePackageInitialize-Initialize&gt;b__1&gt;d.MoveNext()&#x000D;&#x000A;--- End of stack trace from previous location where exception was thrown ---&#x000D;&#x000A;   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)&#x000D;&#x000A;   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)&#x000D;&#x000A;   at Microsoft.VisualStudio.Threading.JoinableTask.&lt;JoinAsync&gt;d__68.MoveNext()&#x000D;&#x000A;--- End of stack trace from previous location where exception was thrown ---&#x000D;&#x000A;   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()&#x000D;&#x000A;   at Microsoft.VisualStudio.Services.VsTask.RethrowException(AggregateException e)&#x000D;&#x000A;   at Microsoft.VisualStudio.Services.VsTask.InternalGetResult(Boolean ignoreUIThreadCheck)&#x000D;&#x000A;   at Microsoft.VisualStudio.Services.VsTask.GetResult()&#x000D;&#x000A;&#x000D;&#x000A;WRN: Assembly binding logging is turned OFF.&#x000D;&#x000A;To enable assembly bind failure logging, set the registry value [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1.&#x000D;&#x000A;Note: There is some performance penalty associated with assembly bind failure logging.&#x000D;&#x000A;To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog].&#x000D;&#x000A;</description>
    <guid>{7CB32B43-C9AA-44F8-BCED-9BAA9A76B4FD}</guid>
    <hr>80070002</hr>
    <errorinfo></errorinfo>
  </entry>
  <entry>
    <record>2849</record>
    <time>2021/04/28 13:11:23.047</time>
    <type>Error</type>
    <source>VisualStudio</source>
    <description>End package load [NTypewriterEditorForVisualStudioPackage]</description>
    <guid>{7CB32B43-C9AA-44F8-BCED-9BAA9A76B4FD}</guid>
    <hr>80070002</hr>
    <errorinfo></errorinfo>
  </entry>

IType.IsAbsract and .IsInterface aren't mutually exclusive (and apply to primitives sometimes?)

I'm not in the best development state to give any information here, but I'm migrating a migration from Typewriter that someone else did and am finding that their initial pass isn't sufficient for our more robust code state.

However:
For

		public static string TypescriptModelName(IType type)
		{
			type = TypeFunctions.Unwrap(type);
			string tsname = TypeFunctions.ToTypeScriptType(type);

			if (type.IsPrimitive)
				return tsname;

			if (type.IsAbstract /*&& !type.IsInterface*/)
				return $"modelDto.{tsname}{{{type.Name}}}";

            if (type.IsEnum)
                return $"modelEnums.{tsname}";

			if (tsname.ToLowerInvariant().EndsWith("dto"))
				return "modelDto." + tsname;

			return "model." + tsname;
		}
Custom.TypescriptModelName method.ReturnType

on

IQueryable<bool>

Outputs

modelDto.boolean[]{IQueryable<bool>}

If I pair IsAbstract && !IsInterface it appears to work exactly as expected.

I'm trying to get the simplest example in code of something that would be useful, I'm absolutely seeing this problem elsewhere, but looking at this example I'm more confused, because bool shouldn't be true on either abstract nor interface?

This may indicate a completely different problem than my initial expectation

Type.ToTypeScriptType Generating Incorrectly

Installed from Visual Studio "Manage Extensions", version 0.1.11

Template:

{{ config.NamespacesToBeSearched = ["SNAP.DAL.Models"] }}

{{- # Helper classes }}

{{- func ImportType(type)
	ret "import { " | String.Append type | String.Append " } from './" | String.Append type | String.Append "'\r"
	end
}}

{{- func TypeName(type)
		useType = Type.Unwrap(type)
		if (useType.ArrayType != null) 
			useType = useType.ArrayType
		end
		ret useType.Name
	end
}}

{{- # output classes }}
{{- for class in data.Classes
		capture output }}
{{- for type in (class | Type.AllReferencedTypes | Array.Each @TypeName | Array.Uniq )}}
	{{- ImportType type}}
{{-end}}
export interface {{class.Name}}{{if class.HasBaseClass}} extends {{class.BaseClass.Name; end}} {
  {{-for prop in class.Properties | Symbols.ThatArePublic }}
  {{ prop.Name }}: {{prop.Type | Type.ToTypeScriptType}}{{if !for.last}},{{end}}
  {{-end}}
}
{{end}}
{{- Save output ("../../../snapgui/src/models/" + class.BareName + ".ts")}}
{{- end}}

C# Model:

namespace SNAP.DAL.Models
{
    public partial class User
    {

        [Key]
        public int UserId { get; set; }
        [Required]
        [StringLength(50)]
        public string Username { get; set; }
        [Required]
        public string Password { get; set; }
        public int RoleMask { get; set; }

        public int? SupervisorId { get; set; }

        public virtual List<Client> ClientDefaultSupervisors { get; } = new List<Client>();
        public virtual List<Client> ClientDefaultStaff { get; } = new List<Client>();
        public virtual List<Review> ReviewStaff { get; } = new List<Review>();
        public virtual List<Review> ReviewSupervisors { get; } = new List<Review>();
    }
}

Generated Typescript:

import { Client } from './Client'
import { Review } from './Review'

export interface User {
  UserId: number,
  Username: string,
  Password: string,
  RoleMask: number,
  SupervisorId: int<number> | null,
  ClientDefaultSupervisors: List<Client>,
  ClientDefaultStaff: List<Client>,
  ReviewStaff: List<Review>,
  ReviewSupervisors: List<Review>
}

Expected Typescript:

import { Client } from './Client'
import { Review } from './Review'

export interface User {
  UserId: number,
  Username: string,
  Password: string,
  RoleMask: number,
  SupervisorId: number | null,
  ClientDefaultSupervisors: Client[],
  ClientDefaultStaff: Client[],
  ReviewStaff: Review[],
  ReviewSupervisors: Review[]
}

The issues seem to be with any List<> in C#, and any nullable ints, it gets the nullable part right, but I can't see why it's generating the invalid int type.

Is there a way to simulate Typewriter's RequestData for a controller method?

This is the typewriter code for processing my Controllers. In typewriter I had to break out processing the methods twice for each method type because some controller actions required sending data and some didn't. Typewriter had a method called Method.RequestData() that would the data that would have to be sent in the body of the post/put request.

I was looking at the Parameters to see if there was a flag that indicated a [FromBody] attribute or something but I don't see any way other than maybe looking at the Parameter's type and using IsPrimitive, but even that misses the [FromBody] attribute, I think.

I am open to any suggestions, even suggestions of "write a custom function to do ..."

This is what my Typewriter script looked like:

import axios, { AxiosResponse } from 'axios';
$Methods(m => (m.HttpMethod() == "post") && m.RequestData() != "null")[
// $HttpMethod: $Url
export const $RouteName = ($Parameters(p => p.Type.IsPrimitive)[$Name: $QualifiedType][, ]) => `/$Url`;
export function $MethodName($Parameters[$Name: $QualifiedType][, ]): Promise<$ReturnType> {
  return axios
    .post($RouteName($Parameters(p => p.Type.IsPrimitive)[$Name][, ]), $RequestData)
    .then((r: AxiosResponse<$ReturnType>) => {
      return r.data;
    });
}]
$Methods(m => (m.HttpMethod() == "post") && m.RequestData() == "null")[
// $HttpMethod: $Url
export const $RouteName = ($Parameters(p => p.Type.IsPrimitive)[$Name: $QualifiedType][, ]) => `/$Url`;
export function $MethodName($Parameters[$Name: $QualifiedType][, ]): Promise<$ReturnType> {
  return axios
    .post($RouteName($Parameters(p => p.Type.IsPrimitive)[$Name][, ]))
    .then((r: AxiosResponse<$ReturnType>) => {
      return r.data;
    });
}]

Action.ReturnType does not return primitive return types

Using v0.0.9, the return type is now successfully picking up the [ResponseType] attribute when the return type is a class. But I have noticed that it is not picking up the return type when the type is a primitive.

Then I tried a plain return type of a primitive to see if this was a problem with ResponseType handling or general return type handling. It didn't return the primitive from there either.

Here is my example Controller

    [RoutePrefix("api/AdServer")]
    public class AdServerController : OurBaseApiController
    {
        [HttpGet]
        [Route("Club/{clubId}/Administrators")]
        [ResponseType(typeof(List<AdServerViewModel.AdAdministrator>))]
        public IHttpActionResult ClubAdministrators(int clubId)
        {
            return Ok();
        }

        [HttpPost]
        [Route("Club/{clubId}/Administrators")]
        [ResponseType(typeof(int))]
        public int AddClubAdministrator(int clubId, AdServerViewModel.NewAdAdministrator newAdmin)
        {
            return 5;
        }

        [HttpPut]
        [Route("Club/{clubId}/Administrators/{adminId}")]
        [ResponseType(typeof(bool))]
        public IHttpActionResult UpdateClubAdministrator(int clubId, int adminId)
        {
            return Ok();
        }
    }

and here is the resulting output with some debug information about the attributues. Notice that the responseType argument for the two primitive based types has a blank value. I left in the non primitive type to show that the responseType argument for that was valid. The return type is stuffed into the : Promise section of the code. If the returnType is null, I convert that to a string of "void".

/* eslint-disable */
import { MakeRequest } from '../ApiServiceHelper';
import { AdAdministrator } from '../Interfaces/AdAdministrator';
import { NewAdAdministrator } from '../Interfaces/NewAdAdministrator';


export class AdServerService {
  method has 3 attributesattr has 1 arguments[responseType : List<AdAdministrator>]

  public static clubAdministratorsRoute = (clubId: number) => `api/AdServer/Club/${clubId}/Administrators`;
  public static clubAdministrators(clubId: number) : Promise<AdAdministrator[]> {
    return MakeRequest<AdAdministrator[]>("get", this.clubAdministratorsRoute(clubId), null);
  }
  method has 3 attributesattr has 1 arguments[responseType : ]

  public static addClubAdministratorRoute = (clubId: number) => `api/AdServer/Club/${clubId}/Administrators`;
  public static addClubAdministrator(clubId: number, newAdmin: NewAdAdministrator) : Promise<void> {
    return MakeRequest<void>("post", this.addClubAdministratorRoute(clubId), newAdmin);
  }
  method has 3 attributesattr has 1 arguments[responseType : ]

  public static updateClubAdministratorRoute = (clubId: number, adminId: number) => `api/AdServer/Club/${clubId}/Administrators/${adminId}`;
  public static updateClubAdministrator(clubId: number, adminId: number) : Promise<void> {
    return MakeRequest<void>("put", this.updateClubAdministratorRoute(clubId, adminId), null);
  }
  
}

I might get a chance to look at this later.

Extension throws missing DLL errors, previously working fine

I am using this tool and sometime recently, not sure exactly when, it stopped working. When trying to render a template I see the following error:

image

Some interesting things to note are

  • I did a search for "Miscrosoft.VisualStudio.LanguageServices" in my entire solution and there were no results
  • The required dependency for the stated 3.11.0 version of that NuGet package is .NET Framework v4.7.2, which none of the projects in my solution are targeting
  • The tool was previously working fine and I can't pinpoint any changes in the solution / project that would cause this error
  • There is nothing more in the NTypewriter output window

Action.Url is missing some query parameters

I have been going through my 46 controllers, matching up the Typewriter Url generation vs the NTypewriter Url generation.

There are cases where NTypewriter drops arguments. Here is what I have noticed:

The argument is dropped when:

  • the argument is an enum
  • the argument is marked as optional. (Verified that if I change int? to int, the param shows up.)

I have anther 40 controllers to go through, but these are definitely issues.

Can't have multiple template files in a project?

I am trying to have two templates in a project like this:

Scripts/api
+- Enums
  +- _Enums.nt
  +- <all the .ts files representing my enums go here>
+- Interfaces
  +- _Interfaces.nt
  +- <all the .ts files representing my interfaces go here>

What I am finding is that as soon as I render the _Interfaces.nt template, it deletes the _Enums.nt file.

I would really like to have three templates, another for services that lives in a similar structure but called _Services.nt.

Is it not possible to have multiple .nt files?

Bug: Action.Url is not using the RoutePrefix attribute of the class to build the Url

I have the following class:

    [RoutePrefix("api/AdServer/AdImage")]
    public class AdImageController : OurBaseApiController
    {
        [HttpGet]
        [Route("{adId}/image", Name = "AdServerImage")]
        public async Task<HttpResponseMessage> GetImage(int adId, int userId)
        {
        }
    }

When I call Action.Url method for the GetImage method, the return value is:
?adId=${adId}&userId=${userId}

But the real Url should be:

api/AdServer/AdImage/?adId=${adId}&userId=${userId}

The issue is that the RoutePrefix attribute on the class isn't being taken into consideration when building the Url.

script started crashing after upgrade

I think this started crashing after the latest upgrade, but it might have been before that.
My script used the same syntax as shown in AngularWebAPIService example. Specifically, I had the same line as line 11.

bodyParameterName = (method | Action.BodyParameter)?.Name ?? "null"

this syntax looks correct. If method | Action.BodyParameter is null, then the ?.Name should not get evaluated and it should return "null" as the result.

However, with this line, I now get an error while running the script:

(53,56) Object `(method|Action.BodyParameter)` is null. Cannot access member: (method|Action.BodyParameter)?.Name

I have worked around the problem by changing my script code to use a ternary operator:

bodyParameterName = (method | Action.BodyParameter) ? (method | Action.BodyParameter)?.Name ?? "null" : "null"

I can't tell which version this started in because VS auto updates my extensions and the only reason I noticed the problem is because I tried to render the template and it failed today after VS auto updated to 0.3.2.1. The original error was because my project still used NTypewriter.Editor.Config.0.1.10-alpha
Once I upgraded my project to NTypewriter.Editor.Config.0.3.1, I started to get this error.

I know that last week I was happily generating new api service classes using the script, so I have to assume it started with the latest version.

COMException: Unable to add file. A file with that name already exists.

I attempted to change the output folder like so:

filePath =  "Folder/" | String.Append class.BareName | String.Append ".ts"
Save output filePath

This gives me the following error:

INFO: Updating VisualStudio solution
ERROR: System.Runtime.InteropServices.COMException (0x80040400): Unable to add 'ClassModel.ts'. A file with that name already exists.
   at EnvDTE.ProjectItems.AddFromFile(String FileName)
   at NTypewriter.EditorForVisualStudio.Editor.SolutionItemsManager.Update(IEnumerable`1 outputFiles)
   at NTypewriter.EditorForVisualStudio.NTypewriterEditorForVisualStudioPackage.<>c__DisplayClass11_0.<RenderTemplateCommand_OnExecuted>b__1()
   at System.Threading.Tasks.Task.InnerInvoke()
   at System.Threading.Tasks.Task.Execute()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at NTypewriter.EditorForVisualStudio.NTypewriterEditorForVisualStudioPackage.<RenderTemplateCommand_OnExecuted>d__11.MoveNext()

It's worth noting that the files are being generated in the correct folder, but not included in the project (not added to the .csproj file). I tried removing the folder, but when rendering the template I get the "already exists" error again.

I tried changing "Folder/" to "/Folder/", but that gave me a different error:

INFO: Updating VisualStudio solution
ERROR: System.Runtime.InteropServices.COMException (0x80004005): Cannot add a link to the file ClassModel.ts. There is already a file of the same name in this folder.
   at EnvDTE.ProjectItems.AddFromFile(String FileName)
   at NTypewriter.EditorForVisualStudio.Editor.SolutionItemsManager.Update(IEnumerable`1 outputFiles)
   at NTypewriter.EditorForVisualStudio.NTypewriterEditorForVisualStudioPackage.<>c__DisplayClass11_0.<RenderTemplateCommand_OnExecuted>b__1()
   at System.Threading.Tasks.Task.InnerInvoke()
   at System.Threading.Tasks.Task.Execute()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at NTypewriter.EditorForVisualStudio.NTypewriterEditorForVisualStudioPackage.<RenderTemplateCommand_OnExecuted>d__11.MoveNext()

What am I doing wrong? This seems like a bug.

Filter out types not used in properties

Just found out about NTypewriter when looking for how to make Typewriter accept types from assemblies.
Looks promising and fast! :)
Looking into migrating a project now.

Question:
What would the best way to filter out referenced types in a class so that only types that are used in the properties (and/or implements/extends) remain?
(So I can skip importing a type only used in a function.)

doesnt work on VS 2019 , 16.10.x versions

plugin cant open own window on .nt editing...
nothings happen in output window except dump of version
on 16.11.x it works

typewriter works on 16.10.x

any diagnostic i can help?

[Question] Get enum names and values from IType

Hello again!

I'm trying to create template for my enums, and stuck with discovering enum names and values from IType. Why from IType? It is because I'm using data.Classes as entry point and discover all referenced types (via built-in function TypeFunctions.AllReferencedTypes) from all parameter and return types of all public actions of my controllers.

Template:

{{- for type in data.Classes | Custom.ExportTypes | Custom.ThatAreEnums
	capture output
}}
export enum {{ type.Name }} {
	{{- for item in type | Custom.EnumValues }}
	{{ item.Name }} = {{ item.Value }},
	{{- end }}
}
{{- end
	Save output ("types\\" + type.Name + ".generated.ts")
end
}}

The custom EnumValues function:

public static IEnumerable<IEnumValue> EnumValues( this IType source )
{
	if (!source.IsEnum)
		return Enumerable.Empty<IEnumValue>();

	// TODO: ???
}

NTypewriter v0.3.4

Include System.Text.Json For Template Config

Would you consider allowing the System.Text.Json NuGet package to be used in the compilation for the template config file? There's a mismatch between the result of String.ToCamelCase provided by this extension and the result of System.Text.Json.JsonNamingPolicy.CamelCase.ConvertName() which is the default in .NET Core. It causes issues when performing POST requests with the models generated by this extension.

Another option would be to utilize the above in the String.ToCamelCase method by default.

Difference between the CLI tool and the VS Extension

Hello again,
I'm building a CLI tool as per your guide, but I'm noticing differences in behavior.

For example, a class with nullable int properties ends up like this (correct) when I render via the VS extension:

image

and like this using the CLI tool:

image

Do you have any quick insights on why this would be? The CLI tool's code is for the juicy part (code analyzer and compilation setup) the same you show in you example:

image

FR: Action.Parameters without Body Parameter

When I am generating a services class, I like to have two functions per end point. I like to have one function that returns the url given all the parameters and the other function that actually calls the url.

I like to have the url function because I use it in unit testing all the time to ensure that I have setup my class under test properly so that it is calling the end point properly. That way my unit tests don't change if the end point url changes.

Here is a sample end point set of functions in a service class:

  public static getImageRoute = (adId: number, userId: number) => `api/AdServer/AdImage/${adId}/image?userId=${userId}`;
  public static getImage(adId: number, userId: number, context: AdServeContext) : Promise<void> {
    return MakeRequest<void>("get", this.getImageRoute(adId, userId), context);
  }

To be able to create this with NTypewriter, I need to call method.Parameters and method.BodyParameter and then I have to remove BodyParameter from the Parameters list. However, I can't seem to do this in Scriban, because once I use the Array methods on the Parameter list, I no longer have the ability to use an Action method that expects an IEnumerable because the parameter list has been converted into something called a range by Scriban.

So I would like to have an Action.UrlParameters that returns the Parameter list that is required for the creation of the Url.

BTW, this would be an improvement over what I had when using Typescript. All of my url methods included the body parameter, which made unit testing awkward because I would have to create an instance of the body parameter to be able to call the url function. The above output would be much better.

Disabling preview?

Is is possible to disable the preview window in the editor?
I don't always need it and it seems to take a decent time spinning up when opening the .nt file.

ERROR: System.NotImplementedException: The method or operation is not implemented.

I receive this error when rendering a template:

ERROR: System.NotImplementedException: The method or operation is not implemented.
at EnvDTE.SourceControl.IsItemCheckedOut(String ItemName)
at NTypewriter.EditorForVisualStudio.Editor.SolutionItemsManager.Checkout(DTE2 dte, String filePath)
at NTypewriter.EditorForVisualStudio.NTypewriterEditorForVisualStudioPackage.<RenderTemplateCommand_OnExecuted>d__13.MoveNext()

Template:

{{ capture output
       for class in data.Classes 
           class.FullName | String.Append "\r\n"
      end
   end
   Save output "index.txt"
}}

The version of the extension is 0.2.0.

the variable or function 'array' was not found

I am trying to use Scriban's builtin array functions and I get this error:

09:43:29.012 INFO: Rendering template
09:43:29.014 ERROR: <input>(6,11) The variable or function `array` was not found
09:43:29.014 ERROR: System.Exception: Rendering template failed
   at NTypewriter.EditorForVisualStudio.CoreDomain.TemplateRenderer.<RenderTemplate>d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NTypewriter.EditorForVisualStudio.CoreDomain.TemplateRenderer.<RenderAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at NTypewriter.EditorForVisualStudio.NTypewriterEditorForVisualStudioPackage.<RenderTemplateCommand_OnExecuted>d__11.MoveNext()

Are the builtins not available?

And if not, do you have a suggestion for how to join two arrays of classes together? I have a situation where I have two different attributes that are used in the code base to trigger conversion to Typescript:
ExportToTypescript
ExportToTypescriptWithKnockout

For this .nt file, I need to process both of these classes the same way, so I figured I would create two arrays, concatenate them and then process the resulting list like this:

{{- 
# gather the classes with ExportToTypescript and ExportToTypescriptWithKnockout.
# I have to gather them into one array that I can then iterate over
normal = data.Classes | Symbols.ThatHaveAttribute "ExportToTypescript"
knockout = data.Classes | Symbols.ThatHaveAttribute "ExportToTypescriptWithKnockout"
classes = array.concat normal knockout
Capture output 
classes
end
Save output "index.txt"
}}

test against empty results in compile error

I am trying to test Type's ArrayType against empty to see if it is null or not. But the compile produced an error that the variable or function 'empty' was not found.

This might be the same problem I raised with the array builtin functions not being found.

10:43:05.108 INFO: Template loaded successfully
10:43:27.737 INFO: Rendering template
10:43:27.995 ERROR: <input>(31,28) The variable or function `empty` was not found
10:43:27.996 ERROR: System.Exception: Rendering template failed
   at NTypewriter.EditorForVisualStudio.CoreDomain.TemplateRenderer.<RenderTemplate>d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NTypewriter.EditorForVisualStudio.CoreDomain.TemplateRenderer.<RenderAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at NTypewriter.EditorForVisualStudio.NTypewriterEditorForVisualStudioPackage.<RenderTemplateCommand_OnExecuted>d__11.MoveNext()

Here is the code:

{{- for class in data.Classes  | Symbols.ThatHaveAttribute "ExportToTypescript" -}}
{{- capture output -}}
  {{- for prop in class.Properties  }}
  {{type = prop.Type
    arrayType = "false"
	if prop.Type.ArrayType != empty
		type = prop.Type.ArrayType
		arrayType = "true"
	end
  }}
  {{prop.Name}}-{{type.Name}}-{{arrayType}}
  {{-end}}
{{-end}}

Here is what I am really trying to do:

I have a class in C# that is defined like this:

        [ExportToTypescript]
        public class ActivityInfo
        {
            public int Id { get; set; }
            public string name { get; set; }
            public List<ActivityPageMenuItem> menuItems { get; set; }
       }

I am trying to get the output to be:

import { ActivityPageMenuItem} from './ActivityPageMenuItem';

export interface ActivityInfo {
  id: number,
  name: string,
  menuItems: ActivityPageMenuItem[],
}

Notice that menuItems is defined as a List, so I need to pull out the type ActivityPageMenuItem and then I need to figure out that ActivityPageMenuItem has an attribute of ExportToTypescript on it so that I can emit that import statement.

I am assuming that the Type.ArrayType is ActivityPageMenuItem, but I can't just get to it because the other properties of the class have Type.ArrayType as null so when I try to access it for those members, I get a null pointer exception.

Should Types.ToTypeScriptType convert DateTime and DateTimeOffset to Date or string?

I see that Types.ToTypeScriptType converts a DateTime to a Date object. After years of working with Typewriter, C# and TS, I have come to the conclusion that the best practice is to define your TS interface interms of a string rather than Date.

The issue marking the field as a Date object is that it isn't a date object. The back end will typically convert that DateTimeOffset or DateTime to a standardized string that javascript can parse. But when that field is read into memory, it is stored as a string. And you need to go through a separate step to create the Date object. And to top that off, the JS date constructor does not take a Date object as a parameter to its constructor, so the Typescript compiler complains that the statement creating the Date object is invalid, even though it will work at run time.

Then when passing the date back to the api, you need to convert it to a string anyway. Again, you get Typescript compiler errors popping up because you are trying to set a Date object with a string value.

I have had much better results making those date objects strings in the TS interface. Once I started doing that, everything worked out much, much better. The code was cleaner and typescript stopped complaining.

So, I would recommend that Types.ToTypeScriptType should map DateTime and DateTimeOffset to strings.

[Question] Auto-render when C# file changes

Will you add it in the future? If not, developers may forget to do it manually. Is there any method to make it auto or at least remind developers to do it manually? Method requires Visual Studio is fine.

"Start without debugging" doesn't trigger a render of the templates

I really like the new feature of RenderWhenProjectBuildIsDone.
I have noticed that it does kick off a template render when I click on the Build/Build Solution menu item.
It also kicks off the template render when I click on Build/Rebuild Solution.

very nice, especially since the template rendering is so much faster than Typewriter.

What I have noticed is that the template render is not kicked off when the build via Debug/Start without debugging, or Debug/Start. Both of these will do a build if necessary and then launch the application. It seems that for some reason these builds do not trigger NTypewriter.

Is there a way to capture these builds as well? I rarely build my project via the Build menu, I always build it via the Debug/Start without Debugging menu.

Include generated files in project

For those of us that are stuck using the legacy project system, can we get an option to include the generated files into the project? For reference, the original TypeWriter did this.

Custom functions not working when excluded from "compile" item group in VS

I'm trying to use custom functions in my project, but unable to make them work without including its .cs in the "compile" item group. I.e. it is not working when I do the following:

<ItemGroup>
	<Compile Remove="CustomFunctions.nt.cs" />
	<None Include="CustomFunctions.nt.cs" />
</ItemGroup>

The main reason to make that is to exclude NTypewriter custom code from my main code, since I consider it as service code, i.e. dev only. And in the NTypewriter docs there were said that it compiles custom functions code outside the project and its settings it was declared.

Is it a bug or what I'm doing wrong? Thank you in advance!

NTypewriter v0.3.0

Type.AllReferencedTypes includes types used by methods of the specified type. Is that what is desired?

Following your suggestion in issue #8, I switched over to use Type.AllReferencedTypes.

Here is an example where too many types are returned. The import section is driven by the call to Types.AllRelatedTypes. As you can see, SessionBox and SeesionPlayer are not needed in this file. Ie, they are not directly related to BoxLeagueNextSession. They are related to BoxLeagueSession.

import { NextSessionBox } from './NextSessionBox';
import { MemberInfo } from './MemberInfo';
import { SessionBox } from './SessionBox';
import { SessionPlayer } from './SessionPlayer';
import { BoxLeagueSession } from './BoxLeagueSession';


export interface BoxLeagueNextSession extends BoxLeagueSession {
  nextSession: NextSessionBox[],
  nextSessionDateRangeDescription: string,
  nextSessionStartDate: string,
  nextSessionEndDate: string,
  targetBoxSize: number,
  playersLeaving: MemberInfo[]
}

v0.3.4 Introduced a Bug in Template Rendering

Hello again,

After version 0.3.4 I started noticing some different functionality in my rendering than normal. An erroneous space is being added to my output.

Snippet of Template:

export interface {{ class.Name }} {{ class.HasBaseClass ? ("extends " + class.BaseClass.Name) : ""}} {
    [key: string]: any;
{{- for property in class.Properties | Symbols.ThatArePublic }}
    {{ property.Name }}: {{ property.Type | Custom.GetTypeScriptType }};
{{- end }}
}

Output:
image

Notice the two spaces between "FutureCast" and "extends". Another weird behavior that I have noticed is that any time class.HasBaseClass resolves to true in my template, my generated model is checked out in source control even though there are no changes.

FR: Action.ReturnType should look for ResponseType attribute when return type IHttpActionResult

As I mentioned in a previous request, I am still on ASP.Net MVC and haven't moved to .Net core yet. So my api controller actions all look like this:

        [IsAjaxRequest]
        [HttpPut]
        [Route("{adId}/image")]
        [ResponseType(typeof(AdImageViewModel.AdImage))]
        public async Task<IHttpActionResult> ReplaceImage(int adId)
        {
            ...
        }

The real type of my method is encoded in the ResponseType attribute.

In the .Net Core world, this is done like this article points out. The attribute is different and the return type is different, but the concept is the same.

It would be great if Action.ReturnType handled this for ASP.Net MVC Web Api 2.0 and for .Net Core.

Type.AllReferencedTypes ignores nullable reference types

Hi,

It seems that Type.AllReferencedTypes ignores nullable reference types.

Here is what I'm trying to do:

Template:

for class in data.Classes | Symbols.WhereNameEndsWith "TestDTO"

    capture output

        for type in class | Type.AllReferencedTypes | Array.Uniq -}}
import { {{ type }} } from './{{ type.BareName }}';
{{      end
    end

    Save output "test_output"
end

Class to transform:

public class TestDTO
{
    public SomeOtherClass? TestProp1 { get; set; }
}

In the output, no line is present when TestProp1 is nullable.
I would expect to see:

import { SomeOtherClass } from './SomeOtherClass':

Otherwise, thanks for your work. I used Typewriter a few years ago and NTypewriter is a huge improvement!

ToTypescriptType should output string for TimeSpan

Hi

I believe that Type.ToTypeScriptType should output string for TimeSpan that might be in a c# file.
Right now it just passes TimeSpan through unchanged. But TS/JS doesn't have a TimeSpan type and it is best handled as the string that MVC converts it to.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.