Closed satfx closed 2 years ago
Here is my _Enums.nt file that exports enums to typescript. The barrel file stuff is about collecting all of them into single export file. The rest is pretty straight forward for extracting an enum that looks like:
export enum ActivityState {
PrePublished = 0,
Published = 1,
Archived = 2
}
here is the Ntypewriter file. Also note that I use an attribute called [ExportToTypescript] as the way to signify which classes/enums to generate into typescript.
{{ $barrelFile = "" }}
{{- for enum in data.Enums | Symbols.ThatHaveAttribute "ExportToTypescript" | Array.Sort "Name" -}}
{{- capture output -}}
export enum {{enum.Name}} {
{{- for enumValue in enum.Values}}
{{ enumValue.Name}} = {{ enumValue.Value}}{{-if !for.last}},{{end}}
{{-end}}
}
{{- end}}
{{- Save output ("..\\..\\..\\SkyCourt.UI\\skycourt\\libs\\api\\enums\\src\\lib\\" | String.Append enum.BareName | String.Append ".ts")}}
{{- capture barrelOutput -}}
export { {{enum.Name}} } from './lib/{{enum.Name}}';
{{- end -}}
{{ $barrelFile = $barrelFile | String.Append barrelOutput | String.Append "\n" }}
{{- end}}
{{- Save $barrelFile ("..\\..\\..\\SkyCourt.UI\\skycourt\\libs\\api\\enums\\src\\index.ts")}}
I read your question a bit closer. I think what you need is that first part for enum in data.Enums
instead of what you have: for type in data.Classes
Thanks, Greg, for a really lightning speed reply! I prefer not to count on any additional attributes (programmers have very bad memory and are really, REALLY lazy persons), nor publishing all my enums from the whole project, but only those that are really used in visible controllers and actions.
Btw, I saw example templates in the test repository "https://github.com/NeVeSpl/TestMe/tree/master/TestMe.Presentation.React/ClientApp/src/autoapi2"
It is possible to achieve what you want on 0.3.4, but that would require a lot of ugly code in the custom function. In 0.3.5 it will be much simpler:
{{- for class in data.Classes
for enum in class| Type.AllReferencedTypes
if !enum.IsEnum
break
end
capture output
}}
export enum {{ enum.Name }}
{
{{- for item in enum.Values }}
{{ item.Name }} = {{ item.Value }},
{{- end }}
}
{{- end
Save output ("enums\\" + enum.FullName + ".tsx")
end
end
}}
Your template from the fist post also should work on 0.3.5 without the need for Custom.EnumValues.
(facepalm) I'm really sorry for bothering you, guys, but it is all fine now! I don't know why initially I received an error when trying to use "Values" in the expression "{{- for item in type.Values }}" in my template from the first post. MB I accidentally used "EnumValues" instead of "Values". Anyway thanks for your help and a tool that is a pleasure to work with!
Source code for the ExportTypes, mb it will help somebody:
private const string ControllerSuffix = "Controller";
public static IEnumerable<IType> ExportTypes( this IEnumerable<IClass> source )
{
var controllers = source
.ThatAreApiControllers()
.WhereControllerInDefaultArea();
var methods = controllers
.SelectMany(v => v.Methods)
.ThatAreActions();
return methods
.SelectMany(v => v.Parameters().Select(x => x.Type).Append(v.ReturnType()))
.SelectMany(v => v.AllReferencedTypes(SearchIn.BaseClass | SearchIn.Properties).Append(v))
.Distinct(new TypeComparer());
}
public static IEnumerable<IClass> ThatAreControllers( this IEnumerable<IClass> source )
=> source
.Where(v => !v.IsAbstract)
.Where(v => IsSubclassOf(v, "ControllerBase") || v.Attributes.Any(x => x.Name == "Controller"))
.Where(v => v.Attributes.All(x => x.Name != "NonController"));
public static IEnumerable<IClass> ThatAreApiControllers( this IEnumerable<IClass> source )
=> source
.ThatAreControllers()
.Where(v => v.Attributes.Any(x => x.Name == "ApiController"));
public static IEnumerable<IClass> ThatAreNotApiControllers( this IEnumerable<IClass> source )
=> source
.ThatAreControllers()
.Where(v => v.Attributes.All(x => x.Name != "ApiController"));
private static bool IsSubclassOf( IType source, string baseTypeName )
{
while (source != null)
{
if (source.Name == baseTypeName)
return true;
source = source.BaseType;
}
return false;
}
public static string AreaName( this IType source )
=> source.Attributes
.Where(v => v.Name == "Area")
.SelectMany(v => v.Arguments)
.Where(v => v.Name == "areaName")
.Select(v => (string)v.Value)
.FirstOrDefault();
public static string ControllerName( this IType source )
=> source.Name.EndsWith(ControllerSuffix)
? source.Name.Substring(0, source.Name.Length - ControllerSuffix.Length)
: source.Name;
public static IEnumerable<IClass> WhereControllerInArea( this IEnumerable<IClass> source, string areaName )
=> source.Where(v => v.AreaName() == areaName);
public static IEnumerable<IClass> WhereControllerNotInArea( this IEnumerable<IClass> source, string areaName )
=> source.Where(v => v.AreaName() != areaName);
public static IEnumerable<IClass> WhereControllerInDefaultArea( this IEnumerable<IClass> source )
=> WhereControllerInArea(source, null);
public static IEnumerable<IMethod> ThatAreActions( this IEnumerable<IMethod> source )
=> source
.Where(v => v.IsPublic && !v.IsStatic)
.Where(v => v.Attributes.All(x => x.Name != "NonAction"));
public static string ActionName( this IMethod source )
=> ActionNameFromAttribute(source) ?? ActionNameFromMethod(source);
private static string ActionNameFromAttribute( IMethod source )
=> source.Attributes
.Where(v => v.Name == "ActionName")
.SelectMany(v => v.Arguments)
.Where(v => v.Name == "name")
.Select(v => (string)v.Value)
.FirstOrDefault();
private static string ActionNameFromMethod( IMethod source )
=> source.Name.EndsWith("Async")
? source.Name.Substring(0, source.Name.Length - 5)
: source.Name;
internal class TypeComparer : IEqualityComparer<IType>
{
public bool Equals( IType x, IType y )
=> x.FullName.Equals(y.FullName);
public int GetHashCode( IType obj )
=> obj.FullName.GetHashCode();
}
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:
The custom EnumValues function:
NTypewriter v0.3.4