Closed gregveres closed 3 years ago
I have done some more experimenting. I guess the other approach would be like this, right?
{{ for enum in data.Enums | Symbols.ThatHaveAttribute "ExportToTypescript" }}
{{capture output}}export const enum {{enum.Name}} {
...
}
{{end}}
{{Save output (enum.BareName | String.Append ".ts")}}
{{end}}
Is there a preference in terms of which one is best practice?
Here is what I have come up with for output Enums that are tagged with an attribute called ExportToTypescript. I am putting it here to help future people get started.
{{- for enum in data.Enums | Symbols.ThatHaveAttribute "ExportToTypescript" -}}
{{- capture output -}}
export const enum {{enum.Name}} {
{{- for enumValue in enum.Values}}
{{ enumValue.Name}} = {{ enumValue.Value}}{{-if !for.last}},{{end}}
{{-end}}
}
{{- end}}
{{- Save output (enum.BareName | String.Append ".ts")}}
{{- end}}
This will produce a file like this:
export const enum AvailabilityStatus {
Available = 0,
NotAvailable = 1,
IfNeeded = 2
}
For beginners (like me) these are the things to note:
And here is my finished .nt file that creates Enum definitions in an Enums folder and Interface definitions in an Interfaces folder. I am putting this here as an example of a non-trivial, fully functioning example for future people to learn from. I think it serves as a pretty good example, but since I just learned Scriban this morning, I am sure there are better ways to do some of the things I am doing.
My next step is to create functions that I can call in TS that will call my controller end points. BTW, this is much simpler than the script I had in Typewritter
{{- # Helper classes }}
{{- importedTypeNames = []}}
{{- func ImportType(type)
useType = Type.Unwrap(type)
if (useType.ArrayType != null)
useType = useType.ArrayType
end
if (importedTypeNames | Array.Contains useType.Name)
ret null
end
importedTypeNames[importedTypeNames.size] = useType.Name
if (type.IsEnum)
path = "../Enums/"
else
path = "./"
end
importType = false
for attr in useType.Attributes
if attr.Name == "ExportToTypescript"
importType = true
break
end
if attr.Name == "ExportToTypescriptWithKnockout"
importType = true
break
end
end
if importType
ret "import { " | String.Append useType.Name | String.Append " } from '" | String.Append path | String.Append useType.Name | String.Append "';\r"
end
ret null
end
}}
{{- func ToTypeScriptType(type)
if(type.Name | String.Contains "TimeSpan")
ret "string"
else if (type.Name == "DateTime")
ret "string"
else if (type.Name == "DateTimeOffset")
ret "string"
end
ret Type.ToTypeScriptType type
end
}}
{{- # output enums }}
{{- for enum in data.Enums | Symbols.ThatHaveAttribute "ExportToTypescript" -}}
{{- capture output -}}
export const enum {{enum.Name}} {
{{- for enumValue in enum.Values}}
{{ enumValue.Name}} = {{ enumValue.Value}}{{-if !for.last}},{{end}}
{{-end}}
}
{{- end}}
{{- Save output ("Enums\\" | String.Append enum.BareName | String.Append ".ts")}}
{{- end}}
{{- # output classes }}
{{ normal = data.Classes | Symbols.ThatHaveAttribute "ExportToTypescript"
knockout = data.Classes | Symbols.ThatHaveAttribute "ExportToTypescriptWithKnockout"
classes = Array.Concat normal knockout
}}
{{- for class in classes -}}
{{- capture output -}}
{{- importedTypeNames = []}}
{{- if class.HasBaseClass
ImportType class.BaseClass
end
}}
{{-for prop in class.Properties}}
{{- ImportType prop.Type}}
{{-end}}
export interface {{class.Name}}{{if class.HasBaseClass}} extends {{class.BaseClass.Name}}{{end}} {
{{- for prop in class.Properties | Symbols.ThatArePublic }}
{{ prop.Name | String.ToCamelCase}}: {{ToTypeScriptType prop.Type}}{{if !for.last}},{{end}}
{{-end}}
}
{{- end}}
{{- Save output ("Interfaces\\" | String.Append class.BareName | String.Append ".ts")}}
{{- end}}
Have you tried to use Type.AllReferencedTypes (TypeFunctions.AllReferencedTypes.cs)? It should streamline further generating import part and reduce size of your template by a few lines. There was a bug in version 0.0.6, arrays were not handled properly, but it was fixed in 0.0.7.
Ah, I see, I can replace this section of the output classes section:
{{- importedTypeNames = []}}
{{- if class.HasBaseClass
ImportType class.BaseClass
end
}}
{{-for prop in class.Properties}}
{{- ImportType prop.Type}}
{{-end}}
with
{{- for type in Type.AllReferencedTypes class}}
{{- ImportType type}}
{{-end}}
because AllReferencedTypes will return the base class and all the classes associated with the methods and properties etc. And it will return a unique list, so I don't have to build up a unique list myself. Nice.
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:
or is there away to have the text just appear in my output without having to use String.Append?
Thanks