跨多个打字机模板使用“共享逻辑”?

时间:2016-06-20 19:58:57

标签: typewriter

我们的项目中有多个Typewriter properties模板,并希望在它们之间共享一些常见的逻辑/方法。有没有办法做到这一点?

2 个答案:

答案 0 :(得分:3)

不幸的是,没有办法在tst模板中共享代码。对此的支持可能会在未来的版本中出现。

答案 1 :(得分:2)

您可以使用T4模板生成打字机模板。将代码放入可重用的T4模板(* .ttinclude)中,并创建tt文件,以将参数传递给此基本模板的呈现方法。

(我使用Visual Studio扩展进行文件嵌套。)

Project structure

每个tt文件看起来都是这样;

<#@ template debug="true" hostSpecific="true" #>
<#@ output extension=".tst" #>
<#@ include file="..\ModelsTemplate.ttinclude" #>
<#  this.ModelsTemplate_Render("UserSettings"); #>

...并且我的ttinclude文件如下所示(这是一个特定于项目的文件,但我将其全部包含在内,以便任何想尝试一下的人都可以轻松地完成某些工作);

<#@ IntelliSenseLanguage processor="tangibleT4Editor" language="C#" #>
<#+ 
  void ModelsTemplate_Render(string @subnamespace) {
     ModelsTemplate_Render("MyApp.ViewData", @subnamespace);
  }

  void ModelsTemplate_Render(string @mainnamespace, string @subnamespace) {
     string renderedMainNamespace = @mainnamespace;
#>
// <auto-generated>
//     This code was generated by a tool.
//     Template: <#= Host.TemplateFile #>
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>

${
    // Enable extension methods by adding using Typewriter.Extensions.*
  using Typewriter.Extensions.Types;
  using System.Text.RegularExpressions;

    Template(Settings settings)
    {
        settings.IncludeProject("MyApp.ViewData");
    }

   static string DebugInfo = "";
    string PrintDebugInfo(File f){
      if (string.IsNullOrEmpty(DebugInfo)) {
         return "";
      }

      return "/*" + Environment.NewLine + "Template debug info: " + DebugInfo + Environment.NewLine + "*/";
    }

    string BaseClassFullPath(Class baseClass)
    {
        //DebugInfo = DebugInfo + Environment.NewLine + "baseClass.FullName:" + baseClass.FullName;
        var result = baseClass.Name;

        // Until we find a better way to handle implementations of generic base classes...
        result = result.Replace("<bool?>", "<boolean>");
        result = result.Replace("<int?>", "<number>");
        result = result.Replace("<long?>", "<number>");
      result = result.Replace("<decimal?>", "<number>");
      result = result.Replace("<double?>", "<number>");
      result = result.Replace("<System.Double>", "<number>");
      result = result.Replace("<System.Double?>", "<number>");
      result = result.Replace("<System.DateTime?>", "<Date>");

        return result;
    }

    string NullableFilter(string typeName)
    {
        return typeName.Replace("?", "");
    }

    string TypeFilteredPath(Type type)
    {
        //DebugInfo = DebugInfo + Environment.NewLine + "type:" + type.FullName + " - genericType:" + type.Unwrap().FullName;
        return NullableFilter(type.Name);
    }

    string TypeFiltered(Type type)
    {
      if (type.IsEnumerable)
      {
          var genericType = type.Unwrap();
          if (!genericType.FullName.StartsWith("System")) 
          {
            return TypeFilteredPath(genericType)+"[]";
          }
        }
        return TypeFilteredPath(type);
    }

    string PropertyTypeFiltered(Property prop)
    {
        return TypeFiltered(prop.Type);
    }

    string ImplementedInterfaces(Class c){
        if (!c.Interfaces.Any()){
            return string.Empty;
        }
        return "implements " + string.Join(", ", c.Interfaces.Select(x => x.FullName));
    }

    string ExtendedInterfaces(Interface i){
        if (!i.Interfaces.Any()){
            return string.Empty;
        }
        return "extends " + string.Join(", ", i.Interfaces.Select(x => x.FullName));
    }

    string DescriptionAttributeValue(Attribute a){
        if (!a.FullName.Contains("DescriptionAttribute")){
            return string.Empty;
        }
        return a.Value;
    }

    string GetPropertyDefinitionWithScope(Property p){
      var definition = GetPropertyDefinition(p);
      if (definition != "")
         return "public " + definition;
      else 
         return definition;
    }

    string GetPropertyDefinition(Property p){
      var ignoreAttribute = p.Attributes.SingleOrDefault(x => x.FullName.Contains("TypeScriptIgnoreMemberAttribute"));
      if (ignoreAttribute != null)
         return "";

        var typeAttribute = p.Attributes.SingleOrDefault(x => x.FullName.Contains("TypeScriptTypeAttribute"));
        if (typeAttribute != null) {
            return p.name + ": " + typeAttribute.Value + ";";
        }
        return p.name + ": " + TypeFiltered(p.Type) + ";";
    }

    string WriteImports(Class theClass){
      //return "import { ViewDataEntity } from '../common/ViewDataEntity';";
      var list = new List<string>();

      var typesToImport = theClass.Properties.Select(x => x.Type.Unwrap()).Where(x => x.Namespace.Contains("MyApp.ViewData.")).ToList();
      if (theClass.BaseClass?.Namespace.Contains("MyApp.ViewData.") == true)
        typesToImport.Add(theClass.BaseClass);
      foreach (var impType in typesToImport)
      {
        var modules = impType.Namespace.Replace("MyApp.ViewData.", "").Split('.').ToList();
        string modPart = string.Join("/", modules.Select(x => CamelCase(x)));
        list.Add($"import {{ {impType.Name} }} from '../{modPart}/{impType.Name}';");
      }

      return string.Join(Environment.NewLine, list.Distinct());
    }

    string CamelCase(string value){
      return value.First().ToString().ToLower() + value.Substring(1);
    }
}//namespace <#= renderedMainNamespace #>.<#= @subnamespace #> {

    $Classes(c => c.Namespace.StartsWith("<#= @mainnamespace #>.<#= @subnamespace #>"))[

$WriteImports

    export class $Name$TypeParameters $BaseClass[extends $BaseClassFullPath ] $ImplementedInterfaces {$Properties[
        $GetPropertyDefinitionWithScope]
    }]
    $Interfaces(<#= @mainnamespace #>.<#= @subnamespace #>.*)[
    export interface $Name $ExtendedInterfaces {
        $Properties[
        $GetPropertyDefinition]
    }]
    $Enums(<#= @mainnamespace #>.<#= @subnamespace #>.*)[
    export class $Name {
        $Values[// $Value - "$Attributes[$Value]"
            static $Name = "$Name"; 
        ]
    }]
   $PrintDebugInfo
//}<#+
   }
#>